Files
TorrentParts/bundle.js
2020-11-13 11:36:25 -05:00

38363 lines
1.0 MiB
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function (process){(function (){
/**
* @popperjs/core v2.5.4 - MIT License
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function getBoundingClientRect(element) {
var rect = element.getBoundingClientRect();
return {
width: rect.width,
height: rect.height,
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left,
x: rect.left,
y: rect.top
};
}
/*:: import type { Window } from '../types'; */
/*:: declare function getWindow(node: Node | Window): Window; */
function getWindow(node) {
if (node.toString() !== '[object Window]') {
var ownerDocument = node.ownerDocument;
return ownerDocument ? ownerDocument.defaultView || window : window;
}
return node;
}
function getWindowScroll(node) {
var win = getWindow(node);
var scrollLeft = win.pageXOffset;
var scrollTop = win.pageYOffset;
return {
scrollLeft: scrollLeft,
scrollTop: scrollTop
};
}
/*:: declare function isElement(node: mixed): boolean %checks(node instanceof
Element); */
function isElement(node) {
var OwnElement = getWindow(node).Element;
return node instanceof OwnElement || node instanceof Element;
}
/*:: declare function isHTMLElement(node: mixed): boolean %checks(node instanceof
HTMLElement); */
function isHTMLElement(node) {
var OwnElement = getWindow(node).HTMLElement;
return node instanceof OwnElement || node instanceof HTMLElement;
}
/*:: declare function isShadowRoot(node: mixed): boolean %checks(node instanceof
ShadowRoot); */
function isShadowRoot(node) {
var OwnElement = getWindow(node).ShadowRoot;
return node instanceof OwnElement || node instanceof ShadowRoot;
}
function getHTMLElementScroll(element) {
return {
scrollLeft: element.scrollLeft,
scrollTop: element.scrollTop
};
}
function getNodeScroll(node) {
if (node === getWindow(node) || !isHTMLElement(node)) {
return getWindowScroll(node);
} else {
return getHTMLElementScroll(node);
}
}
function getNodeName(element) {
return element ? (element.nodeName || '').toLowerCase() : null;
}
function getDocumentElement(element) {
// $FlowFixMe: assume body is always available
return ((isElement(element) ? element.ownerDocument : element.document) || window.document).documentElement;
}
function getWindowScrollBarX(element) {
// If <html> has a CSS width greater than the viewport, then this will be
// incorrect for RTL.
// Popper 1 is broken in this case and never had a bug report so let's assume
// it's not an issue. I don't think anyone ever specifies width on <html>
// anyway.
// Browsers where the left scrollbar doesn't cause an issue report `0` for
// this (e.g. Edge 2019, IE11, Safari)
return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;
}
function getComputedStyle(element) {
return getWindow(element).getComputedStyle(element);
}
function isScrollParent(element) {
// Firefox wants us to check `-x` and `-y` variations as well
var _getComputedStyle = getComputedStyle(element),
overflow = _getComputedStyle.overflow,
overflowX = _getComputedStyle.overflowX,
overflowY = _getComputedStyle.overflowY;
return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);
}
// Composite means it takes into account transforms as well as layout.
function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {
if (isFixed === void 0) {
isFixed = false;
}
var documentElement = getDocumentElement(offsetParent);
var rect = getBoundingClientRect(elementOrVirtualElement);
var isOffsetParentAnElement = isHTMLElement(offsetParent);
var scroll = {
scrollLeft: 0,
scrollTop: 0
};
var offsets = {
x: 0,
y: 0
};
if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078
isScrollParent(documentElement)) {
scroll = getNodeScroll(offsetParent);
}
if (isHTMLElement(offsetParent)) {
offsets = getBoundingClientRect(offsetParent);
offsets.x += offsetParent.clientLeft;
offsets.y += offsetParent.clientTop;
} else if (documentElement) {
offsets.x = getWindowScrollBarX(documentElement);
}
}
return {
x: rect.left + scroll.scrollLeft - offsets.x,
y: rect.top + scroll.scrollTop - offsets.y,
width: rect.width,
height: rect.height
};
}
// Returns the layout rect of an element relative to its offsetParent. Layout
// means it doesn't take into account transforms.
function getLayoutRect(element) {
return {
x: element.offsetLeft,
y: element.offsetTop,
width: element.offsetWidth,
height: element.offsetHeight
};
}
function getParentNode(element) {
if (getNodeName(element) === 'html') {
return element;
}
return (// $FlowFixMe: this is a quicker (but less type safe) way to save quite some bytes from the bundle
element.assignedSlot || // step into the shadow DOM of the parent of a slotted node
element.parentNode || // DOM Element detected
// $FlowFixMe: need a better way to handle this...
element.host || // ShadowRoot detected
// $FlowFixMe: HTMLElement is a Node
getDocumentElement(element) // fallback
);
}
function getScrollParent(node) {
if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {
// $FlowFixMe: assume body is always available
return node.ownerDocument.body;
}
if (isHTMLElement(node) && isScrollParent(node)) {
return node;
}
return getScrollParent(getParentNode(node));
}
/*
given a DOM element, return the list of all scroll parents, up the list of ancesors
until we get to the top window object. This list is what we attach scroll listeners
to, because if any of these parent elements scroll, we'll need to re-calculate the
reference element's position.
*/
function listScrollParents(element, list) {
if (list === void 0) {
list = [];
}
var scrollParent = getScrollParent(element);
var isBody = getNodeName(scrollParent) === 'body';
var win = getWindow(scrollParent);
var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;
var updatedList = list.concat(target);
return isBody ? updatedList : // $FlowFixMe: isBody tells us target will be an HTMLElement here
updatedList.concat(listScrollParents(getParentNode(target)));
}
function isTableElement(element) {
return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;
}
function getTrueOffsetParent(element) {
if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837
getComputedStyle(element).position === 'fixed') {
return null;
}
var offsetParent = element.offsetParent;
if (offsetParent) {
var html = getDocumentElement(offsetParent);
if (getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static' && getComputedStyle(html).position !== 'static') {
return html;
}
}
return offsetParent;
} // `.offsetParent` reports `null` for fixed elements, while absolute elements
// return the containing block
function getContainingBlock(element) {
var currentNode = getParentNode(element);
while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {
var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that
// create a containing block.
if (css.transform !== 'none' || css.perspective !== 'none' || css.willChange && css.willChange !== 'auto') {
return currentNode;
} else {
currentNode = currentNode.parentNode;
}
}
return null;
} // Gets the closest ancestor positioned element. Handles some edge cases,
// such as table ancestors and cross browser bugs.
function getOffsetParent(element) {
var window = getWindow(element);
var offsetParent = getTrueOffsetParent(element);
while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {
offsetParent = getTrueOffsetParent(offsetParent);
}
if (offsetParent && getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static') {
return window;
}
return offsetParent || getContainingBlock(element) || window;
}
var top = 'top';
var bottom = 'bottom';
var right = 'right';
var left = 'left';
var auto = 'auto';
var basePlacements = [top, bottom, right, left];
var start = 'start';
var end = 'end';
var clippingParents = 'clippingParents';
var viewport = 'viewport';
var popper = 'popper';
var reference = 'reference';
var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {
return acc.concat([placement + "-" + start, placement + "-" + end]);
}, []);
var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {
return acc.concat([placement, placement + "-" + start, placement + "-" + end]);
}, []); // modifiers that need to read the DOM
var beforeRead = 'beforeRead';
var read = 'read';
var afterRead = 'afterRead'; // pure-logic modifiers
var beforeMain = 'beforeMain';
var main = 'main';
var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)
var beforeWrite = 'beforeWrite';
var write = 'write';
var afterWrite = 'afterWrite';
var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];
function order(modifiers) {
var map = new Map();
var visited = new Set();
var result = [];
modifiers.forEach(function (modifier) {
map.set(modifier.name, modifier);
}); // On visiting object, check for its dependencies and visit them recursively
function sort(modifier) {
visited.add(modifier.name);
var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);
requires.forEach(function (dep) {
if (!visited.has(dep)) {
var depModifier = map.get(dep);
if (depModifier) {
sort(depModifier);
}
}
});
result.push(modifier);
}
modifiers.forEach(function (modifier) {
if (!visited.has(modifier.name)) {
// check for visited object
sort(modifier);
}
});
return result;
}
function orderModifiers(modifiers) {
// order based on dependencies
var orderedModifiers = order(modifiers); // order based on phase
return modifierPhases.reduce(function (acc, phase) {
return acc.concat(orderedModifiers.filter(function (modifier) {
return modifier.phase === phase;
}));
}, []);
}
function debounce(fn) {
var pending;
return function () {
if (!pending) {
pending = new Promise(function (resolve) {
Promise.resolve().then(function () {
pending = undefined;
resolve(fn());
});
});
}
return pending;
};
}
function format(str) {
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
return [].concat(args).reduce(function (p, c) {
return p.replace(/%s/, c);
}, str);
}
var INVALID_MODIFIER_ERROR = 'Popper: modifier "%s" provided an invalid %s property, expected %s but got %s';
var MISSING_DEPENDENCY_ERROR = 'Popper: modifier "%s" requires "%s", but "%s" modifier is not available';
var VALID_PROPERTIES = ['name', 'enabled', 'phase', 'fn', 'effect', 'requires', 'options'];
function validateModifiers(modifiers) {
modifiers.forEach(function (modifier) {
Object.keys(modifier).forEach(function (key) {
switch (key) {
case 'name':
if (typeof modifier.name !== 'string') {
console.error(format(INVALID_MODIFIER_ERROR, String(modifier.name), '"name"', '"string"', "\"" + String(modifier.name) + "\""));
}
break;
case 'enabled':
if (typeof modifier.enabled !== 'boolean') {
console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"enabled"', '"boolean"', "\"" + String(modifier.enabled) + "\""));
}
case 'phase':
if (modifierPhases.indexOf(modifier.phase) < 0) {
console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"phase"', "either " + modifierPhases.join(', '), "\"" + String(modifier.phase) + "\""));
}
break;
case 'fn':
if (typeof modifier.fn !== 'function') {
console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"fn"', '"function"', "\"" + String(modifier.fn) + "\""));
}
break;
case 'effect':
if (typeof modifier.effect !== 'function') {
console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"effect"', '"function"', "\"" + String(modifier.fn) + "\""));
}
break;
case 'requires':
if (!Array.isArray(modifier.requires)) {
console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"requires"', '"array"', "\"" + String(modifier.requires) + "\""));
}
break;
case 'requiresIfExists':
if (!Array.isArray(modifier.requiresIfExists)) {
console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"requiresIfExists"', '"array"', "\"" + String(modifier.requiresIfExists) + "\""));
}
break;
case 'options':
case 'data':
break;
default:
console.error("PopperJS: an invalid property has been provided to the \"" + modifier.name + "\" modifier, valid properties are " + VALID_PROPERTIES.map(function (s) {
return "\"" + s + "\"";
}).join(', ') + "; but \"" + key + "\" was provided.");
}
modifier.requires && modifier.requires.forEach(function (requirement) {
if (modifiers.find(function (mod) {
return mod.name === requirement;
}) == null) {
console.error(format(MISSING_DEPENDENCY_ERROR, String(modifier.name), requirement, requirement));
}
});
});
});
}
function uniqueBy(arr, fn) {
var identifiers = new Set();
return arr.filter(function (item) {
var identifier = fn(item);
if (!identifiers.has(identifier)) {
identifiers.add(identifier);
return true;
}
});
}
function getBasePlacement(placement) {
return placement.split('-')[0];
}
function mergeByName(modifiers) {
var merged = modifiers.reduce(function (merged, current) {
var existing = merged[current.name];
merged[current.name] = existing ? Object.assign(Object.assign(Object.assign({}, existing), current), {}, {
options: Object.assign(Object.assign({}, existing.options), current.options),
data: Object.assign(Object.assign({}, existing.data), current.data)
}) : current;
return merged;
}, {}); // IE11 does not support Object.values
return Object.keys(merged).map(function (key) {
return merged[key];
});
}
function getViewportRect(element) {
var win = getWindow(element);
var html = getDocumentElement(element);
var visualViewport = win.visualViewport;
var width = html.clientWidth;
var height = html.clientHeight;
var x = 0;
var y = 0; // NB: This isn't supported on iOS <= 12. If the keyboard is open, the popper
// can be obscured underneath it.
// Also, `html.clientHeight` adds the bottom bar height in Safari iOS, even
// if it isn't open, so if this isn't available, the popper will be detected
// to overflow the bottom of the screen too early.
if (visualViewport) {
width = visualViewport.width;
height = visualViewport.height; // Uses Layout Viewport (like Chrome; Safari does not currently)
// In Chrome, it returns a value very close to 0 (+/-) but contains rounding
// errors due to floating point numbers, so we need to check precision.
// Safari returns a number <= 0, usually < -1 when pinch-zoomed
// Feature detection fails in mobile emulation mode in Chrome.
// Math.abs(win.innerWidth / visualViewport.scale - visualViewport.width) <
// 0.001
// Fallback here: "Not Safari" userAgent
if (!/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
x = visualViewport.offsetLeft;
y = visualViewport.offsetTop;
}
}
return {
width: width,
height: height,
x: x + getWindowScrollBarX(element),
y: y
};
}
// of the `<html>` and `<body>` rect bounds if horizontally scrollable
function getDocumentRect(element) {
var html = getDocumentElement(element);
var winScroll = getWindowScroll(element);
var body = element.ownerDocument.body;
var width = Math.max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);
var height = Math.max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);
var x = -winScroll.scrollLeft + getWindowScrollBarX(element);
var y = -winScroll.scrollTop;
if (getComputedStyle(body || html).direction === 'rtl') {
x += Math.max(html.clientWidth, body ? body.clientWidth : 0) - width;
}
return {
width: width,
height: height,
x: x,
y: y
};
}
function contains(parent, child) {
var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method
if (parent.contains(child)) {
return true;
} // then fallback to custom implementation with Shadow DOM support
else if (rootNode && isShadowRoot(rootNode)) {
var next = child;
do {
if (next && parent.isSameNode(next)) {
return true;
} // $FlowFixMe: need a better way to handle this...
next = next.parentNode || next.host;
} while (next);
} // Give up, the result is false
return false;
}
function rectToClientRect(rect) {
return Object.assign(Object.assign({}, rect), {}, {
left: rect.x,
top: rect.y,
right: rect.x + rect.width,
bottom: rect.y + rect.height
});
}
function getInnerBoundingClientRect(element) {
var rect = getBoundingClientRect(element);
rect.top = rect.top + element.clientTop;
rect.left = rect.left + element.clientLeft;
rect.bottom = rect.top + element.clientHeight;
rect.right = rect.left + element.clientWidth;
rect.width = element.clientWidth;
rect.height = element.clientHeight;
rect.x = rect.left;
rect.y = rect.top;
return rect;
}
function getClientRectFromMixedType(element, clippingParent) {
return clippingParent === viewport ? rectToClientRect(getViewportRect(element)) : isHTMLElement(clippingParent) ? getInnerBoundingClientRect(clippingParent) : rectToClientRect(getDocumentRect(getDocumentElement(element)));
} // A "clipping parent" is an overflowable container with the characteristic of
// clipping (or hiding) overflowing elements with a position different from
// `initial`
function getClippingParents(element) {
var clippingParents = listScrollParents(getParentNode(element));
var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;
var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;
if (!isElement(clipperElement)) {
return [];
} // $FlowFixMe: https://github.com/facebook/flow/issues/1414
return clippingParents.filter(function (clippingParent) {
return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';
});
} // Gets the maximum area that the element is visible in due to any number of
// clipping parents
function getClippingRect(element, boundary, rootBoundary) {
var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);
var clippingParents = [].concat(mainClippingParents, [rootBoundary]);
var firstClippingParent = clippingParents[0];
var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {
var rect = getClientRectFromMixedType(element, clippingParent);
accRect.top = Math.max(rect.top, accRect.top);
accRect.right = Math.min(rect.right, accRect.right);
accRect.bottom = Math.min(rect.bottom, accRect.bottom);
accRect.left = Math.max(rect.left, accRect.left);
return accRect;
}, getClientRectFromMixedType(element, firstClippingParent));
clippingRect.width = clippingRect.right - clippingRect.left;
clippingRect.height = clippingRect.bottom - clippingRect.top;
clippingRect.x = clippingRect.left;
clippingRect.y = clippingRect.top;
return clippingRect;
}
function getVariation(placement) {
return placement.split('-')[1];
}
function getMainAxisFromPlacement(placement) {
return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';
}
function computeOffsets(_ref) {
var reference = _ref.reference,
element = _ref.element,
placement = _ref.placement;
var basePlacement = placement ? getBasePlacement(placement) : null;
var variation = placement ? getVariation(placement) : null;
var commonX = reference.x + reference.width / 2 - element.width / 2;
var commonY = reference.y + reference.height / 2 - element.height / 2;
var offsets;
switch (basePlacement) {
case top:
offsets = {
x: commonX,
y: reference.y - element.height
};
break;
case bottom:
offsets = {
x: commonX,
y: reference.y + reference.height
};
break;
case right:
offsets = {
x: reference.x + reference.width,
y: commonY
};
break;
case left:
offsets = {
x: reference.x - element.width,
y: commonY
};
break;
default:
offsets = {
x: reference.x,
y: reference.y
};
}
var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;
if (mainAxis != null) {
var len = mainAxis === 'y' ? 'height' : 'width';
switch (variation) {
case start:
offsets[mainAxis] = Math.floor(offsets[mainAxis]) - Math.floor(reference[len] / 2 - element[len] / 2);
break;
case end:
offsets[mainAxis] = Math.floor(offsets[mainAxis]) + Math.ceil(reference[len] / 2 - element[len] / 2);
break;
}
}
return offsets;
}
function getFreshSideObject() {
return {
top: 0,
right: 0,
bottom: 0,
left: 0
};
}
function mergePaddingObject(paddingObject) {
return Object.assign(Object.assign({}, getFreshSideObject()), paddingObject);
}
function expandToHashMap(value, keys) {
return keys.reduce(function (hashMap, key) {
hashMap[key] = value;
return hashMap;
}, {});
}
function detectOverflow(state, options) {
if (options === void 0) {
options = {};
}
var _options = options,
_options$placement = _options.placement,
placement = _options$placement === void 0 ? state.placement : _options$placement,
_options$boundary = _options.boundary,
boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,
_options$rootBoundary = _options.rootBoundary,
rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,
_options$elementConte = _options.elementContext,
elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,
_options$altBoundary = _options.altBoundary,
altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,
_options$padding = _options.padding,
padding = _options$padding === void 0 ? 0 : _options$padding;
var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));
var altContext = elementContext === popper ? reference : popper;
var referenceElement = state.elements.reference;
var popperRect = state.rects.popper;
var element = state.elements[altBoundary ? altContext : elementContext];
var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary);
var referenceClientRect = getBoundingClientRect(referenceElement);
var popperOffsets = computeOffsets({
reference: referenceClientRect,
element: popperRect,
strategy: 'absolute',
placement: placement
});
var popperClientRect = rectToClientRect(Object.assign(Object.assign({}, popperRect), popperOffsets));
var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect
// 0 or negative = within the clipping rect
var overflowOffsets = {
top: clippingClientRect.top - elementClientRect.top + paddingObject.top,
bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,
left: clippingClientRect.left - elementClientRect.left + paddingObject.left,
right: elementClientRect.right - clippingClientRect.right + paddingObject.right
};
var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element
if (elementContext === popper && offsetData) {
var offset = offsetData[placement];
Object.keys(overflowOffsets).forEach(function (key) {
var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;
var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';
overflowOffsets[key] += offset[axis] * multiply;
});
}
return overflowOffsets;
}
var INVALID_ELEMENT_ERROR = 'Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element.';
var INFINITE_LOOP_ERROR = 'Popper: An infinite loop in the modifiers cycle has been detected! The cycle has been interrupted to prevent a browser crash.';
var DEFAULT_OPTIONS = {
placement: 'bottom',
modifiers: [],
strategy: 'absolute'
};
function areValidElements() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return !args.some(function (element) {
return !(element && typeof element.getBoundingClientRect === 'function');
});
}
function popperGenerator(generatorOptions) {
if (generatorOptions === void 0) {
generatorOptions = {};
}
var _generatorOptions = generatorOptions,
_generatorOptions$def = _generatorOptions.defaultModifiers,
defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,
_generatorOptions$def2 = _generatorOptions.defaultOptions,
defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;
return function createPopper(reference, popper, options) {
if (options === void 0) {
options = defaultOptions;
}
var state = {
placement: 'bottom',
orderedModifiers: [],
options: Object.assign(Object.assign({}, DEFAULT_OPTIONS), defaultOptions),
modifiersData: {},
elements: {
reference: reference,
popper: popper
},
attributes: {},
styles: {}
};
var effectCleanupFns = [];
var isDestroyed = false;
var instance = {
state: state,
setOptions: function setOptions(options) {
cleanupModifierEffects();
state.options = Object.assign(Object.assign(Object.assign({}, defaultOptions), state.options), options);
state.scrollParents = {
reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],
popper: listScrollParents(popper)
}; // Orders the modifiers based on their dependencies and `phase`
// properties
var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers
state.orderedModifiers = orderedModifiers.filter(function (m) {
return m.enabled;
}); // Validate the provided modifiers so that the consumer will get warned
// if one of the modifiers is invalid for any reason
if (process.env.NODE_ENV !== "production") {
var modifiers = uniqueBy([].concat(orderedModifiers, state.options.modifiers), function (_ref) {
var name = _ref.name;
return name;
});
validateModifiers(modifiers);
if (getBasePlacement(state.options.placement) === auto) {
var flipModifier = state.orderedModifiers.find(function (_ref2) {
var name = _ref2.name;
return name === 'flip';
});
if (!flipModifier) {
console.error(['Popper: "auto" placements require the "flip" modifier be', 'present and enabled to work.'].join(' '));
}
}
var _getComputedStyle = getComputedStyle(popper),
marginTop = _getComputedStyle.marginTop,
marginRight = _getComputedStyle.marginRight,
marginBottom = _getComputedStyle.marginBottom,
marginLeft = _getComputedStyle.marginLeft; // We no longer take into account `margins` on the popper, and it can
// cause bugs with positioning, so we'll warn the consumer
if ([marginTop, marginRight, marginBottom, marginLeft].some(function (margin) {
return parseFloat(margin);
})) {
console.warn(['Popper: CSS "margin" styles cannot be used to apply padding', 'between the popper and its reference element or boundary.', 'To replicate margin, use the `offset` modifier, as well as', 'the `padding` option in the `preventOverflow` and `flip`', 'modifiers.'].join(' '));
}
}
runModifierEffects();
return instance.update();
},
// Sync update it will always be executed, even if not necessary. This
// is useful for low frequency updates where sync behavior simplifies the
// logic.
// For high frequency updates (e.g. `resize` and `scroll` events), always
// prefer the async Popper#update method
forceUpdate: function forceUpdate() {
if (isDestroyed) {
return;
}
var _state$elements = state.elements,
reference = _state$elements.reference,
popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements
// anymore
if (!areValidElements(reference, popper)) {
if (process.env.NODE_ENV !== "production") {
console.error(INVALID_ELEMENT_ERROR);
}
return;
} // Store the reference and popper rects to be read by modifiers
state.rects = {
reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),
popper: getLayoutRect(popper)
}; // Modifiers have the ability to reset the current update cycle. The
// most common use case for this is the `flip` modifier changing the
// placement, which then needs to re-run all the modifiers, because the
// logic was previously ran for the previous placement and is therefore
// stale/incorrect
state.reset = false;
state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier
// is filled with the initial data specified by the modifier. This means
// it doesn't persist and is fresh on each update.
// To ensure persistent data, use `${name}#persistent`
state.orderedModifiers.forEach(function (modifier) {
return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);
});
var __debug_loops__ = 0;
for (var index = 0; index < state.orderedModifiers.length; index++) {
if (process.env.NODE_ENV !== "production") {
__debug_loops__ += 1;
if (__debug_loops__ > 100) {
console.error(INFINITE_LOOP_ERROR);
break;
}
}
if (state.reset === true) {
state.reset = false;
index = -1;
continue;
}
var _state$orderedModifie = state.orderedModifiers[index],
fn = _state$orderedModifie.fn,
_state$orderedModifie2 = _state$orderedModifie.options,
_options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,
name = _state$orderedModifie.name;
if (typeof fn === 'function') {
state = fn({
state: state,
options: _options,
name: name,
instance: instance
}) || state;
}
}
},
// Async and optimistically optimized update it will not be executed if
// not necessary (debounced to run at most once-per-tick)
update: debounce(function () {
return new Promise(function (resolve) {
instance.forceUpdate();
resolve(state);
});
}),
destroy: function destroy() {
cleanupModifierEffects();
isDestroyed = true;
}
};
if (!areValidElements(reference, popper)) {
if (process.env.NODE_ENV !== "production") {
console.error(INVALID_ELEMENT_ERROR);
}
return instance;
}
instance.setOptions(options).then(function (state) {
if (!isDestroyed && options.onFirstUpdate) {
options.onFirstUpdate(state);
}
}); // Modifiers have the ability to execute arbitrary code before the first
// update cycle runs. They will be executed in the same order as the update
// cycle. This is useful when a modifier adds some persistent data that
// other modifiers need to use, but the modifier is run after the dependent
// one.
function runModifierEffects() {
state.orderedModifiers.forEach(function (_ref3) {
var name = _ref3.name,
_ref3$options = _ref3.options,
options = _ref3$options === void 0 ? {} : _ref3$options,
effect = _ref3.effect;
if (typeof effect === 'function') {
var cleanupFn = effect({
state: state,
name: name,
instance: instance,
options: options
});
var noopFn = function noopFn() {};
effectCleanupFns.push(cleanupFn || noopFn);
}
});
}
function cleanupModifierEffects() {
effectCleanupFns.forEach(function (fn) {
return fn();
});
effectCleanupFns = [];
}
return instance;
};
}
var passive = {
passive: true
};
function effect(_ref) {
var state = _ref.state,
instance = _ref.instance,
options = _ref.options;
var _options$scroll = options.scroll,
scroll = _options$scroll === void 0 ? true : _options$scroll,
_options$resize = options.resize,
resize = _options$resize === void 0 ? true : _options$resize;
var window = getWindow(state.elements.popper);
var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);
if (scroll) {
scrollParents.forEach(function (scrollParent) {
scrollParent.addEventListener('scroll', instance.update, passive);
});
}
if (resize) {
window.addEventListener('resize', instance.update, passive);
}
return function () {
if (scroll) {
scrollParents.forEach(function (scrollParent) {
scrollParent.removeEventListener('scroll', instance.update, passive);
});
}
if (resize) {
window.removeEventListener('resize', instance.update, passive);
}
};
} // eslint-disable-next-line import/no-unused-modules
var eventListeners = {
name: 'eventListeners',
enabled: true,
phase: 'write',
fn: function fn() {},
effect: effect,
data: {}
};
function popperOffsets(_ref) {
var state = _ref.state,
name = _ref.name;
// Offsets are the actual position the popper needs to have to be
// properly positioned near its reference element
// This is the most basic placement, and will be adjusted by
// the modifiers in the next step
state.modifiersData[name] = computeOffsets({
reference: state.rects.reference,
element: state.rects.popper,
strategy: 'absolute',
placement: state.placement
});
} // eslint-disable-next-line import/no-unused-modules
var popperOffsets$1 = {
name: 'popperOffsets',
enabled: true,
phase: 'read',
fn: popperOffsets,
data: {}
};
var unsetSides = {
top: 'auto',
right: 'auto',
bottom: 'auto',
left: 'auto'
}; // Round the offsets to the nearest suitable subpixel based on the DPR.
// Zooming can change the DPR, but it seems to report a value that will
// cleanly divide the values into the appropriate subpixels.
function roundOffsets(_ref) {
var x = _ref.x,
y = _ref.y;
var win = window;
var dpr = win.devicePixelRatio || 1;
return {
x: Math.round(x * dpr) / dpr || 0,
y: Math.round(y * dpr) / dpr || 0
};
}
function mapToStyles(_ref2) {
var _Object$assign2;
var popper = _ref2.popper,
popperRect = _ref2.popperRect,
placement = _ref2.placement,
offsets = _ref2.offsets,
position = _ref2.position,
gpuAcceleration = _ref2.gpuAcceleration,
adaptive = _ref2.adaptive;
var _roundOffsets = roundOffsets(offsets),
x = _roundOffsets.x,
y = _roundOffsets.y;
var hasX = offsets.hasOwnProperty('x');
var hasY = offsets.hasOwnProperty('y');
var sideX = left;
var sideY = top;
var win = window;
if (adaptive) {
var offsetParent = getOffsetParent(popper);
if (offsetParent === getWindow(popper)) {
offsetParent = getDocumentElement(popper);
} // $FlowFixMe: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it
/*:: offsetParent = (offsetParent: Element); */
if (placement === top) {
sideY = bottom;
y -= offsetParent.clientHeight - popperRect.height;
y *= gpuAcceleration ? 1 : -1;
}
if (placement === left) {
sideX = right;
x -= offsetParent.clientWidth - popperRect.width;
x *= gpuAcceleration ? 1 : -1;
}
}
var commonStyles = Object.assign({
position: position
}, adaptive && unsetSides);
if (gpuAcceleration) {
var _Object$assign;
return Object.assign(Object.assign({}, commonStyles), {}, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) < 2 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign));
}
return Object.assign(Object.assign({}, commonStyles), {}, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2));
}
function computeStyles(_ref3) {
var state = _ref3.state,
options = _ref3.options;
var _options$gpuAccelerat = options.gpuAcceleration,
gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,
_options$adaptive = options.adaptive,
adaptive = _options$adaptive === void 0 ? true : _options$adaptive;
if (process.env.NODE_ENV !== "production") {
var transitionProperty = getComputedStyle(state.elements.popper).transitionProperty || '';
if (adaptive && ['transform', 'top', 'right', 'bottom', 'left'].some(function (property) {
return transitionProperty.indexOf(property) >= 0;
})) {
console.warn(['Popper: Detected CSS transitions on at least one of the following', 'CSS properties: "transform", "top", "right", "bottom", "left".', '\n\n', 'Disable the "computeStyles" modifier\'s `adaptive` option to allow', 'for smooth transitions, or remove these properties from the CSS', 'transition declaration on the popper element if only transitioning', 'opacity or background-color for example.', '\n\n', 'We recommend using the popper element as a wrapper around an inner', 'element that can have any CSS property transitioned for animations.'].join(' '));
}
}
var commonStyles = {
placement: getBasePlacement(state.placement),
popper: state.elements.popper,
popperRect: state.rects.popper,
gpuAcceleration: gpuAcceleration
};
if (state.modifiersData.popperOffsets != null) {
state.styles.popper = Object.assign(Object.assign({}, state.styles.popper), mapToStyles(Object.assign(Object.assign({}, commonStyles), {}, {
offsets: state.modifiersData.popperOffsets,
position: state.options.strategy,
adaptive: adaptive
})));
}
if (state.modifiersData.arrow != null) {
state.styles.arrow = Object.assign(Object.assign({}, state.styles.arrow), mapToStyles(Object.assign(Object.assign({}, commonStyles), {}, {
offsets: state.modifiersData.arrow,
position: 'absolute',
adaptive: false
})));
}
state.attributes.popper = Object.assign(Object.assign({}, state.attributes.popper), {}, {
'data-popper-placement': state.placement
});
} // eslint-disable-next-line import/no-unused-modules
var computeStyles$1 = {
name: 'computeStyles',
enabled: true,
phase: 'beforeWrite',
fn: computeStyles,
data: {}
};
// and applies them to the HTMLElements such as popper and arrow
function applyStyles(_ref) {
var state = _ref.state;
Object.keys(state.elements).forEach(function (name) {
var style = state.styles[name] || {};
var attributes = state.attributes[name] || {};
var element = state.elements[name]; // arrow is optional + virtual elements
if (!isHTMLElement(element) || !getNodeName(element)) {
return;
} // Flow doesn't support to extend this property, but it's the most
// effective way to apply styles to an HTMLElement
// $FlowFixMe
Object.assign(element.style, style);
Object.keys(attributes).forEach(function (name) {
var value = attributes[name];
if (value === false) {
element.removeAttribute(name);
} else {
element.setAttribute(name, value === true ? '' : value);
}
});
});
}
function effect$1(_ref2) {
var state = _ref2.state;
var initialStyles = {
popper: {
position: state.options.strategy,
left: '0',
top: '0',
margin: '0'
},
arrow: {
position: 'absolute'
},
reference: {}
};
Object.assign(state.elements.popper.style, initialStyles.popper);
if (state.elements.arrow) {
Object.assign(state.elements.arrow.style, initialStyles.arrow);
}
return function () {
Object.keys(state.elements).forEach(function (name) {
var element = state.elements[name];
var attributes = state.attributes[name] || {};
var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them
var style = styleProperties.reduce(function (style, property) {
style[property] = '';
return style;
}, {}); // arrow is optional + virtual elements
if (!isHTMLElement(element) || !getNodeName(element)) {
return;
} // Flow doesn't support to extend this property, but it's the most
// effective way to apply styles to an HTMLElement
// $FlowFixMe
Object.assign(element.style, style);
Object.keys(attributes).forEach(function (attribute) {
element.removeAttribute(attribute);
});
});
};
} // eslint-disable-next-line import/no-unused-modules
var applyStyles$1 = {
name: 'applyStyles',
enabled: true,
phase: 'write',
fn: applyStyles,
effect: effect$1,
requires: ['computeStyles']
};
function distanceAndSkiddingToXY(placement, rects, offset) {
var basePlacement = getBasePlacement(placement);
var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;
var _ref = typeof offset === 'function' ? offset(Object.assign(Object.assign({}, rects), {}, {
placement: placement
})) : offset,
skidding = _ref[0],
distance = _ref[1];
skidding = skidding || 0;
distance = (distance || 0) * invertDistance;
return [left, right].indexOf(basePlacement) >= 0 ? {
x: distance,
y: skidding
} : {
x: skidding,
y: distance
};
}
function offset(_ref2) {
var state = _ref2.state,
options = _ref2.options,
name = _ref2.name;
var _options$offset = options.offset,
offset = _options$offset === void 0 ? [0, 0] : _options$offset;
var data = placements.reduce(function (acc, placement) {
acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);
return acc;
}, {});
var _data$state$placement = data[state.placement],
x = _data$state$placement.x,
y = _data$state$placement.y;
if (state.modifiersData.popperOffsets != null) {
state.modifiersData.popperOffsets.x += x;
state.modifiersData.popperOffsets.y += y;
}
state.modifiersData[name] = data;
} // eslint-disable-next-line import/no-unused-modules
var offset$1 = {
name: 'offset',
enabled: true,
phase: 'main',
requires: ['popperOffsets'],
fn: offset
};
var hash = {
left: 'right',
right: 'left',
bottom: 'top',
top: 'bottom'
};
function getOppositePlacement(placement) {
return placement.replace(/left|right|bottom|top/g, function (matched) {
return hash[matched];
});
}
var hash$1 = {
start: 'end',
end: 'start'
};
function getOppositeVariationPlacement(placement) {
return placement.replace(/start|end/g, function (matched) {
return hash$1[matched];
});
}
/*:: type OverflowsMap = { [ComputedPlacement]: number }; */
/*;; type OverflowsMap = { [key in ComputedPlacement]: number }; */
function computeAutoPlacement(state, options) {
if (options === void 0) {
options = {};
}
var _options = options,
placement = _options.placement,
boundary = _options.boundary,
rootBoundary = _options.rootBoundary,
padding = _options.padding,
flipVariations = _options.flipVariations,
_options$allowedAutoP = _options.allowedAutoPlacements,
allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP;
var variation = getVariation(placement);
var placements$1 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {
return getVariation(placement) === variation;
}) : basePlacements; // $FlowFixMe
var allowedPlacements = placements$1.filter(function (placement) {
return allowedAutoPlacements.indexOf(placement) >= 0;
});
if (allowedPlacements.length === 0) {
allowedPlacements = placements$1;
if (process.env.NODE_ENV !== "production") {
console.error(['Popper: The `allowedAutoPlacements` option did not allow any', 'placements. Ensure the `placement` option matches the variation', 'of the allowed placements.', 'For example, "auto" cannot be used to allow "bottom-start".', 'Use "auto-start" instead.'].join(' '));
}
} // $FlowFixMe: Flow seems to have problems with two array unions...
var overflows = allowedPlacements.reduce(function (acc, placement) {
acc[placement] = detectOverflow(state, {
placement: placement,
boundary: boundary,
rootBoundary: rootBoundary,
padding: padding
})[getBasePlacement(placement)];
return acc;
}, {});
return Object.keys(overflows).sort(function (a, b) {
return overflows[a] - overflows[b];
});
}
function getExpandedFallbackPlacements(placement) {
if (getBasePlacement(placement) === auto) {
return [];
}
var oppositePlacement = getOppositePlacement(placement);
return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];
}
function flip(_ref) {
var state = _ref.state,
options = _ref.options,
name = _ref.name;
if (state.modifiersData[name]._skip) {
return;
}
var _options$mainAxis = options.mainAxis,
checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
_options$altAxis = options.altAxis,
checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,
specifiedFallbackPlacements = options.fallbackPlacements,
padding = options.padding,
boundary = options.boundary,
rootBoundary = options.rootBoundary,
altBoundary = options.altBoundary,
_options$flipVariatio = options.flipVariations,
flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,
allowedAutoPlacements = options.allowedAutoPlacements;
var preferredPlacement = state.options.placement;
var basePlacement = getBasePlacement(preferredPlacement);
var isBasePlacement = basePlacement === preferredPlacement;
var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));
var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {
return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {
placement: placement,
boundary: boundary,
rootBoundary: rootBoundary,
padding: padding,
flipVariations: flipVariations,
allowedAutoPlacements: allowedAutoPlacements
}) : placement);
}, []);
var referenceRect = state.rects.reference;
var popperRect = state.rects.popper;
var checksMap = new Map();
var makeFallbackChecks = true;
var firstFittingPlacement = placements[0];
for (var i = 0; i < placements.length; i++) {
var placement = placements[i];
var _basePlacement = getBasePlacement(placement);
var isStartVariation = getVariation(placement) === start;
var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;
var len = isVertical ? 'width' : 'height';
var overflow = detectOverflow(state, {
placement: placement,
boundary: boundary,
rootBoundary: rootBoundary,
altBoundary: altBoundary,
padding: padding
});
var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;
if (referenceRect[len] > popperRect[len]) {
mainVariationSide = getOppositePlacement(mainVariationSide);
}
var altVariationSide = getOppositePlacement(mainVariationSide);
var checks = [];
if (checkMainAxis) {
checks.push(overflow[_basePlacement] <= 0);
}
if (checkAltAxis) {
checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);
}
if (checks.every(function (check) {
return check;
})) {
firstFittingPlacement = placement;
makeFallbackChecks = false;
break;
}
checksMap.set(placement, checks);
}
if (makeFallbackChecks) {
// `2` may be desired in some cases research later
var numberOfChecks = flipVariations ? 3 : 1;
var _loop = function _loop(_i) {
var fittingPlacement = placements.find(function (placement) {
var checks = checksMap.get(placement);
if (checks) {
return checks.slice(0, _i).every(function (check) {
return check;
});
}
});
if (fittingPlacement) {
firstFittingPlacement = fittingPlacement;
return "break";
}
};
for (var _i = numberOfChecks; _i > 0; _i--) {
var _ret = _loop(_i);
if (_ret === "break") break;
}
}
if (state.placement !== firstFittingPlacement) {
state.modifiersData[name]._skip = true;
state.placement = firstFittingPlacement;
state.reset = true;
}
} // eslint-disable-next-line import/no-unused-modules
var flip$1 = {
name: 'flip',
enabled: true,
phase: 'main',
fn: flip,
requiresIfExists: ['offset'],
data: {
_skip: false
}
};
function getAltAxis(axis) {
return axis === 'x' ? 'y' : 'x';
}
function within(min, value, max) {
return Math.max(min, Math.min(value, max));
}
function preventOverflow(_ref) {
var state = _ref.state,
options = _ref.options,
name = _ref.name;
var _options$mainAxis = options.mainAxis,
checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
_options$altAxis = options.altAxis,
checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,
boundary = options.boundary,
rootBoundary = options.rootBoundary,
altBoundary = options.altBoundary,
padding = options.padding,
_options$tether = options.tether,
tether = _options$tether === void 0 ? true : _options$tether,
_options$tetherOffset = options.tetherOffset,
tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;
var overflow = detectOverflow(state, {
boundary: boundary,
rootBoundary: rootBoundary,
padding: padding,
altBoundary: altBoundary
});
var basePlacement = getBasePlacement(state.placement);
var variation = getVariation(state.placement);
var isBasePlacement = !variation;
var mainAxis = getMainAxisFromPlacement(basePlacement);
var altAxis = getAltAxis(mainAxis);
var popperOffsets = state.modifiersData.popperOffsets;
var referenceRect = state.rects.reference;
var popperRect = state.rects.popper;
var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign(Object.assign({}, state.rects), {}, {
placement: state.placement
})) : tetherOffset;
var data = {
x: 0,
y: 0
};
if (!popperOffsets) {
return;
}
if (checkMainAxis) {
var mainSide = mainAxis === 'y' ? top : left;
var altSide = mainAxis === 'y' ? bottom : right;
var len = mainAxis === 'y' ? 'height' : 'width';
var offset = popperOffsets[mainAxis];
var min = popperOffsets[mainAxis] + overflow[mainSide];
var max = popperOffsets[mainAxis] - overflow[altSide];
var additive = tether ? -popperRect[len] / 2 : 0;
var minLen = variation === start ? referenceRect[len] : popperRect[len];
var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go
// outside the reference bounds
var arrowElement = state.elements.arrow;
var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {
width: 0,
height: 0
};
var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();
var arrowPaddingMin = arrowPaddingObject[mainSide];
var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want
// to include its full size in the calculation. If the reference is small
// and near the edge of a boundary, the popper can overflow even if the
// reference is not overflowing as well (e.g. virtual elements with no
// width or height)
var arrowLen = within(0, referenceRect[len], arrowRect[len]);
var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - tetherOffsetValue : minLen - arrowLen - arrowPaddingMin - tetherOffsetValue;
var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + tetherOffsetValue : maxLen + arrowLen + arrowPaddingMax + tetherOffsetValue;
var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);
var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;
var offsetModifierValue = state.modifiersData.offset ? state.modifiersData.offset[state.placement][mainAxis] : 0;
var tetherMin = popperOffsets[mainAxis] + minOffset - offsetModifierValue - clientOffset;
var tetherMax = popperOffsets[mainAxis] + maxOffset - offsetModifierValue;
var preventedOffset = within(tether ? Math.min(min, tetherMin) : min, offset, tether ? Math.max(max, tetherMax) : max);
popperOffsets[mainAxis] = preventedOffset;
data[mainAxis] = preventedOffset - offset;
}
if (checkAltAxis) {
var _mainSide = mainAxis === 'x' ? top : left;
var _altSide = mainAxis === 'x' ? bottom : right;
var _offset = popperOffsets[altAxis];
var _min = _offset + overflow[_mainSide];
var _max = _offset - overflow[_altSide];
var _preventedOffset = within(_min, _offset, _max);
popperOffsets[altAxis] = _preventedOffset;
data[altAxis] = _preventedOffset - _offset;
}
state.modifiersData[name] = data;
} // eslint-disable-next-line import/no-unused-modules
var preventOverflow$1 = {
name: 'preventOverflow',
enabled: true,
phase: 'main',
fn: preventOverflow,
requiresIfExists: ['offset']
};
function arrow(_ref) {
var _state$modifiersData$;
var state = _ref.state,
name = _ref.name;
var arrowElement = state.elements.arrow;
var popperOffsets = state.modifiersData.popperOffsets;
var basePlacement = getBasePlacement(state.placement);
var axis = getMainAxisFromPlacement(basePlacement);
var isVertical = [left, right].indexOf(basePlacement) >= 0;
var len = isVertical ? 'height' : 'width';
if (!arrowElement || !popperOffsets) {
return;
}
var paddingObject = state.modifiersData[name + "#persistent"].padding;
var arrowRect = getLayoutRect(arrowElement);
var minProp = axis === 'y' ? top : left;
var maxProp = axis === 'y' ? bottom : right;
var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];
var startDiff = popperOffsets[axis] - state.rects.reference[axis];
var arrowOffsetParent = getOffsetParent(arrowElement);
var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;
var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is
// outside of the popper bounds
var min = paddingObject[minProp];
var max = clientSize - arrowRect[len] - paddingObject[maxProp];
var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;
var offset = within(min, center, max); // Prevents breaking syntax highlighting...
var axisProp = axis;
state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);
}
function effect$2(_ref2) {
var state = _ref2.state,
options = _ref2.options,
name = _ref2.name;
var _options$element = options.element,
arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element,
_options$padding = options.padding,
padding = _options$padding === void 0 ? 0 : _options$padding;
if (arrowElement == null) {
return;
} // CSS selector
if (typeof arrowElement === 'string') {
arrowElement = state.elements.popper.querySelector(arrowElement);
if (!arrowElement) {
return;
}
}
if (process.env.NODE_ENV !== "production") {
if (!isHTMLElement(arrowElement)) {
console.error(['Popper: "arrow" element must be an HTMLElement (not an SVGElement).', 'To use an SVG arrow, wrap it in an HTMLElement that will be used as', 'the arrow.'].join(' '));
}
}
if (!contains(state.elements.popper, arrowElement)) {
if (process.env.NODE_ENV !== "production") {
console.error(['Popper: "arrow" modifier\'s `element` must be a child of the popper', 'element.'].join(' '));
}
return;
}
state.elements.arrow = arrowElement;
state.modifiersData[name + "#persistent"] = {
padding: mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements))
};
} // eslint-disable-next-line import/no-unused-modules
var arrow$1 = {
name: 'arrow',
enabled: true,
phase: 'main',
fn: arrow,
effect: effect$2,
requires: ['popperOffsets'],
requiresIfExists: ['preventOverflow']
};
function getSideOffsets(overflow, rect, preventedOffsets) {
if (preventedOffsets === void 0) {
preventedOffsets = {
x: 0,
y: 0
};
}
return {
top: overflow.top - rect.height - preventedOffsets.y,
right: overflow.right - rect.width + preventedOffsets.x,
bottom: overflow.bottom - rect.height + preventedOffsets.y,
left: overflow.left - rect.width - preventedOffsets.x
};
}
function isAnySideFullyClipped(overflow) {
return [top, right, bottom, left].some(function (side) {
return overflow[side] >= 0;
});
}
function hide(_ref) {
var state = _ref.state,
name = _ref.name;
var referenceRect = state.rects.reference;
var popperRect = state.rects.popper;
var preventedOffsets = state.modifiersData.preventOverflow;
var referenceOverflow = detectOverflow(state, {
elementContext: 'reference'
});
var popperAltOverflow = detectOverflow(state, {
altBoundary: true
});
var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);
var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);
var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);
var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);
state.modifiersData[name] = {
referenceClippingOffsets: referenceClippingOffsets,
popperEscapeOffsets: popperEscapeOffsets,
isReferenceHidden: isReferenceHidden,
hasPopperEscaped: hasPopperEscaped
};
state.attributes.popper = Object.assign(Object.assign({}, state.attributes.popper), {}, {
'data-popper-reference-hidden': isReferenceHidden,
'data-popper-escaped': hasPopperEscaped
});
} // eslint-disable-next-line import/no-unused-modules
var hide$1 = {
name: 'hide',
enabled: true,
phase: 'main',
requiresIfExists: ['preventOverflow'],
fn: hide
};
var defaultModifiers = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1];
var createPopper = /*#__PURE__*/popperGenerator({
defaultModifiers: defaultModifiers
}); // eslint-disable-next-line import/no-unused-modules
var defaultModifiers$1 = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1, offset$1, flip$1, preventOverflow$1, arrow$1, hide$1];
var createPopper$1 = /*#__PURE__*/popperGenerator({
defaultModifiers: defaultModifiers$1
}); // eslint-disable-next-line import/no-unused-modules
exports.applyStyles = applyStyles$1;
exports.arrow = arrow$1;
exports.computeStyles = computeStyles$1;
exports.createPopper = createPopper$1;
exports.createPopperLite = createPopper;
exports.defaultModifiers = defaultModifiers$1;
exports.detectOverflow = detectOverflow;
exports.eventListeners = eventListeners;
exports.flip = flip$1;
exports.hide = hide$1;
exports.offset = offset$1;
exports.popperGenerator = popperGenerator;
exports.popperOffsets = popperOffsets$1;
exports.preventOverflow = preventOverflow$1;
}).call(this)}).call(this,require('_process'))
},{"_process":187}],2:[function(require,module,exports){
(function (Buffer){(function (){
if ('undefined' === typeof Buffer) {
// implicit global
Buffer = undefined;
}
(function () {
"use strict";
function createBuffer() {
return Array;
/*
function Buffer(sizeOrArrayOrString, encoding) {
var size, arr, str;
if ('number' === typeof sizeOrArrayOrString) {
size = sizeOrArrayOrString;
} else if ('string' === typeof sizeOrArrayOrString) {
// TODO handle encoding
str = String(sizeOrArrayOrString);
arr = arr.split('');
size = arr.length;
} else {
arr = sizeOrArrayOrString;
size = arr.length;
}
this.length = size;
}
Buffer.prototype = new Array();
delete Buffer.prototype.push;
delete Buffer.prototype.pop;
delete Buffer.prototype.shift;
delete Buffer.prototype.unshift;
delete Buffer.prototype.splice;
Buffer.isBuffer = function (buf) {
return buf instanceof Buffer;
};
// TODO
Buffer.byteLength = function (string, encoding) {
console.log('[todo] byteLength');
encoding = encoding || 'utf8';
// return string.length;
};
// TODO
Buffer.prototype.write = function (string, offset, encoding) {
console.log('[todo] write');
};
Buffer.prototype.toString = function (encoding, start, end) {
var res = {}
, i
;
start = start || 0;
end = end || this.length - 1;
res.length = end + 1;
if (this.length === res.length) {
res = this;
} else {
i = 0;
while (start <= end) {
res[i] = this[start];
i += 1;
start += 1;
}
}
return JSON.stringify(res);
};
Buffer.prototype.copy = function (targetBuffer, targetStart, sourceStart, sourceEnd) {
targetStart = targetStart || 0;
sourceStart = sourceStart || 0;
sourceEnd = sourceEnd || targetBuffer.length;
};
Buffer.prototype.slice = function (start, end) {
end = end || this.length;
this.slice(start, end);
}
return Buffer;
*/
}
if ('undefined' === typeof Buffer) {
Buffer = createBuffer();
}
module.exports = Buffer;
}());
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60}],3:[function(require,module,exports){
const ADDR_RE = /^\[?([^\]]+)\]?:(\d+)$/ // ipv4/ipv6/hostname + port
let cache = {}
// reset cache when it gets to 100,000 elements (~ 600KB of ipv4 addresses)
// so it will not grow to consume all memory in long-running processes
let size = 0
module.exports = function addrToIPPort (addr) {
if (size === 100000) module.exports.reset()
if (!cache[addr]) {
const m = ADDR_RE.exec(addr)
if (!m) throw new Error(`invalid addr: ${addr}`)
cache[addr] = [ m[1], Number(m[2]) ]
size += 1
}
return cache[addr]
}
module.exports.reset = function reset () {
cache = {}
size = 0
}
},{}],4:[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
}
// Support decoding URL-safe base64 strings, as Node.js does.
// See: https://en.wikipedia.org/wiki/Base64#URL_applications
revLookup['-'.charCodeAt(0)] = 62
revLookup['_'.charCodeAt(0)] = 63
function getLens (b64) {
var len = b64.length
if (len % 4 > 0) {
throw new Error('Invalid string. Length must be a multiple of 4')
}
// Trim off extra bytes after placeholder bytes are found
// See: https://github.com/beatgammit/base64-js/issues/42
var validLen = b64.indexOf('=')
if (validLen === -1) validLen = len
var placeHoldersLen = validLen === len
? 0
: 4 - (validLen % 4)
return [validLen, placeHoldersLen]
}
// base64 is 4/3 + up to two characters of the original data
function byteLength (b64) {
var lens = getLens(b64)
var validLen = lens[0]
var placeHoldersLen = lens[1]
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
}
function _byteLength (b64, validLen, placeHoldersLen) {
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
}
function toByteArray (b64) {
var tmp
var lens = getLens(b64)
var validLen = lens[0]
var placeHoldersLen = lens[1]
var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
var curByte = 0
// if there are placeholders, only get up to the last complete 4 chars
var len = placeHoldersLen > 0
? validLen - 4
: validLen
var i
for (i = 0; i < len; 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[curByte++] = (tmp >> 16) & 0xFF
arr[curByte++] = (tmp >> 8) & 0xFF
arr[curByte++] = tmp & 0xFF
}
if (placeHoldersLen === 2) {
tmp =
(revLookup[b64.charCodeAt(i)] << 2) |
(revLookup[b64.charCodeAt(i + 1)] >> 4)
arr[curByte++] = tmp & 0xFF
}
if (placeHoldersLen === 1) {
tmp =
(revLookup[b64.charCodeAt(i)] << 10) |
(revLookup[b64.charCodeAt(i + 1)] << 4) |
(revLookup[b64.charCodeAt(i + 2)] >> 2)
arr[curByte++] = (tmp >> 8) & 0xFF
arr[curByte++] = 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) & 0xFF0000) +
((uint8[i + 1] << 8) & 0xFF00) +
(uint8[i + 2] & 0xFF)
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 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]
parts.push(
lookup[tmp >> 2] +
lookup[(tmp << 4) & 0x3F] +
'=='
)
} else if (extraBytes === 2) {
tmp = (uint8[len - 2] << 8) + uint8[len - 1]
parts.push(
lookup[tmp >> 10] +
lookup[(tmp >> 4) & 0x3F] +
lookup[(tmp << 2) & 0x3F] +
'='
)
}
return parts.join('')
}
},{}],5:[function(require,module,exports){
var Buffer = require('safe-buffer').Buffer
const INTEGER_START = 0x69 // 'i'
const STRING_DELIM = 0x3A // ':'
const DICTIONARY_START = 0x64 // 'd'
const LIST_START = 0x6C // 'l'
const END_OF_TYPE = 0x65 // 'e'
/**
* replaces parseInt(buffer.toString('ascii', start, end)).
* For strings with less then ~30 charachters, this is actually a lot faster.
*
* @param {Buffer} data
* @param {Number} start
* @param {Number} end
* @return {Number} calculated number
*/
function getIntFromBuffer (buffer, start, end) {
var sum = 0
var sign = 1
for (var i = start; i < end; i++) {
var num = buffer[i]
if (num < 58 && num >= 48) {
sum = sum * 10 + (num - 48)
continue
}
if (i === start && num === 43) { // +
continue
}
if (i === start && num === 45) { // -
sign = -1
continue
}
if (num === 46) { // .
// its a float. break here.
break
}
throw new Error('not a number: buffer[' + i + '] = ' + num)
}
return sum * sign
}
/**
* Decodes bencoded data.
*
* @param {Buffer} data
* @param {Number} start (optional)
* @param {Number} end (optional)
* @param {String} encoding (optional)
* @return {Object|Array|Buffer|String|Number}
*/
function decode (data, start, end, encoding) {
if (data == null || data.length === 0) {
return null
}
if (typeof start !== 'number' && encoding == null) {
encoding = start
start = undefined
}
if (typeof end !== 'number' && encoding == null) {
encoding = end
end = undefined
}
decode.position = 0
decode.encoding = encoding || null
decode.data = !(Buffer.isBuffer(data))
? Buffer.from(data)
: data.slice(start, end)
decode.bytes = decode.data.length
return decode.next()
}
decode.bytes = 0
decode.position = 0
decode.data = null
decode.encoding = null
decode.next = function () {
switch (decode.data[decode.position]) {
case DICTIONARY_START:
return decode.dictionary()
case LIST_START:
return decode.list()
case INTEGER_START:
return decode.integer()
default:
return decode.buffer()
}
}
decode.find = function (chr) {
var i = decode.position
var c = decode.data.length
var d = decode.data
while (i < c) {
if (d[i] === chr) return i
i++
}
throw new Error(
'Invalid data: Missing delimiter "' +
String.fromCharCode(chr) + '" [0x' +
chr.toString(16) + ']'
)
}
decode.dictionary = function () {
decode.position++
var dict = {}
while (decode.data[decode.position] !== END_OF_TYPE) {
dict[decode.buffer()] = decode.next()
}
decode.position++
return dict
}
decode.list = function () {
decode.position++
var lst = []
while (decode.data[decode.position] !== END_OF_TYPE) {
lst.push(decode.next())
}
decode.position++
return lst
}
decode.integer = function () {
var end = decode.find(END_OF_TYPE)
var number = getIntFromBuffer(decode.data, decode.position + 1, end)
decode.position += end + 1 - decode.position
return number
}
decode.buffer = function () {
var sep = decode.find(STRING_DELIM)
var length = getIntFromBuffer(decode.data, decode.position, sep)
var end = ++sep + length
decode.position = end
return decode.encoding
? decode.data.toString(decode.encoding, sep, end)
: decode.data.slice(sep, end)
}
module.exports = decode
},{"safe-buffer":220}],6:[function(require,module,exports){
var Buffer = require('safe-buffer').Buffer
/**
* Encodes data in bencode.
*
* @param {Buffer|Array|String|Object|Number|Boolean} data
* @return {Buffer}
*/
function encode (data, buffer, offset) {
var buffers = []
var result = null
encode._encode(buffers, data)
result = Buffer.concat(buffers)
encode.bytes = result.length
if (Buffer.isBuffer(buffer)) {
result.copy(buffer, offset)
return buffer
}
return result
}
encode.bytes = -1
encode._floatConversionDetected = false
encode.getType = function (value) {
if (Buffer.isBuffer(value)) return 'buffer'
if (Array.isArray(value)) return 'array'
if (ArrayBuffer.isView(value)) return 'arraybufferview'
if (value instanceof Number) return 'number'
if (value instanceof Boolean) return 'boolean'
if (value instanceof ArrayBuffer) return 'arraybuffer'
return typeof value
}
encode._encode = function (buffers, data) {
if (data == null) { return }
switch (encode.getType(data)) {
case 'buffer': encode.buffer(buffers, data); break
case 'object': encode.dict(buffers, data); break
case 'array': encode.list(buffers, data); break
case 'string': encode.string(buffers, data); break
case 'number': encode.number(buffers, data); break
case 'boolean': encode.number(buffers, data); break
case 'arraybufferview': encode.buffer(buffers, Buffer.from(data.buffer, data.byteOffset, data.byteLength)); break
case 'arraybuffer': encode.buffer(buffers, Buffer.from(data)); break
}
}
var buffE = Buffer.from('e')
var buffD = Buffer.from('d')
var buffL = Buffer.from('l')
encode.buffer = function (buffers, data) {
buffers.push(Buffer.from(data.length + ':'), data)
}
encode.string = function (buffers, data) {
buffers.push(Buffer.from(Buffer.byteLength(data) + ':' + data))
}
encode.number = function (buffers, data) {
var maxLo = 0x80000000
var hi = (data / maxLo) << 0
var lo = (data % maxLo) << 0
var val = hi * maxLo + lo
buffers.push(Buffer.from('i' + val + 'e'))
if (val !== data && !encode._floatConversionDetected) {
encode._floatConversionDetected = true
console.warn(
'WARNING: Possible data corruption detected with value "' + data + '":',
'Bencoding only defines support for integers, value was converted to "' + val + '"'
)
console.trace()
}
}
encode.dict = function (buffers, data) {
buffers.push(buffD)
var j = 0
var k
// fix for issue #13 - sorted dicts
var keys = Object.keys(data).sort()
var kl = keys.length
for (; j < kl; j++) {
k = keys[j]
if (data[k] == null) continue
encode.string(buffers, k)
encode._encode(buffers, data[k])
}
buffers.push(buffE)
}
encode.list = function (buffers, data) {
var i = 0
var c = data.length
buffers.push(buffL)
for (; i < c; i++) {
if (data[i] == null) continue
encode._encode(buffers, data[i])
}
buffers.push(buffE)
}
module.exports = encode
},{"safe-buffer":220}],7:[function(require,module,exports){
var bencode = module.exports
bencode.encode = require('./encode')
bencode.decode = require('./decode')
/**
* Determines the amount of bytes
* needed to encode the given value
* @param {Object|Array|Buffer|String|Number|Boolean} value
* @return {Number} byteCount
*/
bencode.byteLength = bencode.encodingLength = function (value) {
return bencode.encode(value).length
}
},{"./decode":5,"./encode":6}],8:[function(require,module,exports){
module.exports = parseRange
module.exports.parse = parseRange
module.exports.compose = composeRange
function composeRange (range) {
return range
.reduce((acc, cur, idx, arr) => {
if (idx === 0 || cur !== arr[idx - 1] + 1) acc.push([])
acc[acc.length - 1].push(cur)
return acc
}, [])
.map((cur) => {
return cur.length > 1 ? `${cur[0]}-${cur[cur.length - 1]}` : `${cur[0]}`
})
}
function parseRange (range) {
const generateRange = (start, end = start) => Array.from({ length: end - start + 1 }, (cur, idx) => idx + start)
return range
.reduce((acc, cur, idx, arr) => {
const r = cur.split('-').map(cur => parseInt(cur))
return acc.concat(generateRange(...r))
}, [])
}
},{}],9:[function(require,module,exports){
module.exports = function(haystack, needle, comparator, low, high) {
var mid, cmp;
if(low === undefined)
low = 0;
else {
low = low|0;
if(low < 0 || low >= haystack.length)
throw new RangeError("invalid lower bound");
}
if(high === undefined)
high = haystack.length - 1;
else {
high = high|0;
if(high < low || high >= haystack.length)
throw new RangeError("invalid upper bound");
}
while(low <= high) {
// The naive `low + high >>> 1` could fail for array lengths > 2**31
// because `>>>` converts its operands to int32. `low + (high - low >>> 1)`
// works for array lengths <= 2**32-1 which is also Javascript's max array
// length.
mid = low + ((high - low) >>> 1);
cmp = +comparator(haystack[mid], needle, mid, haystack);
// Too low.
if(cmp < 0.0)
low = mid + 1;
// Too high.
else if(cmp > 0.0)
high = mid - 1;
// Key found.
else
return mid;
}
// Key not found.
return ~low;
}
},{}],10:[function(require,module,exports){
function getByteSize (num) {
let out = num >> 3
if (num % 8 !== 0) out++
return out
}
class BitField {
constructor (data = 0, opts) {
const grow = opts != null && opts.grow
this.grow = (grow && isFinite(grow) && getByteSize(grow)) || grow || 0
this.buffer = typeof data === 'number' ? new Uint8Array(getByteSize(data)) : data
}
get (i) {
const j = i >> 3
return (j < this.buffer.length) &&
!!(this.buffer[j] & (128 >> (i % 8)))
}
set (i, b = true) {
const j = i >> 3
if (b) {
if (this.buffer.length < j + 1) {
const length = Math.max(j + 1, Math.min(2 * this.buffer.length, this.grow))
if (length <= this.grow) {
const newBuffer = new Uint8Array(length)
newBuffer.set(this.buffer)
this.buffer = newBuffer
}
}
// Set
this.buffer[j] |= 128 >> (i % 8)
} else if (j < this.buffer.length) {
// Clear
this.buffer[j] &= ~(128 >> (i % 8))
}
}
}
if (typeof module !== 'undefined') module.exports = BitField
},{}],11:[function(require,module,exports){
(function (Buffer){(function (){
/*! bittorrent-protocol. MIT License. WebTorrent LLC <https://webtorrent.io/opensource> */
const arrayRemove = require('unordered-array-remove')
const bencode = require('bencode')
const BitField = require('bitfield').default
const debug = require('debug')('bittorrent-protocol')
const randombytes = require('randombytes')
const speedometer = require('speedometer')
const stream = require('readable-stream')
const BITFIELD_GROW = 400000
const KEEP_ALIVE_TIMEOUT = 55000
const MESSAGE_PROTOCOL = Buffer.from('\u0013BitTorrent protocol')
const MESSAGE_KEEP_ALIVE = Buffer.from([0x00, 0x00, 0x00, 0x00])
const MESSAGE_CHOKE = Buffer.from([0x00, 0x00, 0x00, 0x01, 0x00])
const MESSAGE_UNCHOKE = Buffer.from([0x00, 0x00, 0x00, 0x01, 0x01])
const MESSAGE_INTERESTED = Buffer.from([0x00, 0x00, 0x00, 0x01, 0x02])
const MESSAGE_UNINTERESTED = Buffer.from([0x00, 0x00, 0x00, 0x01, 0x03])
const MESSAGE_RESERVED = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
const MESSAGE_PORT = [0x00, 0x00, 0x00, 0x03, 0x09, 0x00, 0x00]
class Request {
constructor (piece, offset, length, callback) {
this.piece = piece
this.offset = offset
this.length = length
this.callback = callback
}
}
class Wire extends stream.Duplex {
constructor () {
super()
this._debugId = randombytes(4).toString('hex')
this._debug('new wire')
this.peerId = null // remote peer id (hex string)
this.peerIdBuffer = null // remote peer id (buffer)
this.type = null // connection type ('webrtc', 'tcpIncoming', 'tcpOutgoing', 'webSeed')
this.amChoking = true // are we choking the peer?
this.amInterested = false // are we interested in the peer?
this.peerChoking = true // is the peer choking us?
this.peerInterested = false // is the peer interested in us?
// The largest torrent that I know of (the Geocities archive) is ~641 GB and has
// ~41,000 pieces. Therefore, cap bitfield to 10x larger (400,000 bits) to support all
// possible torrents but prevent malicious peers from growing bitfield to fill memory.
this.peerPieces = new BitField(0, { grow: BITFIELD_GROW })
this.peerExtensions = {}
this.requests = [] // outgoing
this.peerRequests = [] // incoming
this.extendedMapping = {} // number -> string, ex: 1 -> 'ut_metadata'
this.peerExtendedMapping = {} // string -> number, ex: 9 -> 'ut_metadata'
// The extended handshake to send, minus the "m" field, which gets automatically
// filled from `this.extendedMapping`
this.extendedHandshake = {}
this.peerExtendedHandshake = {} // remote peer's extended handshake
this._ext = {} // string -> function, ex 'ut_metadata' -> ut_metadata()
this._nextExt = 1
this.uploaded = 0
this.downloaded = 0
this.uploadSpeed = speedometer()
this.downloadSpeed = speedometer()
this._keepAliveInterval = null
this._timeout = null
this._timeoutMs = 0
this.destroyed = false // was the wire ended by calling `destroy`?
this._finished = false
this._parserSize = 0 // number of needed bytes to parse next message from remote peer
this._parser = null // function to call once `this._parserSize` bytes are available
this._buffer = [] // incomplete message data
this._bufferSize = 0 // cached total length of buffers in `this._buffer`
this.once('finish', () => this._onFinish())
this._parseHandshake()
}
/**
* Set whether to send a "keep-alive" ping (sent every 55s)
* @param {boolean} enable
*/
setKeepAlive (enable) {
this._debug('setKeepAlive %s', enable)
clearInterval(this._keepAliveInterval)
if (enable === false) return
this._keepAliveInterval = setInterval(() => {
this.keepAlive()
}, KEEP_ALIVE_TIMEOUT)
}
/**
* Set the amount of time to wait before considering a request to be "timed out"
* @param {number} ms
* @param {boolean=} unref (should the timer be unref'd? default: false)
*/
setTimeout (ms, unref) {
this._debug('setTimeout ms=%d unref=%s', ms, unref)
this._clearTimeout()
this._timeoutMs = ms
this._timeoutUnref = !!unref
this._updateTimeout()
}
destroy () {
if (this.destroyed) return
this.destroyed = true
this._debug('destroy')
this.emit('close')
this.end()
}
end (...args) {
this._debug('end')
this._onUninterested()
this._onChoke()
super.end(...args)
}
/**
* Use the specified protocol extension.
* @param {function} Extension
*/
use (Extension) {
const name = Extension.prototype.name
if (!name) {
throw new Error('Extension class requires a "name" property on the prototype')
}
this._debug('use extension.name=%s', name)
const ext = this._nextExt
const handler = new Extension(this)
function noop () {}
if (typeof handler.onHandshake !== 'function') {
handler.onHandshake = noop
}
if (typeof handler.onExtendedHandshake !== 'function') {
handler.onExtendedHandshake = noop
}
if (typeof handler.onMessage !== 'function') {
handler.onMessage = noop
}
this.extendedMapping[ext] = name
this._ext[name] = handler
this[name] = handler
this._nextExt += 1
}
//
// OUTGOING MESSAGES
//
/**
* Message "keep-alive": <len=0000>
*/
keepAlive () {
this._debug('keep-alive')
this._push(MESSAGE_KEEP_ALIVE)
}
/**
* Message: "handshake" <pstrlen><pstr><reserved><info_hash><peer_id>
* @param {Buffer|string} infoHash (as Buffer or *hex* string)
* @param {Buffer|string} peerId
* @param {Object} extensions
*/
handshake (infoHash, peerId, extensions) {
let infoHashBuffer
let peerIdBuffer
if (typeof infoHash === 'string') {
infoHash = infoHash.toLowerCase()
infoHashBuffer = Buffer.from(infoHash, 'hex')
} else {
infoHashBuffer = infoHash
infoHash = infoHashBuffer.toString('hex')
}
if (typeof peerId === 'string') {
peerIdBuffer = Buffer.from(peerId, 'hex')
} else {
peerIdBuffer = peerId
peerId = peerIdBuffer.toString('hex')
}
if (infoHashBuffer.length !== 20 || peerIdBuffer.length !== 20) {
throw new Error('infoHash and peerId MUST have length 20')
}
this._debug('handshake i=%s p=%s exts=%o', infoHash, peerId, extensions)
const reserved = Buffer.from(MESSAGE_RESERVED)
// enable extended message
reserved[5] |= 0x10
if (extensions && extensions.dht) reserved[7] |= 1
this._push(Buffer.concat([MESSAGE_PROTOCOL, reserved, infoHashBuffer, peerIdBuffer]))
this._handshakeSent = true
if (this.peerExtensions.extended && !this._extendedHandshakeSent) {
// Peer's handshake indicated support already
// (incoming connection)
this._sendExtendedHandshake()
}
}
/* Peer supports BEP-0010, send extended handshake.
*
* This comes after the 'handshake' event to give the user a chance to populate
* `this.extendedHandshake` and `this.extendedMapping` before the extended handshake
* is sent to the remote peer.
*/
_sendExtendedHandshake () {
// Create extended message object from registered extensions
const msg = Object.assign({}, this.extendedHandshake)
msg.m = {}
for (const ext in this.extendedMapping) {
const name = this.extendedMapping[ext]
msg.m[name] = Number(ext)
}
// Send extended handshake
this.extended(0, bencode.encode(msg))
this._extendedHandshakeSent = true
}
/**
* Message "choke": <len=0001><id=0>
*/
choke () {
if (this.amChoking) return
this.amChoking = true
this._debug('choke')
while (this.peerRequests.length) {
this.peerRequests.pop()
}
this._push(MESSAGE_CHOKE)
}
/**
* Message "unchoke": <len=0001><id=1>
*/
unchoke () {
if (!this.amChoking) return
this.amChoking = false
this._debug('unchoke')
this._push(MESSAGE_UNCHOKE)
}
/**
* Message "interested": <len=0001><id=2>
*/
interested () {
if (this.amInterested) return
this.amInterested = true
this._debug('interested')
this._push(MESSAGE_INTERESTED)
}
/**
* Message "uninterested": <len=0001><id=3>
*/
uninterested () {
if (!this.amInterested) return
this.amInterested = false
this._debug('uninterested')
this._push(MESSAGE_UNINTERESTED)
}
/**
* Message "have": <len=0005><id=4><piece index>
* @param {number} index
*/
have (index) {
this._debug('have %d', index)
this._message(4, [index], null)
}
/**
* Message "bitfield": <len=0001+X><id=5><bitfield>
* @param {BitField|Buffer} bitfield
*/
bitfield (bitfield) {
this._debug('bitfield')
if (!Buffer.isBuffer(bitfield)) bitfield = bitfield.buffer
this._message(5, [], bitfield)
}
/**
* Message "request": <len=0013><id=6><index><begin><length>
* @param {number} index
* @param {number} offset
* @param {number} length
* @param {function} cb
*/
request (index, offset, length, cb) {
if (!cb) cb = () => {}
if (this._finished) return cb(new Error('wire is closed'))
if (this.peerChoking) return cb(new Error('peer is choking'))
this._debug('request index=%d offset=%d length=%d', index, offset, length)
this.requests.push(new Request(index, offset, length, cb))
this._updateTimeout()
this._message(6, [index, offset, length], null)
}
/**
* Message "piece": <len=0009+X><id=7><index><begin><block>
* @param {number} index
* @param {number} offset
* @param {Buffer} buffer
*/
piece (index, offset, buffer) {
this._debug('piece index=%d offset=%d', index, offset)
this.uploaded += buffer.length
this.uploadSpeed(buffer.length)
this.emit('upload', buffer.length)
this._message(7, [index, offset], buffer)
}
/**
* Message "cancel": <len=0013><id=8><index><begin><length>
* @param {number} index
* @param {number} offset
* @param {number} length
*/
cancel (index, offset, length) {
this._debug('cancel index=%d offset=%d length=%d', index, offset, length)
this._callback(
this._pull(this.requests, index, offset, length),
new Error('request was cancelled'),
null
)
this._message(8, [index, offset, length], null)
}
/**
* Message: "port" <len=0003><id=9><listen-port>
* @param {Number} port
*/
port (port) {
this._debug('port %d', port)
const message = Buffer.from(MESSAGE_PORT)
message.writeUInt16BE(port, 5)
this._push(message)
}
/**
* Message: "extended" <len=0005+X><id=20><ext-number><payload>
* @param {number|string} ext
* @param {Object} obj
*/
extended (ext, obj) {
this._debug('extended ext=%s', ext)
if (typeof ext === 'string' && this.peerExtendedMapping[ext]) {
ext = this.peerExtendedMapping[ext]
}
if (typeof ext === 'number') {
const extId = Buffer.from([ext])
const buf = Buffer.isBuffer(obj) ? obj : bencode.encode(obj)
this._message(20, [], Buffer.concat([extId, buf]))
} else {
throw new Error(`Unrecognized extension: ${ext}`)
}
}
/**
* Duplex stream method. Called whenever the remote peer stream wants data. No-op
* since we'll just push data whenever we get it.
*/
_read () {}
/**
* Send a message to the remote peer.
*/
_message (id, numbers, data) {
const dataLength = data ? data.length : 0
const buffer = Buffer.allocUnsafe(5 + (4 * numbers.length))
buffer.writeUInt32BE(buffer.length + dataLength - 4, 0)
buffer[4] = id
for (let i = 0; i < numbers.length; i++) {
buffer.writeUInt32BE(numbers[i], 5 + (4 * i))
}
this._push(buffer)
if (data) this._push(data)
}
_push (data) {
if (this._finished) return
return this.push(data)
}
//
// INCOMING MESSAGES
//
_onKeepAlive () {
this._debug('got keep-alive')
this.emit('keep-alive')
}
_onHandshake (infoHashBuffer, peerIdBuffer, extensions) {
const infoHash = infoHashBuffer.toString('hex')
const peerId = peerIdBuffer.toString('hex')
this._debug('got handshake i=%s p=%s exts=%o', infoHash, peerId, extensions)
this.peerId = peerId
this.peerIdBuffer = peerIdBuffer
this.peerExtensions = extensions
this.emit('handshake', infoHash, peerId, extensions)
let name
for (name in this._ext) {
this._ext[name].onHandshake(infoHash, peerId, extensions)
}
if (extensions.extended && this._handshakeSent &&
!this._extendedHandshakeSent) {
// outgoing connection
this._sendExtendedHandshake()
}
}
_onChoke () {
this.peerChoking = true
this._debug('got choke')
this.emit('choke')
while (this.requests.length) {
this._callback(this.requests.pop(), new Error('peer is choking'), null)
}
}
_onUnchoke () {
this.peerChoking = false
this._debug('got unchoke')
this.emit('unchoke')
}
_onInterested () {
this.peerInterested = true
this._debug('got interested')
this.emit('interested')
}
_onUninterested () {
this.peerInterested = false
this._debug('got uninterested')
this.emit('uninterested')
}
_onHave (index) {
if (this.peerPieces.get(index)) return
this._debug('got have %d', index)
this.peerPieces.set(index, true)
this.emit('have', index)
}
_onBitField (buffer) {
this.peerPieces = new BitField(buffer)
this._debug('got bitfield')
this.emit('bitfield', this.peerPieces)
}
_onRequest (index, offset, length) {
if (this.amChoking) return
this._debug('got request index=%d offset=%d length=%d', index, offset, length)
const respond = (err, buffer) => {
if (request !== this._pull(this.peerRequests, index, offset, length)) return
if (err) return this._debug('error satisfying request index=%d offset=%d length=%d (%s)', index, offset, length, err.message)
this.piece(index, offset, buffer)
}
const request = new Request(index, offset, length, respond)
this.peerRequests.push(request)
this.emit('request', index, offset, length, respond)
}
_onPiece (index, offset, buffer) {
this._debug('got piece index=%d offset=%d', index, offset)
this._callback(this._pull(this.requests, index, offset, buffer.length), null, buffer)
this.downloaded += buffer.length
this.downloadSpeed(buffer.length)
this.emit('download', buffer.length)
this.emit('piece', index, offset, buffer)
}
_onCancel (index, offset, length) {
this._debug('got cancel index=%d offset=%d length=%d', index, offset, length)
this._pull(this.peerRequests, index, offset, length)
this.emit('cancel', index, offset, length)
}
_onPort (port) {
this._debug('got port %d', port)
this.emit('port', port)
}
_onExtended (ext, buf) {
if (ext === 0) {
let info
try {
info = bencode.decode(buf)
} catch (err) {
this._debug('ignoring invalid extended handshake: %s', err.message || err)
}
if (!info) return
this.peerExtendedHandshake = info
let name
if (typeof info.m === 'object') {
for (name in info.m) {
this.peerExtendedMapping[name] = Number(info.m[name].toString())
}
}
for (name in this._ext) {
if (this.peerExtendedMapping[name]) {
this._ext[name].onExtendedHandshake(this.peerExtendedHandshake)
}
}
this._debug('got extended handshake')
this.emit('extended', 'handshake', this.peerExtendedHandshake)
} else {
if (this.extendedMapping[ext]) {
ext = this.extendedMapping[ext] // friendly name for extension
if (this._ext[ext]) {
// there is an registered extension handler, so call it
this._ext[ext].onMessage(buf)
}
}
this._debug('got extended message ext=%s', ext)
this.emit('extended', ext, buf)
}
}
_onTimeout () {
this._debug('request timed out')
this._callback(this.requests.shift(), new Error('request has timed out'), null)
this.emit('timeout')
}
/**
* Duplex stream method. Called whenever the remote peer has data for us. Data that the
* remote peer sends gets buffered (i.e. not actually processed) until the right number
* of bytes have arrived, determined by the last call to `this._parse(number, callback)`.
* Once enough bytes have arrived to process the message, the callback function
* (i.e. `this._parser`) gets called with the full buffer of data.
* @param {Buffer} data
* @param {string} encoding
* @param {function} cb
*/
_write (data, encoding, cb) {
this._bufferSize += data.length
this._buffer.push(data)
while (this._bufferSize >= this._parserSize) {
const buffer = (this._buffer.length === 1)
? this._buffer[0]
: Buffer.concat(this._buffer)
this._bufferSize -= this._parserSize
this._buffer = this._bufferSize
? [buffer.slice(this._parserSize)]
: []
this._parser(buffer.slice(0, this._parserSize))
}
cb(null) // Signal that we're ready for more data
}
_callback (request, err, buffer) {
if (!request) return
this._clearTimeout()
if (!this.peerChoking && !this._finished) this._updateTimeout()
request.callback(err, buffer)
}
_clearTimeout () {
if (!this._timeout) return
clearTimeout(this._timeout)
this._timeout = null
}
_updateTimeout () {
if (!this._timeoutMs || !this.requests.length || this._timeout) return
this._timeout = setTimeout(() => this._onTimeout(), this._timeoutMs)
if (this._timeoutUnref && this._timeout.unref) this._timeout.unref()
}
/**
* Takes a number of bytes that the local peer is waiting to receive from the remote peer
* in order to parse a complete message, and a callback function to be called once enough
* bytes have arrived.
* @param {number} size
* @param {function} parser
*/
_parse (size, parser) {
this._parserSize = size
this._parser = parser
}
/**
* Handle the first 4 bytes of a message, to determine the length of bytes that must be
* waited for in order to have the whole message.
* @param {Buffer} buffer
*/
_onMessageLength (buffer) {
const length = buffer.readUInt32BE(0)
if (length > 0) {
this._parse(length, this._onMessage)
} else {
this._onKeepAlive()
this._parse(4, this._onMessageLength)
}
}
/**
* Handle a message from the remote peer.
* @param {Buffer} buffer
*/
_onMessage (buffer) {
this._parse(4, this._onMessageLength)
switch (buffer[0]) {
case 0:
return this._onChoke()
case 1:
return this._onUnchoke()
case 2:
return this._onInterested()
case 3:
return this._onUninterested()
case 4:
return this._onHave(buffer.readUInt32BE(1))
case 5:
return this._onBitField(buffer.slice(1))
case 6:
return this._onRequest(
buffer.readUInt32BE(1),
buffer.readUInt32BE(5),
buffer.readUInt32BE(9)
)
case 7:
return this._onPiece(
buffer.readUInt32BE(1),
buffer.readUInt32BE(5),
buffer.slice(9)
)
case 8:
return this._onCancel(
buffer.readUInt32BE(1),
buffer.readUInt32BE(5),
buffer.readUInt32BE(9)
)
case 9:
return this._onPort(buffer.readUInt16BE(1))
case 20:
return this._onExtended(buffer.readUInt8(1), buffer.slice(2))
default:
this._debug('got unknown message')
return this.emit('unknownmessage', buffer)
}
}
_parseHandshake () {
this._parse(1, buffer => {
const pstrlen = buffer.readUInt8(0)
this._parse(pstrlen + 48, handshake => {
const protocol = handshake.slice(0, pstrlen)
if (protocol.toString() !== 'BitTorrent protocol') {
this._debug('Error: wire not speaking BitTorrent protocol (%s)', protocol.toString())
this.end()
return
}
handshake = handshake.slice(pstrlen)
this._onHandshake(handshake.slice(8, 28), handshake.slice(28, 48), {
dht: !!(handshake[7] & 0x01), // see bep_0005
extended: !!(handshake[5] & 0x10) // see bep_0010
})
this._parse(4, this._onMessageLength)
})
})
}
_onFinish () {
this._finished = true
this.push(null) // stream cannot be half open, so signal the end of it
while (this.read()) {
// body intentionally empty
// consume and discard the rest of the stream data
}
clearInterval(this._keepAliveInterval)
this._parse(Number.MAX_VALUE, () => {})
while (this.peerRequests.length) {
this.peerRequests.pop()
}
while (this.requests.length) {
this._callback(this.requests.pop(), new Error('wire was closed'), null)
}
}
_debug (...args) {
args[0] = `[${this._debugId}] ${args[0]}`
debug(...args)
}
_pull (requests, piece, offset, length) {
for (let i = 0; i < requests.length; i++) {
const req = requests[i]
if (req.piece === piece && req.offset === offset && req.length === length) {
arrayRemove(requests, i)
return req
}
}
return null
}
}
module.exports = Wire
}).call(this)}).call(this,require("buffer").Buffer)
},{"bencode":7,"bitfield":12,"buffer":60,"debug":13,"randombytes":195,"readable-stream":30,"speedometer":263,"unordered-array-remove":298}],12:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function getByteSize(num) {
var out = num >> 3;
if (num % 8 !== 0)
out++;
return out;
}
var BitField = /** @class */ (function () {
/**
*
*
* @param data Either a number representing the maximum number of supported bytes, or a Uint8Array.
* @param opts Options for the bitfield.
*/
function BitField(data, opts) {
if (data === void 0) { data = 0; }
var grow = opts === null || opts === void 0 ? void 0 : opts.grow;
this.grow = (grow && isFinite(grow) && getByteSize(grow)) || grow || 0;
this.buffer =
typeof data === "number" ? new Uint8Array(getByteSize(data)) : data;
}
/**
* Get a particular bit.
*
* @param i Bit index to retrieve.
* @returns A boolean indicating whether the `i`th bit is set.
*/
BitField.prototype.get = function (i) {
var j = i >> 3;
return j < this.buffer.length && !!(this.buffer[j] & (128 >> i % 8));
};
/**
* Set a particular bit.
*
* Will grow the underlying array if the bit is out of bounds and the `grow` option is set.
*
* @param i Bit index to set.
* @param value Value to set the bit to. Defaults to `true`.
*/
BitField.prototype.set = function (i, value) {
if (value === void 0) { value = true; }
var j = i >> 3;
if (value) {
if (this.buffer.length < j + 1) {
var length_1 = Math.max(j + 1, Math.min(2 * this.buffer.length, this.grow));
if (length_1 <= this.grow) {
var newBuffer = new Uint8Array(length_1);
newBuffer.set(this.buffer);
this.buffer = newBuffer;
}
}
// Set
this.buffer[j] |= 128 >> i % 8;
}
else if (j < this.buffer.length) {
// Clear
this.buffer[j] &= ~(128 >> i % 8);
}
};
/**
* Loop through the bits in the bitfield.
*
* @param fn Function to be called with the bit value and index.
* @param start Index of the first bit to look at.
* @param end Index of the first bit that should no longer be considered.
*/
BitField.prototype.forEach = function (fn, start, end) {
if (start === void 0) { start = 0; }
if (end === void 0) { end = this.buffer.length * 8; }
for (var i = start, j = i >> 3, y = 128 >> i % 8, byte = this.buffer[j]; i < end; i++) {
fn(!!(byte & y), i);
y = y === 1 ? ((byte = this.buffer[++j]), 128) : y >> 1;
}
};
return BitField;
}());
exports.default = BitField;
},{}],13:[function(require,module,exports){
(function (process){(function (){
/* eslint-env browser */
/**
* This is the web browser implementation of `debug()`.
*/
exports.formatArgs = formatArgs;
exports.save = save;
exports.load = load;
exports.useColors = useColors;
exports.storage = localstorage();
/**
* Colors.
*/
exports.colors = [
'#0000CC',
'#0000FF',
'#0033CC',
'#0033FF',
'#0066CC',
'#0066FF',
'#0099CC',
'#0099FF',
'#00CC00',
'#00CC33',
'#00CC66',
'#00CC99',
'#00CCCC',
'#00CCFF',
'#3300CC',
'#3300FF',
'#3333CC',
'#3333FF',
'#3366CC',
'#3366FF',
'#3399CC',
'#3399FF',
'#33CC00',
'#33CC33',
'#33CC66',
'#33CC99',
'#33CCCC',
'#33CCFF',
'#6600CC',
'#6600FF',
'#6633CC',
'#6633FF',
'#66CC00',
'#66CC33',
'#9900CC',
'#9900FF',
'#9933CC',
'#9933FF',
'#99CC00',
'#99CC33',
'#CC0000',
'#CC0033',
'#CC0066',
'#CC0099',
'#CC00CC',
'#CC00FF',
'#CC3300',
'#CC3333',
'#CC3366',
'#CC3399',
'#CC33CC',
'#CC33FF',
'#CC6600',
'#CC6633',
'#CC9900',
'#CC9933',
'#CCCC00',
'#CCCC33',
'#FF0000',
'#FF0033',
'#FF0066',
'#FF0099',
'#FF00CC',
'#FF00FF',
'#FF3300',
'#FF3333',
'#FF3366',
'#FF3399',
'#FF33CC',
'#FF33FF',
'#FF6600',
'#FF6633',
'#FF9900',
'#FF9933',
'#FFCC00',
'#FFCC33'
];
/**
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
* and the Firebug extension (any Firefox version) are known
* to support "%c" CSS customizations.
*
* TODO: add a `localStorage` variable to explicitly enable/disable colors
*/
// eslint-disable-next-line complexity
function useColors() {
// NB: In an Electron preload script, document will be defined but not fully
// initialized. Since we know we're in Chrome, we'll just detect this case
// explicitly
if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
return true;
}
// Internet Explorer and Edge do not support colors.
if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
return false;
}
// Is webkit? http://stackoverflow.com/a/16459606/376773
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
// Is firebug? http://stackoverflow.com/a/398120/376773
(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
// Is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
// Double check webkit in userAgent just in case we are in a worker
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
}
/**
* Colorize log arguments if enabled.
*
* @api public
*/
function formatArgs(args) {
args[0] = (this.useColors ? '%c' : '') +
this.namespace +
(this.useColors ? ' %c' : ' ') +
args[0] +
(this.useColors ? '%c ' : ' ') +
'+' + module.exports.humanize(this.diff);
if (!this.useColors) {
return;
}
const c = 'color: ' + this.color;
args.splice(1, 0, c, 'color: inherit');
// The final "%c" is somewhat tricky, because there could be other
// arguments passed either before or after the %c, so we need to
// figure out the correct index to insert the CSS into
let index = 0;
let lastC = 0;
args[0].replace(/%[a-zA-Z%]/g, match => {
if (match === '%%') {
return;
}
index++;
if (match === '%c') {
// We only are interested in the *last* %c
// (the user may have provided their own)
lastC = index;
}
});
args.splice(lastC, 0, c);
}
/**
* Invokes `console.debug()` when available.
* No-op when `console.debug` is not a "function".
* If `console.debug` is not available, falls back
* to `console.log`.
*
* @api public
*/
exports.log = console.debug || console.log || (() => {});
/**
* Save `namespaces`.
*
* @param {String} namespaces
* @api private
*/
function save(namespaces) {
try {
if (namespaces) {
exports.storage.setItem('debug', namespaces);
} else {
exports.storage.removeItem('debug');
}
} catch (error) {
// Swallow
// XXX (@Qix-) should we be logging these?
}
}
/**
* Load `namespaces`.
*
* @return {String} returns the previously persisted debug modes
* @api private
*/
function load() {
let r;
try {
r = exports.storage.getItem('debug');
} catch (error) {
// Swallow
// XXX (@Qix-) should we be logging these?
}
// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
if (!r && typeof process !== 'undefined' && 'env' in process) {
r = process.env.DEBUG;
}
return r;
}
/**
* Localstorage attempts to return the localstorage.
*
* This is necessary because safari throws
* when a user disables cookies/localstorage
* and you attempt to access it.
*
* @return {LocalStorage}
* @api private
*/
function localstorage() {
try {
// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
// The Browser also has localStorage in the global context.
return localStorage;
} catch (error) {
// Swallow
// XXX (@Qix-) should we be logging these?
}
}
module.exports = require('./common')(exports);
const {formatters} = module.exports;
/**
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
*/
formatters.j = function (v) {
try {
return JSON.stringify(v);
} catch (error) {
return '[UnexpectedJSONParseError]: ' + error.message;
}
};
}).call(this)}).call(this,require('_process'))
},{"./common":14,"_process":187}],14:[function(require,module,exports){
/**
* This is the common logic for both the Node.js and web browser
* implementations of `debug()`.
*/
function setup(env) {
createDebug.debug = createDebug;
createDebug.default = createDebug;
createDebug.coerce = coerce;
createDebug.disable = disable;
createDebug.enable = enable;
createDebug.enabled = enabled;
createDebug.humanize = require('ms');
Object.keys(env).forEach(key => {
createDebug[key] = env[key];
});
/**
* Active `debug` instances.
*/
createDebug.instances = [];
/**
* The currently active debug mode names, and names to skip.
*/
createDebug.names = [];
createDebug.skips = [];
/**
* Map of special "%n" handling functions, for the debug "format" argument.
*
* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
*/
createDebug.formatters = {};
/**
* Selects a color for a debug namespace
* @param {String} namespace The namespace string for the for the debug instance to be colored
* @return {Number|String} An ANSI color code for the given namespace
* @api private
*/
function selectColor(namespace) {
let hash = 0;
for (let i = 0; i < namespace.length; i++) {
hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
hash |= 0; // Convert to 32bit integer
}
return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
}
createDebug.selectColor = selectColor;
/**
* Create a debugger with the given `namespace`.
*
* @param {String} namespace
* @return {Function}
* @api public
*/
function createDebug(namespace) {
let prevTime;
function debug(...args) {
// Disabled?
if (!debug.enabled) {
return;
}
const self = debug;
// Set `diff` timestamp
const curr = Number(new Date());
const ms = curr - (prevTime || curr);
self.diff = ms;
self.prev = prevTime;
self.curr = curr;
prevTime = curr;
args[0] = createDebug.coerce(args[0]);
if (typeof args[0] !== 'string') {
// Anything else let's inspect with %O
args.unshift('%O');
}
// Apply any `formatters` transformations
let index = 0;
args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
// If we encounter an escaped % then don't increase the array index
if (match === '%%') {
return match;
}
index++;
const formatter = createDebug.formatters[format];
if (typeof formatter === 'function') {
const val = args[index];
match = formatter.call(self, val);
// Now we need to remove `args[index]` since it's inlined in the `format`
args.splice(index, 1);
index--;
}
return match;
});
// Apply env-specific formatting (colors, etc.)
createDebug.formatArgs.call(self, args);
const logFn = self.log || createDebug.log;
logFn.apply(self, args);
}
debug.namespace = namespace;
debug.enabled = createDebug.enabled(namespace);
debug.useColors = createDebug.useColors();
debug.color = createDebug.selectColor(namespace);
debug.destroy = destroy;
debug.extend = extend;
// Env-specific initialization logic for debug instances
if (typeof createDebug.init === 'function') {
createDebug.init(debug);
}
createDebug.instances.push(debug);
return debug;
}
function destroy() {
const index = createDebug.instances.indexOf(this);
if (index !== -1) {
createDebug.instances.splice(index, 1);
return true;
}
return false;
}
function extend(namespace, delimiter) {
const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
newDebug.log = this.log;
return newDebug;
}
/**
* Enables a debug mode by namespaces. This can include modes
* separated by a colon and wildcards.
*
* @param {String} namespaces
* @api public
*/
function enable(namespaces) {
createDebug.save(namespaces);
createDebug.names = [];
createDebug.skips = [];
let i;
const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
const len = split.length;
for (i = 0; i < len; i++) {
if (!split[i]) {
// ignore empty strings
continue;
}
namespaces = split[i].replace(/\*/g, '.*?');
if (namespaces[0] === '-') {
createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
} else {
createDebug.names.push(new RegExp('^' + namespaces + '$'));
}
}
for (i = 0; i < createDebug.instances.length; i++) {
const instance = createDebug.instances[i];
instance.enabled = createDebug.enabled(instance.namespace);
}
}
/**
* Disable debug output.
*
* @return {String} namespaces
* @api public
*/
function disable() {
const namespaces = [
...createDebug.names.map(toNamespace),
...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)
].join(',');
createDebug.enable('');
return namespaces;
}
/**
* Returns true if the given mode name is enabled, false otherwise.
*
* @param {String} name
* @return {Boolean}
* @api public
*/
function enabled(name) {
if (name[name.length - 1] === '*') {
return true;
}
let i;
let len;
for (i = 0, len = createDebug.skips.length; i < len; i++) {
if (createDebug.skips[i].test(name)) {
return false;
}
}
for (i = 0, len = createDebug.names.length; i < len; i++) {
if (createDebug.names[i].test(name)) {
return true;
}
}
return false;
}
/**
* Convert regexp to namespace
*
* @param {RegExp} regxep
* @return {String} namespace
* @api private
*/
function toNamespace(regexp) {
return regexp.toString()
.substring(2, regexp.toString().length - 2)
.replace(/\.\*\?$/, '*');
}
/**
* Coerce `val`.
*
* @param {Mixed} val
* @return {Mixed}
* @api private
*/
function coerce(val) {
if (val instanceof Error) {
return val.stack || val.message;
}
return val;
}
createDebug.enable(createDebug.load());
return createDebug;
}
module.exports = setup;
},{"ms":15}],15:[function(require,module,exports){
/**
* Helpers.
*/
var s = 1000;
var m = s * 60;
var h = m * 60;
var d = h * 24;
var w = d * 7;
var y = d * 365.25;
/**
* Parse or format the given `val`.
*
* Options:
*
* - `long` verbose formatting [false]
*
* @param {String|Number} val
* @param {Object} [options]
* @throws {Error} throw an error if val is not a non-empty string or a number
* @return {String|Number}
* @api public
*/
module.exports = function(val, options) {
options = options || {};
var type = typeof val;
if (type === 'string' && val.length > 0) {
return parse(val);
} else if (type === 'number' && isFinite(val)) {
return options.long ? fmtLong(val) : fmtShort(val);
}
throw new Error(
'val is not a non-empty string or a valid number. val=' +
JSON.stringify(val)
);
};
/**
* Parse the given `str` and return milliseconds.
*
* @param {String} str
* @return {Number}
* @api private
*/
function parse(str) {
str = String(str);
if (str.length > 100) {
return;
}
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
str
);
if (!match) {
return;
}
var n = parseFloat(match[1]);
var type = (match[2] || 'ms').toLowerCase();
switch (type) {
case 'years':
case 'year':
case 'yrs':
case 'yr':
case 'y':
return n * y;
case 'weeks':
case 'week':
case 'w':
return n * w;
case 'days':
case 'day':
case 'd':
return n * d;
case 'hours':
case 'hour':
case 'hrs':
case 'hr':
case 'h':
return n * h;
case 'minutes':
case 'minute':
case 'mins':
case 'min':
case 'm':
return n * m;
case 'seconds':
case 'second':
case 'secs':
case 'sec':
case 's':
return n * s;
case 'milliseconds':
case 'millisecond':
case 'msecs':
case 'msec':
case 'ms':
return n;
default:
return undefined;
}
}
/**
* Short format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function fmtShort(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return Math.round(ms / d) + 'd';
}
if (msAbs >= h) {
return Math.round(ms / h) + 'h';
}
if (msAbs >= m) {
return Math.round(ms / m) + 'm';
}
if (msAbs >= s) {
return Math.round(ms / s) + 's';
}
return ms + 'ms';
}
/**
* Long format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function fmtLong(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return plural(ms, msAbs, d, 'day');
}
if (msAbs >= h) {
return plural(ms, msAbs, h, 'hour');
}
if (msAbs >= m) {
return plural(ms, msAbs, m, 'minute');
}
if (msAbs >= s) {
return plural(ms, msAbs, s, 'second');
}
return ms + ' ms';
}
/**
* Pluralization helper.
*/
function plural(ms, msAbs, n, name) {
var isPlural = msAbs >= n * 1.5;
return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
}
},{}],16:[function(require,module,exports){
'use strict';
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
var codes = {};
function createErrorType(code, message, Base) {
if (!Base) {
Base = Error;
}
function getMessage(arg1, arg2, arg3) {
if (typeof message === 'string') {
return message;
} else {
return message(arg1, arg2, arg3);
}
}
var NodeError =
/*#__PURE__*/
function (_Base) {
_inheritsLoose(NodeError, _Base);
function NodeError(arg1, arg2, arg3) {
return _Base.call(this, getMessage(arg1, arg2, arg3)) || this;
}
return NodeError;
}(Base);
NodeError.prototype.name = Base.name;
NodeError.prototype.code = code;
codes[code] = NodeError;
} // https://github.com/nodejs/node/blob/v10.8.0/lib/internal/errors.js
function oneOf(expected, thing) {
if (Array.isArray(expected)) {
var len = expected.length;
expected = expected.map(function (i) {
return String(i);
});
if (len > 2) {
return "one of ".concat(thing, " ").concat(expected.slice(0, len - 1).join(', '), ", or ") + expected[len - 1];
} else if (len === 2) {
return "one of ".concat(thing, " ").concat(expected[0], " or ").concat(expected[1]);
} else {
return "of ".concat(thing, " ").concat(expected[0]);
}
} else {
return "of ".concat(thing, " ").concat(String(expected));
}
} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
function startsWith(str, search, pos) {
return str.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
function endsWith(str, search, this_len) {
if (this_len === undefined || this_len > str.length) {
this_len = str.length;
}
return str.substring(this_len - search.length, this_len) === search;
} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes
function includes(str, search, start) {
if (typeof start !== 'number') {
start = 0;
}
if (start + search.length > str.length) {
return false;
} else {
return str.indexOf(search, start) !== -1;
}
}
createErrorType('ERR_INVALID_OPT_VALUE', function (name, value) {
return 'The value "' + value + '" is invalid for option "' + name + '"';
}, TypeError);
createErrorType('ERR_INVALID_ARG_TYPE', function (name, expected, actual) {
// determiner: 'must be' or 'must not be'
var determiner;
if (typeof expected === 'string' && startsWith(expected, 'not ')) {
determiner = 'must not be';
expected = expected.replace(/^not /, '');
} else {
determiner = 'must be';
}
var msg;
if (endsWith(name, ' argument')) {
// For cases like 'first argument'
msg = "The ".concat(name, " ").concat(determiner, " ").concat(oneOf(expected, 'type'));
} else {
var type = includes(name, '.') ? 'property' : 'argument';
msg = "The \"".concat(name, "\" ").concat(type, " ").concat(determiner, " ").concat(oneOf(expected, 'type'));
}
msg += ". Received type ".concat(typeof actual);
return msg;
}, TypeError);
createErrorType('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF');
createErrorType('ERR_METHOD_NOT_IMPLEMENTED', function (name) {
return 'The ' + name + ' method is not implemented';
});
createErrorType('ERR_STREAM_PREMATURE_CLOSE', 'Premature close');
createErrorType('ERR_STREAM_DESTROYED', function (name) {
return 'Cannot call ' + name + ' after a stream was destroyed';
});
createErrorType('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times');
createErrorType('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable');
createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end');
createErrorType('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError);
createErrorType('ERR_UNKNOWN_ENCODING', function (arg) {
return 'Unknown encoding: ' + arg;
}, TypeError);
createErrorType('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event');
module.exports.codes = codes;
},{}],17:[function(require,module,exports){
(function (process){(function (){
// 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 objectKeys = Object.keys || function (obj) {
var keys = [];
for (var key in obj) {
keys.push(key);
}
return keys;
};
/*</replacement>*/
module.exports = Duplex;
var Readable = require('./_stream_readable');
var Writable = require('./_stream_writable');
require('inherits')(Duplex, Readable);
{
// Allow the keys array to be GC'ed.
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);
this.allowHalfOpen = true;
if (options) {
if (options.readable === false) this.readable = false;
if (options.writable === false) this.writable = false;
if (options.allowHalfOpen === false) {
this.allowHalfOpen = false;
this.once('end', onend);
}
}
}
Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
return this._writableState.highWaterMark;
}
});
Object.defineProperty(Duplex.prototype, 'writableBuffer', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
return this._writableState && this._writableState.getBuffer();
}
});
Object.defineProperty(Duplex.prototype, 'writableLength', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
return this._writableState.length;
}
}); // the no-half-open enforcer
function onend() {
// If the writable side ended, then we're ok.
if (this._writableState.ended) return; // no more data can be written.
// But allow more writes to happen in this tick.
process.nextTick(onEndNT, this);
}
function onEndNT(self) {
self.end();
}
Object.defineProperty(Duplex.prototype, 'destroyed', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
if (this._readableState === undefined || this._writableState === undefined) {
return false;
}
return this._readableState.destroyed && this._writableState.destroyed;
},
set: function set(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;
}
});
}).call(this)}).call(this,require('_process'))
},{"./_stream_readable":19,"./_stream_writable":21,"_process":187,"inherits":119}],18:[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');
require('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":20,"inherits":119}],19:[function(require,module,exports){
(function (process,global){(function (){
// 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';
module.exports = Readable;
/*<replacement>*/
var Duplex;
/*</replacement>*/
Readable.ReadableState = ReadableState;
/*<replacement>*/
var EE = require('events').EventEmitter;
var EElistenerCount = function EElistenerCount(emitter, type) {
return emitter.listeners(type).length;
};
/*</replacement>*/
/*<replacement>*/
var Stream = require('./internal/streams/stream');
/*</replacement>*/
var Buffer = require('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 debugUtil = require('util');
var debug;
if (debugUtil && debugUtil.debuglog) {
debug = debugUtil.debuglog('stream');
} else {
debug = function debug() {};
}
/*</replacement>*/
var BufferList = require('./internal/streams/buffer_list');
var destroyImpl = require('./internal/streams/destroy');
var _require = require('./internal/streams/state'),
getHighWaterMark = _require.getHighWaterMark;
var _require$codes = require('../errors').codes,
ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE,
ERR_STREAM_PUSH_AFTER_EOF = _require$codes.ERR_STREAM_PUSH_AFTER_EOF,
ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,
ERR_STREAM_UNSHIFT_AFTER_END_EVENT = _require$codes.ERR_STREAM_UNSHIFT_AFTER_END_EVENT; // Lazy loaded to improve the startup performance.
var StringDecoder;
var createReadableStreamAsyncIterator;
var from;
require('inherits')(Readable, Stream);
var errorOrDestroy = destroyImpl.errorOrDestroy;
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); // 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 (Array.isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];
}
function ReadableState(options, stream, isDuplex) {
Duplex = Duplex || require('./_stream_duplex');
options = options || {}; // Duplex streams are both readable and writable, but share
// the same options object.
// However, some cases require setting options to different
// values for the readable and the writable sides of the duplex stream.
// These options can be provided separately as readableXXX and writableXXX.
if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // 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 (isDuplex) 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"
this.highWaterMark = getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex); // 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;
this.paused = true; // Should close be emitted on destroy. Defaults to true.
this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'end' (and potentially 'finish')
this.autoDestroy = !!options.autoDestroy; // 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); // Checking for a Stream.Duplex instance is faster here instead of inside
// the ReadableState constructor, at least with V8 6.5
var isDuplex = this instanceof Duplex;
this._readableState = new ReadableState(options, this, isDuplex); // 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', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
if (this._readableState === undefined) {
return false;
}
return this._readableState.destroyed;
},
set: function set(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) {
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) {
debug('readableAddChunk', chunk);
var state = stream._readableState;
if (chunk === null) {
state.reading = false;
onEofChunk(stream, state);
} else {
var er;
if (!skipChunkCheck) er = chunkInvalid(state, chunk);
if (er) {
errorOrDestroy(stream, 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) errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT());else addChunk(stream, state, chunk, true);
} else if (state.ended) {
errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF());
} else if (state.destroyed) {
return false;
} 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;
maybeReadMore(stream, state);
}
} // We can push more data if we are below the highWaterMark.
// 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.
return !state.ended && (state.length < state.highWaterMark || state.length === 0);
}
function addChunk(stream, state, chunk, addToFront) {
if (state.flowing && state.length === 0 && !state.sync) {
state.awaitDrain = 0;
stream.emit('data', chunk);
} 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 ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer', 'Uint8Array'], chunk);
}
return er;
}
Readable.prototype.isPaused = function () {
return this._readableState.flowing === false;
}; // backwards compatibility.
Readable.prototype.setEncoding = function (enc) {
if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;
var decoder = new StringDecoder(enc);
this._readableState.decoder = decoder; // If setEncoding(null), decoder.encoding equals utf8
this._readableState.encoding = this._readableState.decoder.encoding; // Iterate over current buffer to convert already stored Buffers:
var p = this._readableState.buffer.head;
var content = '';
while (p !== null) {
content += decoder.write(p.data);
p = p.next;
}
this._readableState.buffer.clear();
if (content !== '') this._readableState.buffer.push(content);
this._readableState.length = content.length;
return this;
}; // Don't raise the hwm > 1GB
var MAX_HWM = 0x40000000;
function computeNewHighWaterMark(n) {
if (n >= MAX_HWM) {
// TODO(ronag): Throw ERR_VALUE_OUT_OF_RANGE.
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.highWaterMark !== 0 ? state.length >= state.highWaterMark : state.length > 0) || 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 = state.length <= state.highWaterMark;
n = 0;
} else {
state.length -= n;
state.awaitDrain = 0;
}
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) {
debug('onEofChunk');
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;
if (state.sync) {
// if we are sync, wait until next tick to emit the data.
// Otherwise we risk emitting data in the flow()
// the readable code triggers during a read() call
emitReadable(stream);
} else {
// emit 'readable' now to make sure it gets picked up.
state.needReadable = false;
if (!state.emittedReadable) {
state.emittedReadable = true;
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;
debug('emitReadable', state.needReadable, state.emittedReadable);
state.needReadable = false;
if (!state.emittedReadable) {
debug('emitReadable', state.flowing);
state.emittedReadable = true;
process.nextTick(emitReadable_, stream);
}
}
function emitReadable_(stream) {
var state = stream._readableState;
debug('emitReadable_', state.destroyed, state.length, state.ended);
if (!state.destroyed && (state.length || state.ended)) {
stream.emit('readable');
state.emittedReadable = false;
} // The stream needs another readable event if
// 1. It is not flowing, as the flow mechanism will take
// care of it.
// 2. It is not ended.
// 3. It is below the highWaterMark, so we can schedule
// another readable later.
state.needReadable = !state.flowing && !state.ended && state.length <= state.highWaterMark;
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;
process.nextTick(maybeReadMore_, stream, state);
}
}
function maybeReadMore_(stream, state) {
// Attempt to read more data if we should.
//
// The conditions for reading more data are (one of):
// - Not enough data buffered (state.length < state.highWaterMark). The loop
// is responsible for filling the buffer with enough data if such data
// is available. If highWaterMark is 0 and we are not in the flowing mode
// we should _not_ attempt to buffer any extra data. We'll get more data
// when the stream consumer calls read() instead.
// - No data in the buffer, and the stream is in flowing mode. In this mode
// the loop below is responsible for ensuring read() is called. Failing to
// call read here would abort the flow and there's no other mechanism for
// continuing the flow if the stream consumer has just subscribed to the
// 'data' event.
//
// In addition to the above conditions to keep reading data, the following
// conditions prevent the data from being read:
// - The stream has ended (state.ended).
// - There is already a pending 'read' operation (state.reading). This is a
// case where the the stream has called the implementation defined _read()
// method, but they are processing the call asynchronously and have _not_
// called push() with new data. In this case we skip performing more
// read()s. The execution ends in this method again after the _read() ends
// up calling push() with more data.
while (!state.reading && !state.ended && (state.length < state.highWaterMark || state.flowing && state.length === 0)) {
var len = state.length;
debug('maybeReadMore read 0');
stream.read(0);
if (len === state.length) // didn't get any data, stop spinning.
break;
}
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) {
errorOrDestroy(this, new ERR_METHOD_NOT_IMPLEMENTED('_read()'));
};
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) process.nextTick(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();
}
src.on('data', ondata);
function ondata(chunk) {
debug('ondata');
var ret = dest.write(chunk);
debug('dest.write', ret);
if (ret === false) {
// 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', state.awaitDrain);
state.awaitDrain++;
}
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) errorOrDestroy(dest, 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 pipeOnDrainFunctionResult() {
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, {
hasUnpiped: false
});
}
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);
var state = this._readableState;
if (ev === 'data') {
// update readableListening so that resume() may be a no-op
// a few lines down. This is needed to support once('readable').
state.readableListening = this.listenerCount('readable') > 0; // Try start flowing on next tick if stream isn't explicitly paused
if (state.flowing !== false) this.resume();
} else if (ev === 'readable') {
if (!state.endEmitted && !state.readableListening) {
state.readableListening = state.needReadable = true;
state.flowing = false;
state.emittedReadable = false;
debug('on readable', state.length, state.reading);
if (state.length) {
emitReadable(this);
} else if (!state.reading) {
process.nextTick(nReadingNextTick, this);
}
}
}
return res;
};
Readable.prototype.addListener = Readable.prototype.on;
Readable.prototype.removeListener = function (ev, fn) {
var res = Stream.prototype.removeListener.call(this, ev, fn);
if (ev === 'readable') {
// We need to check if there is someone still listening to
// readable and reset the state. However this needs to happen
// after readable has been emitted but before I/O (nextTick) to
// support once('readable', fn) cycles. This means that calling
// resume within the same tick will have no
// effect.
process.nextTick(updateReadableListening, this);
}
return res;
};
Readable.prototype.removeAllListeners = function (ev) {
var res = Stream.prototype.removeAllListeners.apply(this, arguments);
if (ev === 'readable' || ev === undefined) {
// We need to check if there is someone still listening to
// readable and reset the state. However this needs to happen
// after readable has been emitted but before I/O (nextTick) to
// support once('readable', fn) cycles. This means that calling
// resume within the same tick will have no
// effect.
process.nextTick(updateReadableListening, this);
}
return res;
};
function updateReadableListening(self) {
var state = self._readableState;
state.readableListening = self.listenerCount('readable') > 0;
if (state.resumeScheduled && !state.paused) {
// flowing needs to be set to true now, otherwise
// the upcoming resume will not flow.
state.flowing = true; // crude way to check if we should resume
} else if (self.listenerCount('data') > 0) {
self.resume();
}
}
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'); // we flow only if there is no one listening
// for readable, but we still have to call
// resume()
state.flowing = !state.readableListening;
resume(this, state);
}
state.paused = false;
return this;
};
function resume(stream, state) {
if (!state.resumeScheduled) {
state.resumeScheduled = true;
process.nextTick(resume_, stream, state);
}
}
function resume_(stream, state) {
debug('resume', state.reading);
if (!state.reading) {
stream.read(0);
}
state.resumeScheduled = false;
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 (this._readableState.flowing !== false) {
debug('pause');
this._readableState.flowing = false;
this.emit('pause');
}
this._readableState.paused = true;
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 _this = this;
var state = this._readableState;
var paused = false;
stream.on('end', function () {
debug('wrapped end');
if (state.decoder && !state.ended) {
var chunk = state.decoder.end();
if (chunk && chunk.length) _this.push(chunk);
}
_this.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 = _this.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 methodWrap(method) {
return function methodWrapReturnFunction() {
return stream[method].apply(stream, arguments);
};
}(i);
}
} // proxy certain important events.
for (var n = 0; n < kProxyEvents.length; n++) {
stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n]));
} // when we try to consume some more bytes, simply unpause the
// underlying stream.
this._read = function (n) {
debug('wrapped _read', n);
if (paused) {
paused = false;
stream.resume();
}
};
return this;
};
if (typeof Symbol === 'function') {
Readable.prototype[Symbol.asyncIterator] = function () {
if (createReadableStreamAsyncIterator === undefined) {
createReadableStreamAsyncIterator = require('./internal/streams/async_iterator');
}
return createReadableStreamAsyncIterator(this);
};
}
Object.defineProperty(Readable.prototype, 'readableHighWaterMark', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
return this._readableState.highWaterMark;
}
});
Object.defineProperty(Readable.prototype, 'readableBuffer', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
return this._readableState && this._readableState.buffer;
}
});
Object.defineProperty(Readable.prototype, 'readableFlowing', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
return this._readableState.flowing;
},
set: function set(state) {
if (this._readableState) {
this._readableState.flowing = state;
}
}
}); // exposed for testing purposes only.
Readable._fromList = fromList;
Object.defineProperty(Readable.prototype, 'readableLength', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
return this._readableState.length;
}
}); // 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.first();else ret = state.buffer.concat(state.length);
state.buffer.clear();
} else {
// read part of list
ret = state.buffer.consume(n, state.decoder);
}
return ret;
}
function endReadable(stream) {
var state = stream._readableState;
debug('endReadable', state.endEmitted);
if (!state.endEmitted) {
state.ended = true;
process.nextTick(endReadableNT, state, stream);
}
}
function endReadableNT(state, stream) {
debug('endReadableNT', state.endEmitted, state.length); // Check that we didn't get one last unshift.
if (!state.endEmitted && state.length === 0) {
state.endEmitted = true;
stream.readable = false;
stream.emit('end');
if (state.autoDestroy) {
// In case of duplex streams we need a way to detect
// if the writable side is ready for autoDestroy as well
var wState = stream._writableState;
if (!wState || wState.autoDestroy && wState.finished) {
stream.destroy();
}
}
}
}
if (typeof Symbol === 'function') {
Readable.from = function (iterable, opts) {
if (from === undefined) {
from = require('./internal/streams/from');
}
return from(Readable, iterable, opts);
};
}
function indexOf(xs, x) {
for (var i = 0, l = xs.length; i < l; i++) {
if (xs[i] === x) return i;
}
return -1;
}
}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../errors":16,"./_stream_duplex":17,"./internal/streams/async_iterator":22,"./internal/streams/buffer_list":23,"./internal/streams/destroy":24,"./internal/streams/from":26,"./internal/streams/state":28,"./internal/streams/stream":29,"_process":187,"buffer":60,"events":98,"inherits":119,"string_decoder/":286,"util":55}],20:[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 _require$codes = require('../errors').codes,
ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,
ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK,
ERR_TRANSFORM_ALREADY_TRANSFORMING = _require$codes.ERR_TRANSFORM_ALREADY_TRANSFORMING,
ERR_TRANSFORM_WITH_LENGTH_0 = _require$codes.ERR_TRANSFORM_WITH_LENGTH_0;
var Duplex = require('./_stream_duplex');
require('inherits')(Transform, Duplex);
function afterTransform(er, data) {
var ts = this._transformState;
ts.transforming = false;
var cb = ts.writecb;
if (cb === null) {
return this.emit('error', new ERR_MULTIPLE_CALLBACK());
}
ts.writechunk = null;
ts.writecb = null;
if (data != null) // single equals check for both `null` and `undefined`
this.push(data);
cb(er);
var rs = this._readableState;
rs.reading = false;
if (rs.needReadable || rs.length < rs.highWaterMark) {
this._read(rs.highWaterMark);
}
}
function Transform(options) {
if (!(this instanceof Transform)) return new Transform(options);
Duplex.call(this, options);
this._transformState = {
afterTransform: afterTransform.bind(this),
needTransform: false,
transforming: false,
writecb: null,
writechunk: null,
writeencoding: null
}; // 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.on('prefinish', prefinish);
}
function prefinish() {
var _this = this;
if (typeof this._flush === 'function' && !this._readableState.destroyed) {
this._flush(function (er, data) {
done(_this, er, data);
});
} else {
done(this, null, null);
}
}
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) {
cb(new ERR_METHOD_NOT_IMPLEMENTED('_transform()'));
};
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.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) {
Duplex.prototype._destroy.call(this, err, function (err2) {
cb(err2);
});
};
function done(stream, er, data) {
if (er) return stream.emit('error', er);
if (data != null) // single equals check for both `null` and `undefined`
stream.push(data); // TODO(BridgeAR): Write a test for these two error cases
// if there's nothing in the write buffer, then that means
// that nothing more will ever be provided
if (stream._writableState.length) throw new ERR_TRANSFORM_WITH_LENGTH_0();
if (stream._transformState.transforming) throw new ERR_TRANSFORM_ALREADY_TRANSFORMING();
return stream.push(null);
}
},{"../errors":16,"./_stream_duplex":17,"inherits":119}],21:[function(require,module,exports){
(function (process,global){(function (){
// 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';
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 Duplex;
/*</replacement>*/
Writable.WritableState = WritableState;
/*<replacement>*/
var internalUtil = {
deprecate: require('util-deprecate')
};
/*</replacement>*/
/*<replacement>*/
var Stream = require('./internal/streams/stream');
/*</replacement>*/
var Buffer = require('buffer').Buffer;
var OurUint8Array = global.Uint8Array || function () {};
function _uint8ArrayToBuffer(chunk) {
return Buffer.from(chunk);
}
function _isUint8Array(obj) {
return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
}
var destroyImpl = require('./internal/streams/destroy');
var _require = require('./internal/streams/state'),
getHighWaterMark = _require.getHighWaterMark;
var _require$codes = require('../errors').codes,
ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE,
ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,
ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK,
ERR_STREAM_CANNOT_PIPE = _require$codes.ERR_STREAM_CANNOT_PIPE,
ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED,
ERR_STREAM_NULL_VALUES = _require$codes.ERR_STREAM_NULL_VALUES,
ERR_STREAM_WRITE_AFTER_END = _require$codes.ERR_STREAM_WRITE_AFTER_END,
ERR_UNKNOWN_ENCODING = _require$codes.ERR_UNKNOWN_ENCODING;
var errorOrDestroy = destroyImpl.errorOrDestroy;
require('inherits')(Writable, Stream);
function nop() {}
function WritableState(options, stream, isDuplex) {
Duplex = Duplex || require('./_stream_duplex');
options = options || {}; // Duplex streams are both readable and writable, but share
// the same options object.
// However, some cases require setting options to different
// values for the readable and the writable sides of the duplex stream,
// e.g. options.readableObjectMode vs. options.writableObjectMode, etc.
if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag to indicate whether or not this stream
// contains buffers or objects.
this.objectMode = !!options.objectMode;
if (isDuplex) 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()
this.highWaterMark = getHighWaterMark(this, options, 'writableHighWaterMark', isDuplex); // 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; // Should close be emitted on destroy. Defaults to true.
this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'finish' (and potentially 'end')
this.autoDestroy = !!options.autoDestroy; // 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 writableStateBufferGetter() {
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 value(object) {
if (realHasInstance.call(this, object)) return true;
if (this !== Writable) return false;
return object && object._writableState instanceof WritableState;
}
});
} else {
realHasInstance = function realHasInstance(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.
// Checking for a Stream.Duplex instance is faster here instead of inside
// the WritableState constructor, at least with V8 6.5
var isDuplex = this instanceof Duplex;
if (!isDuplex && !realHasInstance.call(Writable, this)) return new Writable(options);
this._writableState = new WritableState(options, this, isDuplex); // 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 () {
errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE());
};
function writeAfterEnd(stream, cb) {
var er = new ERR_STREAM_WRITE_AFTER_END(); // TODO: defer error events consistently everywhere, not just the cb
errorOrDestroy(stream, er);
process.nextTick(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 er;
if (chunk === null) {
er = new ERR_STREAM_NULL_VALUES();
} else if (typeof chunk !== 'string' && !state.objectMode) {
er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk);
}
if (er) {
errorOrDestroy(stream, er);
process.nextTick(cb, er);
return false;
}
return true;
}
Writable.prototype.write = function (chunk, encoding, cb) {
var state = this._writableState;
var ret = false;
var isBuf = !state.objectMode && _isUint8Array(chunk);
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.ending) 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 () {
this._writableState.corked++;
};
Writable.prototype.uncork = function () {
var state = this._writableState;
if (state.corked) {
state.corked--;
if (!state.writing && !state.corked && !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 ERR_UNKNOWN_ENCODING(encoding);
this._writableState.defaultEncoding = encoding;
return this;
};
Object.defineProperty(Writable.prototype, 'writableBuffer', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
return this._writableState && this._writableState.getBuffer();
}
});
function decodeChunk(state, chunk, encoding) {
if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {
chunk = Buffer.from(chunk, encoding);
}
return chunk;
}
Object.defineProperty(Writable.prototype, 'writableHighWaterMark', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
return this._writableState.highWaterMark;
}
}); // 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 (state.destroyed) state.onwrite(new ERR_STREAM_DESTROYED('write'));else 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
process.nextTick(cb, er); // this can emit finish, and it will always happen
// after error
process.nextTick(finishMaybe, stream, state);
stream._writableState.errorEmitted = true;
errorOrDestroy(stream, er);
} else {
// the caller expect this to happen before if
// it is async
cb(er);
stream._writableState.errorEmitted = true;
errorOrDestroy(stream, 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;
if (typeof cb !== 'function') throw new ERR_MULTIPLE_CALLBACK();
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) || stream.destroyed;
if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {
clearBuffer(stream, state);
}
if (sync) {
process.nextTick(afterWrite, stream, state, finished, cb);
} 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);
}
state.bufferedRequestCount = 0;
} 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;
state.bufferedRequestCount--; // 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.bufferedRequest = entry;
state.bufferProcessing = false;
}
Writable.prototype._write = function (chunk, encoding, cb) {
cb(new ERR_METHOD_NOT_IMPLEMENTED('_write()'));
};
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) endWritable(this, state, cb);
return this;
};
Object.defineProperty(Writable.prototype, 'writableLength', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
return this._writableState.length;
}
});
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) {
errorOrDestroy(stream, 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.destroyed) {
state.pendingcb++;
state.finalCalled = true;
process.nextTick(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');
if (state.autoDestroy) {
// In case of duplex streams we need a way to detect
// if the readable side is ready for autoDestroy as well
var rState = stream._readableState;
if (!rState || rState.autoDestroy && rState.endEmitted) {
stream.destroy();
}
}
}
}
return need;
}
function endWritable(stream, state, cb) {
state.ending = true;
finishMaybe(stream, state);
if (cb) {
if (state.finished) process.nextTick(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;
} // reuse the free corkReq.
state.corkedRequestsFree.next = corkReq;
}
Object.defineProperty(Writable.prototype, 'destroyed', {
// making it explicit this property is not enumerable
// because otherwise some prototype manipulation in
// userland will fail
enumerable: false,
get: function get() {
if (this._writableState === undefined) {
return false;
}
return this._writableState.destroyed;
},
set: function set(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) {
cb(err);
};
}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../errors":16,"./_stream_duplex":17,"./internal/streams/destroy":24,"./internal/streams/state":28,"./internal/streams/stream":29,"_process":187,"buffer":60,"inherits":119,"util-deprecate":306}],22:[function(require,module,exports){
(function (process){(function (){
'use strict';
var _Object$setPrototypeO;
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var finished = require('./end-of-stream');
var kLastResolve = Symbol('lastResolve');
var kLastReject = Symbol('lastReject');
var kError = Symbol('error');
var kEnded = Symbol('ended');
var kLastPromise = Symbol('lastPromise');
var kHandlePromise = Symbol('handlePromise');
var kStream = Symbol('stream');
function createIterResult(value, done) {
return {
value: value,
done: done
};
}
function readAndResolve(iter) {
var resolve = iter[kLastResolve];
if (resolve !== null) {
var data = iter[kStream].read(); // we defer if data is null
// we can be expecting either 'end' or
// 'error'
if (data !== null) {
iter[kLastPromise] = null;
iter[kLastResolve] = null;
iter[kLastReject] = null;
resolve(createIterResult(data, false));
}
}
}
function onReadable(iter) {
// we wait for the next tick, because it might
// emit an error with process.nextTick
process.nextTick(readAndResolve, iter);
}
function wrapForNext(lastPromise, iter) {
return function (resolve, reject) {
lastPromise.then(function () {
if (iter[kEnded]) {
resolve(createIterResult(undefined, true));
return;
}
iter[kHandlePromise](resolve, reject);
}, reject);
};
}
var AsyncIteratorPrototype = Object.getPrototypeOf(function () {});
var ReadableStreamAsyncIteratorPrototype = Object.setPrototypeOf((_Object$setPrototypeO = {
get stream() {
return this[kStream];
},
next: function next() {
var _this = this;
// if we have detected an error in the meanwhile
// reject straight away
var error = this[kError];
if (error !== null) {
return Promise.reject(error);
}
if (this[kEnded]) {
return Promise.resolve(createIterResult(undefined, true));
}
if (this[kStream].destroyed) {
// We need to defer via nextTick because if .destroy(err) is
// called, the error will be emitted via nextTick, and
// we cannot guarantee that there is no error lingering around
// waiting to be emitted.
return new Promise(function (resolve, reject) {
process.nextTick(function () {
if (_this[kError]) {
reject(_this[kError]);
} else {
resolve(createIterResult(undefined, true));
}
});
});
} // if we have multiple next() calls
// we will wait for the previous Promise to finish
// this logic is optimized to support for await loops,
// where next() is only called once at a time
var lastPromise = this[kLastPromise];
var promise;
if (lastPromise) {
promise = new Promise(wrapForNext(lastPromise, this));
} else {
// fast path needed to support multiple this.push()
// without triggering the next() queue
var data = this[kStream].read();
if (data !== null) {
return Promise.resolve(createIterResult(data, false));
}
promise = new Promise(this[kHandlePromise]);
}
this[kLastPromise] = promise;
return promise;
}
}, _defineProperty(_Object$setPrototypeO, Symbol.asyncIterator, function () {
return this;
}), _defineProperty(_Object$setPrototypeO, "return", function _return() {
var _this2 = this;
// destroy(err, cb) is a private API
// we can guarantee we have that here, because we control the
// Readable class this is attached to
return new Promise(function (resolve, reject) {
_this2[kStream].destroy(null, function (err) {
if (err) {
reject(err);
return;
}
resolve(createIterResult(undefined, true));
});
});
}), _Object$setPrototypeO), AsyncIteratorPrototype);
var createReadableStreamAsyncIterator = function createReadableStreamAsyncIterator(stream) {
var _Object$create;
var iterator = Object.create(ReadableStreamAsyncIteratorPrototype, (_Object$create = {}, _defineProperty(_Object$create, kStream, {
value: stream,
writable: true
}), _defineProperty(_Object$create, kLastResolve, {
value: null,
writable: true
}), _defineProperty(_Object$create, kLastReject, {
value: null,
writable: true
}), _defineProperty(_Object$create, kError, {
value: null,
writable: true
}), _defineProperty(_Object$create, kEnded, {
value: stream._readableState.endEmitted,
writable: true
}), _defineProperty(_Object$create, kHandlePromise, {
value: function value(resolve, reject) {
var data = iterator[kStream].read();
if (data) {
iterator[kLastPromise] = null;
iterator[kLastResolve] = null;
iterator[kLastReject] = null;
resolve(createIterResult(data, false));
} else {
iterator[kLastResolve] = resolve;
iterator[kLastReject] = reject;
}
},
writable: true
}), _Object$create));
iterator[kLastPromise] = null;
finished(stream, function (err) {
if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') {
var reject = iterator[kLastReject]; // reject if we are waiting for data in the Promise
// returned by next() and store the error
if (reject !== null) {
iterator[kLastPromise] = null;
iterator[kLastResolve] = null;
iterator[kLastReject] = null;
reject(err);
}
iterator[kError] = err;
return;
}
var resolve = iterator[kLastResolve];
if (resolve !== null) {
iterator[kLastPromise] = null;
iterator[kLastResolve] = null;
iterator[kLastReject] = null;
resolve(createIterResult(undefined, true));
}
iterator[kEnded] = true;
});
stream.on('readable', onReadable.bind(null, iterator));
return iterator;
};
module.exports = createReadableStreamAsyncIterator;
}).call(this)}).call(this,require('_process'))
},{"./end-of-stream":25,"_process":187}],23:[function(require,module,exports){
'use strict';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var _require = require('buffer'),
Buffer = _require.Buffer;
var _require2 = require('util'),
inspect = _require2.inspect;
var custom = inspect && inspect.custom || 'inspect';
function copyBuffer(src, target, offset) {
Buffer.prototype.copy.call(src, target, offset);
}
module.exports =
/*#__PURE__*/
function () {
function BufferList() {
_classCallCheck(this, BufferList);
this.head = null;
this.tail = null;
this.length = 0;
}
_createClass(BufferList, [{
key: "push",
value: 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;
}
}, {
key: "unshift",
value: function unshift(v) {
var entry = {
data: v,
next: this.head
};
if (this.length === 0) this.tail = entry;
this.head = entry;
++this.length;
}
}, {
key: "shift",
value: 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;
}
}, {
key: "clear",
value: function clear() {
this.head = this.tail = null;
this.length = 0;
}
}, {
key: "join",
value: 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;
}
}, {
key: "concat",
value: function concat(n) {
if (this.length === 0) return Buffer.alloc(0);
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;
} // Consumes a specified amount of bytes or characters from the buffered data.
}, {
key: "consume",
value: function consume(n, hasStrings) {
var ret;
if (n < this.head.data.length) {
// `slice` is the same for buffers and strings.
ret = this.head.data.slice(0, n);
this.head.data = this.head.data.slice(n);
} else if (n === this.head.data.length) {
// First chunk is a perfect match.
ret = this.shift();
} else {
// Result spans more than one buffer.
ret = hasStrings ? this._getString(n) : this._getBuffer(n);
}
return ret;
}
}, {
key: "first",
value: function first() {
return this.head.data;
} // Consumes a specified amount of characters from the buffered data.
}, {
key: "_getString",
value: function _getString(n) {
var p = this.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) this.head = p.next;else this.head = this.tail = null;
} else {
this.head = p;
p.data = str.slice(nb);
}
break;
}
++c;
}
this.length -= c;
return ret;
} // Consumes a specified amount of bytes from the buffered data.
}, {
key: "_getBuffer",
value: function _getBuffer(n) {
var ret = Buffer.allocUnsafe(n);
var p = this.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) this.head = p.next;else this.head = this.tail = null;
} else {
this.head = p;
p.data = buf.slice(nb);
}
break;
}
++c;
}
this.length -= c;
return ret;
} // Make sure the linked list only shows the minimal necessary information.
}, {
key: custom,
value: function value(_, options) {
return inspect(this, _objectSpread({}, options, {
// Only inspect one level.
depth: 0,
// It should not recurse.
customInspect: false
}));
}
}]);
return BufferList;
}();
},{"buffer":60,"util":55}],24:[function(require,module,exports){
(function (process){(function (){
'use strict'; // 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) {
if (!this._writableState) {
process.nextTick(emitErrorNT, this, err);
} else if (!this._writableState.errorEmitted) {
this._writableState.errorEmitted = true;
process.nextTick(emitErrorNT, this, err);
}
}
return this;
} // 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) {
if (!_this._writableState) {
process.nextTick(emitErrorAndCloseNT, _this, err);
} else if (!_this._writableState.errorEmitted) {
_this._writableState.errorEmitted = true;
process.nextTick(emitErrorAndCloseNT, _this, err);
} else {
process.nextTick(emitCloseNT, _this);
}
} else if (cb) {
process.nextTick(emitCloseNT, _this);
cb(err);
} else {
process.nextTick(emitCloseNT, _this);
}
});
return this;
}
function emitErrorAndCloseNT(self, err) {
emitErrorNT(self, err);
emitCloseNT(self);
}
function emitCloseNT(self) {
if (self._writableState && !self._writableState.emitClose) return;
if (self._readableState && !self._readableState.emitClose) return;
self.emit('close');
}
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.finalCalled = false;
this._writableState.prefinished = false;
this._writableState.finished = false;
this._writableState.errorEmitted = false;
}
}
function emitErrorNT(self, err) {
self.emit('error', err);
}
function errorOrDestroy(stream, err) {
// We have tests that rely on errors being emitted
// in the same tick, so changing this is semver major.
// For now when you opt-in to autoDestroy we allow
// the error to be emitted nextTick. In a future
// semver major update we should change the default to this.
var rState = stream._readableState;
var wState = stream._writableState;
if (rState && rState.autoDestroy || wState && wState.autoDestroy) stream.destroy(err);else stream.emit('error', err);
}
module.exports = {
destroy: destroy,
undestroy: undestroy,
errorOrDestroy: errorOrDestroy
};
}).call(this)}).call(this,require('_process'))
},{"_process":187}],25:[function(require,module,exports){
// Ported from https://github.com/mafintosh/end-of-stream with
// permission from the author, Mathias Buus (@mafintosh).
'use strict';
var ERR_STREAM_PREMATURE_CLOSE = require('../../../errors').codes.ERR_STREAM_PREMATURE_CLOSE;
function once(callback) {
var called = false;
return function () {
if (called) return;
called = true;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
callback.apply(this, args);
};
}
function noop() {}
function isRequest(stream) {
return stream.setHeader && typeof stream.abort === 'function';
}
function eos(stream, opts, callback) {
if (typeof opts === 'function') return eos(stream, null, opts);
if (!opts) opts = {};
callback = once(callback || noop);
var readable = opts.readable || opts.readable !== false && stream.readable;
var writable = opts.writable || opts.writable !== false && stream.writable;
var onlegacyfinish = function onlegacyfinish() {
if (!stream.writable) onfinish();
};
var writableEnded = stream._writableState && stream._writableState.finished;
var onfinish = function onfinish() {
writable = false;
writableEnded = true;
if (!readable) callback.call(stream);
};
var readableEnded = stream._readableState && stream._readableState.endEmitted;
var onend = function onend() {
readable = false;
readableEnded = true;
if (!writable) callback.call(stream);
};
var onerror = function onerror(err) {
callback.call(stream, err);
};
var onclose = function onclose() {
var err;
if (readable && !readableEnded) {
if (!stream._readableState || !stream._readableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE();
return callback.call(stream, err);
}
if (writable && !writableEnded) {
if (!stream._writableState || !stream._writableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE();
return callback.call(stream, err);
}
};
var onrequest = function onrequest() {
stream.req.on('finish', onfinish);
};
if (isRequest(stream)) {
stream.on('complete', onfinish);
stream.on('abort', onclose);
if (stream.req) onrequest();else stream.on('request', onrequest);
} else if (writable && !stream._writableState) {
// legacy streams
stream.on('end', onlegacyfinish);
stream.on('close', onlegacyfinish);
}
stream.on('end', onend);
stream.on('finish', onfinish);
if (opts.error !== false) stream.on('error', onerror);
stream.on('close', onclose);
return function () {
stream.removeListener('complete', onfinish);
stream.removeListener('abort', onclose);
stream.removeListener('request', onrequest);
if (stream.req) stream.req.removeListener('finish', onfinish);
stream.removeListener('end', onlegacyfinish);
stream.removeListener('close', onlegacyfinish);
stream.removeListener('finish', onfinish);
stream.removeListener('end', onend);
stream.removeListener('error', onerror);
stream.removeListener('close', onclose);
};
}
module.exports = eos;
},{"../../../errors":16}],26:[function(require,module,exports){
module.exports = function () {
throw new Error('Readable.from is not available in the browser')
};
},{}],27:[function(require,module,exports){
// Ported from https://github.com/mafintosh/pump with
// permission from the author, Mathias Buus (@mafintosh).
'use strict';
var eos;
function once(callback) {
var called = false;
return function () {
if (called) return;
called = true;
callback.apply(void 0, arguments);
};
}
var _require$codes = require('../../../errors').codes,
ERR_MISSING_ARGS = _require$codes.ERR_MISSING_ARGS,
ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED;
function noop(err) {
// Rethrow the error if it exists to avoid swallowing it
if (err) throw err;
}
function isRequest(stream) {
return stream.setHeader && typeof stream.abort === 'function';
}
function destroyer(stream, reading, writing, callback) {
callback = once(callback);
var closed = false;
stream.on('close', function () {
closed = true;
});
if (eos === undefined) eos = require('./end-of-stream');
eos(stream, {
readable: reading,
writable: writing
}, function (err) {
if (err) return callback(err);
closed = true;
callback();
});
var destroyed = false;
return function (err) {
if (closed) return;
if (destroyed) return;
destroyed = true; // request.destroy just do .end - .abort is what we want
if (isRequest(stream)) return stream.abort();
if (typeof stream.destroy === 'function') return stream.destroy();
callback(err || new ERR_STREAM_DESTROYED('pipe'));
};
}
function call(fn) {
fn();
}
function pipe(from, to) {
return from.pipe(to);
}
function popCallback(streams) {
if (!streams.length) return noop;
if (typeof streams[streams.length - 1] !== 'function') return noop;
return streams.pop();
}
function pipeline() {
for (var _len = arguments.length, streams = new Array(_len), _key = 0; _key < _len; _key++) {
streams[_key] = arguments[_key];
}
var callback = popCallback(streams);
if (Array.isArray(streams[0])) streams = streams[0];
if (streams.length < 2) {
throw new ERR_MISSING_ARGS('streams');
}
var error;
var destroys = streams.map(function (stream, i) {
var reading = i < streams.length - 1;
var writing = i > 0;
return destroyer(stream, reading, writing, function (err) {
if (!error) error = err;
if (err) destroys.forEach(call);
if (reading) return;
destroys.forEach(call);
callback(error);
});
});
return streams.reduce(pipe);
}
module.exports = pipeline;
},{"../../../errors":16,"./end-of-stream":25}],28:[function(require,module,exports){
'use strict';
var ERR_INVALID_OPT_VALUE = require('../../../errors').codes.ERR_INVALID_OPT_VALUE;
function highWaterMarkFrom(options, isDuplex, duplexKey) {
return options.highWaterMark != null ? options.highWaterMark : isDuplex ? options[duplexKey] : null;
}
function getHighWaterMark(state, options, duplexKey, isDuplex) {
var hwm = highWaterMarkFrom(options, isDuplex, duplexKey);
if (hwm != null) {
if (!(isFinite(hwm) && Math.floor(hwm) === hwm) || hwm < 0) {
var name = isDuplex ? duplexKey : 'highWaterMark';
throw new ERR_INVALID_OPT_VALUE(name, hwm);
}
return Math.floor(hwm);
} // Default value
return state.objectMode ? 16 : 16 * 1024;
}
module.exports = {
getHighWaterMark: getHighWaterMark
};
},{"../../../errors":16}],29:[function(require,module,exports){
module.exports = require('events').EventEmitter;
},{"events":98}],30:[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');
exports.finished = require('./lib/internal/streams/end-of-stream.js');
exports.pipeline = require('./lib/internal/streams/pipeline.js');
},{"./lib/_stream_duplex.js":17,"./lib/_stream_passthrough.js":18,"./lib/_stream_readable.js":19,"./lib/_stream_transform.js":20,"./lib/_stream_writable.js":21,"./lib/internal/streams/end-of-stream.js":25,"./lib/internal/streams/pipeline.js":27}],31:[function(require,module,exports){
(function (process,Buffer){(function (){
const debug = require('debug')('bittorrent-tracker:client')
const EventEmitter = require('events')
const once = require('once')
const parallel = require('run-parallel')
const Peer = require('simple-peer')
const common = require('./lib/common')
const HTTPTracker = require('./lib/client/http-tracker') // empty object in browser
const UDPTracker = require('./lib/client/udp-tracker') // empty object in browser
const WebSocketTracker = require('./lib/client/websocket-tracker')
/**
* BitTorrent tracker client.
*
* Find torrent peers, to help a torrent client participate in a torrent swarm.
*
* @param {Object} opts options object
* @param {string|Buffer} opts.infoHash torrent info hash
* @param {string|Buffer} opts.peerId peer id
* @param {string|Array.<string>} opts.announce announce
* @param {number} opts.port torrent client listening port
* @param {function} opts.getAnnounceOpts callback to provide data to tracker
* @param {number} opts.rtcConfig RTCPeerConnection configuration object
* @param {number} opts.userAgent User-Agent header for http requests
* @param {number} opts.wrtc custom webrtc impl (useful in node.js)
*/
class Client extends EventEmitter {
constructor (opts = {}) {
super()
if (!opts.peerId) throw new Error('Option `peerId` is required')
if (!opts.infoHash) throw new Error('Option `infoHash` is required')
if (!opts.announce) throw new Error('Option `announce` is required')
if (!process.browser && !opts.port) throw new Error('Option `port` is required')
this.peerId = typeof opts.peerId === 'string'
? opts.peerId
: opts.peerId.toString('hex')
this._peerIdBuffer = Buffer.from(this.peerId, 'hex')
this._peerIdBinary = this._peerIdBuffer.toString('binary')
this.infoHash = typeof opts.infoHash === 'string'
? opts.infoHash.toLowerCase()
: opts.infoHash.toString('hex')
this._infoHashBuffer = Buffer.from(this.infoHash, 'hex')
this._infoHashBinary = this._infoHashBuffer.toString('binary')
debug('new client %s', this.infoHash)
this.destroyed = false
this._port = opts.port
this._getAnnounceOpts = opts.getAnnounceOpts
this._rtcConfig = opts.rtcConfig
this._userAgent = opts.userAgent
// Support lazy 'wrtc' module initialization
// See: https://github.com/webtorrent/webtorrent-hybrid/issues/46
this._wrtc = typeof opts.wrtc === 'function' ? opts.wrtc() : opts.wrtc
let announce = typeof opts.announce === 'string'
? [opts.announce]
: opts.announce == null ? [] : opts.announce
// Remove trailing slash from trackers to catch duplicates
announce = announce.map(announceUrl => {
announceUrl = announceUrl.toString()
if (announceUrl[announceUrl.length - 1] === '/') {
announceUrl = announceUrl.substring(0, announceUrl.length - 1)
}
return announceUrl
})
// remove duplicates by converting to Set and back
announce = Array.from(new Set(announce))
const webrtcSupport = this._wrtc !== false && (!!this._wrtc || Peer.WEBRTC_SUPPORT)
const nextTickWarn = err => {
process.nextTick(() => {
this.emit('warning', err)
})
}
this._trackers = announce
.map(announceUrl => {
let parsedUrl
try {
parsedUrl = new URL(announceUrl)
} catch (err) {
nextTickWarn(new Error(`Invalid tracker URL: ${announceUrl}`))
return null
}
const port = parsedUrl.port
if (port < 0 || port > 65535) {
nextTickWarn(new Error(`Invalid tracker port: ${announceUrl}`))
return null
}
const protocol = parsedUrl.protocol
if ((protocol === 'http:' || protocol === 'https:') &&
typeof HTTPTracker === 'function') {
return new HTTPTracker(this, announceUrl)
} else if (protocol === 'udp:' && typeof UDPTracker === 'function') {
return new UDPTracker(this, announceUrl)
} else if ((protocol === 'ws:' || protocol === 'wss:') && webrtcSupport) {
// Skip ws:// trackers on https:// sites because they throw SecurityError
if (protocol === 'ws:' && typeof window !== 'undefined' &&
window.location.protocol === 'https:') {
nextTickWarn(new Error(`Unsupported tracker protocol: ${announceUrl}`))
return null
}
return new WebSocketTracker(this, announceUrl)
} else {
nextTickWarn(new Error(`Unsupported tracker protocol: ${announceUrl}`))
return null
}
})
.filter(Boolean)
}
/**
* Send a `start` announce to the trackers.
* @param {Object} opts
* @param {number=} opts.uploaded
* @param {number=} opts.downloaded
* @param {number=} opts.left (if not set, calculated automatically)
*/
start (opts) {
opts = this._defaultAnnounceOpts(opts)
opts.event = 'started'
debug('send `start` %o', opts)
this._announce(opts)
// start announcing on intervals
this._trackers.forEach(tracker => {
tracker.setInterval()
})
}
/**
* Send a `stop` announce to the trackers.
* @param {Object} opts
* @param {number=} opts.uploaded
* @param {number=} opts.downloaded
* @param {number=} opts.numwant
* @param {number=} opts.left (if not set, calculated automatically)
*/
stop (opts) {
opts = this._defaultAnnounceOpts(opts)
opts.event = 'stopped'
debug('send `stop` %o', opts)
this._announce(opts)
}
/**
* Send a `complete` announce to the trackers.
* @param {Object} opts
* @param {number=} opts.uploaded
* @param {number=} opts.downloaded
* @param {number=} opts.numwant
* @param {number=} opts.left (if not set, calculated automatically)
*/
complete (opts) {
if (!opts) opts = {}
opts = this._defaultAnnounceOpts(opts)
opts.event = 'completed'
debug('send `complete` %o', opts)
this._announce(opts)
}
/**
* Send a `update` announce to the trackers.
* @param {Object} opts
* @param {number=} opts.uploaded
* @param {number=} opts.downloaded
* @param {number=} opts.numwant
* @param {number=} opts.left (if not set, calculated automatically)
*/
update (opts) {
opts = this._defaultAnnounceOpts(opts)
if (opts.event) delete opts.event
debug('send `update` %o', opts)
this._announce(opts)
}
_announce (opts) {
this._trackers.forEach(tracker => {
// tracker should not modify `opts` object, it's passed to all trackers
tracker.announce(opts)
})
}
/**
* Send a scrape request to the trackers.
* @param {Object} opts
*/
scrape (opts) {
debug('send `scrape`')
if (!opts) opts = {}
this._trackers.forEach(tracker => {
// tracker should not modify `opts` object, it's passed to all trackers
tracker.scrape(opts)
})
}
setInterval (intervalMs) {
debug('setInterval %d', intervalMs)
this._trackers.forEach(tracker => {
tracker.setInterval(intervalMs)
})
}
destroy (cb) {
if (this.destroyed) return
this.destroyed = true
debug('destroy')
const tasks = this._trackers.map(tracker => cb => {
tracker.destroy(cb)
})
parallel(tasks, cb)
this._trackers = []
this._getAnnounceOpts = null
}
_defaultAnnounceOpts (opts = {}) {
if (opts.numwant == null) opts.numwant = common.DEFAULT_ANNOUNCE_PEERS
if (opts.uploaded == null) opts.uploaded = 0
if (opts.downloaded == null) opts.downloaded = 0
if (this._getAnnounceOpts) opts = Object.assign({}, opts, this._getAnnounceOpts())
return opts
}
}
/**
* Simple convenience function to scrape a tracker for an info hash without needing to
* create a Client, pass it a parsed torrent, etc. Support scraping a tracker for multiple
* torrents at the same time.
* @params {Object} opts
* @param {string|Array.<string>} opts.infoHash
* @param {string} opts.announce
* @param {function} cb
*/
Client.scrape = (opts, cb) => {
cb = once(cb)
if (!opts.infoHash) throw new Error('Option `infoHash` is required')
if (!opts.announce) throw new Error('Option `announce` is required')
const clientOpts = Object.assign({}, opts, {
infoHash: Array.isArray(opts.infoHash) ? opts.infoHash[0] : opts.infoHash,
peerId: Buffer.from('01234567890123456789'), // dummy value
port: 6881 // dummy value
})
const client = new Client(clientOpts)
client.once('error', cb)
client.once('warning', cb)
let len = Array.isArray(opts.infoHash) ? opts.infoHash.length : 1
const results = {}
client.on('scrape', data => {
len -= 1
results[data.infoHash] = data
if (len === 0) {
client.destroy()
const keys = Object.keys(results)
if (keys.length === 1) {
cb(null, results[keys[0]])
} else {
cb(null, results)
}
}
})
opts.infoHash = Array.isArray(opts.infoHash)
? opts.infoHash.map(infoHash => {
return Buffer.from(infoHash, 'hex')
})
: Buffer.from(opts.infoHash, 'hex')
client.scrape({ infoHash: opts.infoHash })
return client
}
module.exports = Client
}).call(this)}).call(this,require('_process'),require("buffer").Buffer)
},{"./lib/client/http-tracker":55,"./lib/client/udp-tracker":55,"./lib/client/websocket-tracker":33,"./lib/common":34,"_process":187,"buffer":60,"debug":35,"events":98,"once":183,"run-parallel":218,"simple-peer":223}],32:[function(require,module,exports){
const EventEmitter = require('events')
class Tracker extends EventEmitter {
constructor (client, announceUrl) {
super()
this.client = client
this.announceUrl = announceUrl
this.interval = null
this.destroyed = false
}
setInterval (intervalMs) {
if (intervalMs == null) intervalMs = this.DEFAULT_ANNOUNCE_INTERVAL
clearInterval(this.interval)
if (intervalMs) {
this.interval = setInterval(() => {
this.announce(this.client._defaultAnnounceOpts())
}, intervalMs)
if (this.interval.unref) this.interval.unref()
}
}
}
module.exports = Tracker
},{"events":98}],33:[function(require,module,exports){
const debug = require('debug')('bittorrent-tracker:websocket-tracker')
const Peer = require('simple-peer')
const randombytes = require('randombytes')
const Socket = require('simple-websocket')
const common = require('../common')
const Tracker = require('./tracker')
// Use a socket pool, so tracker clients share WebSocket objects for the same server.
// In practice, WebSockets are pretty slow to establish, so this gives a nice performance
// boost, and saves browser resources.
const socketPool = {}
const RECONNECT_MINIMUM = 10 * 1000
const RECONNECT_MAXIMUM = 60 * 60 * 1000
const RECONNECT_VARIANCE = 5 * 60 * 1000
const OFFER_TIMEOUT = 50 * 1000
class WebSocketTracker extends Tracker {
constructor (client, announceUrl, opts) {
super(client, announceUrl)
debug('new websocket tracker %s', announceUrl)
this.peers = {} // peers (offer id -> peer)
this.socket = null
this.reconnecting = false
this.retries = 0
this.reconnectTimer = null
// Simple boolean flag to track whether the socket has received data from
// the websocket server since the last time socket.send() was called.
this.expectingResponse = false
this._openSocket()
}
announce (opts) {
if (this.destroyed || this.reconnecting) return
if (!this.socket.connected) {
this.socket.once('connect', () => {
this.announce(opts)
})
return
}
const params = Object.assign({}, opts, {
action: 'announce',
info_hash: this.client._infoHashBinary,
peer_id: this.client._peerIdBinary
})
if (this._trackerId) params.trackerid = this._trackerId
if (opts.event === 'stopped' || opts.event === 'completed') {
// Don't include offers with 'stopped' or 'completed' event
this._send(params)
} else {
// Limit the number of offers that are generated, since it can be slow
const numwant = Math.min(opts.numwant, 10)
this._generateOffers(numwant, offers => {
params.numwant = numwant
params.offers = offers
this._send(params)
})
}
}
scrape (opts) {
if (this.destroyed || this.reconnecting) return
if (!this.socket.connected) {
this.socket.once('connect', () => {
this.scrape(opts)
})
return
}
const infoHashes = (Array.isArray(opts.infoHash) && opts.infoHash.length > 0)
? opts.infoHash.map(infoHash => {
return infoHash.toString('binary')
})
: (opts.infoHash && opts.infoHash.toString('binary')) || this.client._infoHashBinary
const params = {
action: 'scrape',
info_hash: infoHashes
}
this._send(params)
}
destroy (cb = noop) {
if (this.destroyed) return cb(null)
this.destroyed = true
clearInterval(this.interval)
clearTimeout(this.reconnectTimer)
// Destroy peers
for (const peerId in this.peers) {
const peer = this.peers[peerId]
clearTimeout(peer.trackerTimeout)
peer.destroy()
}
this.peers = null
if (this.socket) {
this.socket.removeListener('connect', this._onSocketConnectBound)
this.socket.removeListener('data', this._onSocketDataBound)
this.socket.removeListener('close', this._onSocketCloseBound)
this.socket.removeListener('error', this._onSocketErrorBound)
this.socket = null
}
this._onSocketConnectBound = null
this._onSocketErrorBound = null
this._onSocketDataBound = null
this._onSocketCloseBound = null
if (socketPool[this.announceUrl]) {
socketPool[this.announceUrl].consumers -= 1
}
// Other instances are using the socket, so there's nothing left to do here
if (socketPool[this.announceUrl].consumers > 0) return cb()
let socket = socketPool[this.announceUrl]
delete socketPool[this.announceUrl]
socket.on('error', noop) // ignore all future errors
socket.once('close', cb)
// If there is no data response expected, destroy immediately.
if (!this.expectingResponse) return destroyCleanup()
// Otherwise, wait a short time for potential responses to come in from the
// server, then force close the socket.
var timeout = setTimeout(destroyCleanup, common.DESTROY_TIMEOUT)
// But, if a response comes from the server before the timeout fires, do cleanup
// right away.
socket.once('data', destroyCleanup)
function destroyCleanup () {
if (timeout) {
clearTimeout(timeout)
timeout = null
}
socket.removeListener('data', destroyCleanup)
socket.destroy()
socket = null
}
}
_openSocket () {
this.destroyed = false
if (!this.peers) this.peers = {}
this._onSocketConnectBound = () => {
this._onSocketConnect()
}
this._onSocketErrorBound = err => {
this._onSocketError(err)
}
this._onSocketDataBound = data => {
this._onSocketData(data)
}
this._onSocketCloseBound = () => {
this._onSocketClose()
}
this.socket = socketPool[this.announceUrl]
if (this.socket) {
socketPool[this.announceUrl].consumers += 1
if (this.socket.connected) {
this._onSocketConnectBound()
}
} else {
this.socket = socketPool[this.announceUrl] = new Socket(this.announceUrl)
this.socket.consumers = 1
this.socket.once('connect', this._onSocketConnectBound)
}
this.socket.on('data', this._onSocketDataBound)
this.socket.once('close', this._onSocketCloseBound)
this.socket.once('error', this._onSocketErrorBound)
}
_onSocketConnect () {
if (this.destroyed) return
if (this.reconnecting) {
this.reconnecting = false
this.retries = 0
this.announce(this.client._defaultAnnounceOpts())
}
}
_onSocketData (data) {
if (this.destroyed) return
this.expectingResponse = false
try {
data = JSON.parse(data)
} catch (err) {
this.client.emit('warning', new Error('Invalid tracker response'))
return
}
if (data.action === 'announce') {
this._onAnnounceResponse(data)
} else if (data.action === 'scrape') {
this._onScrapeResponse(data)
} else {
this._onSocketError(new Error(`invalid action in WS response: ${data.action}`))
}
}
_onAnnounceResponse (data) {
if (data.info_hash !== this.client._infoHashBinary) {
debug(
'ignoring websocket data from %s for %s (looking for %s: reused socket)',
this.announceUrl, common.binaryToHex(data.info_hash), this.client.infoHash
)
return
}
if (data.peer_id && data.peer_id === this.client._peerIdBinary) {
// ignore offers/answers from this client
return
}
debug(
'received %s from %s for %s',
JSON.stringify(data), this.announceUrl, this.client.infoHash
)
const failure = data['failure reason']
if (failure) return this.client.emit('warning', new Error(failure))
const warning = data['warning message']
if (warning) this.client.emit('warning', new Error(warning))
const interval = data.interval || data['min interval']
if (interval) this.setInterval(interval * 1000)
const trackerId = data['tracker id']
if (trackerId) {
// If absent, do not discard previous trackerId value
this._trackerId = trackerId
}
if (data.complete != null) {
const response = Object.assign({}, data, {
announce: this.announceUrl,
infoHash: common.binaryToHex(data.info_hash)
})
this.client.emit('update', response)
}
let peer
if (data.offer && data.peer_id) {
debug('creating peer (from remote offer)')
peer = this._createPeer()
peer.id = common.binaryToHex(data.peer_id)
peer.once('signal', answer => {
const params = {
action: 'announce',
info_hash: this.client._infoHashBinary,
peer_id: this.client._peerIdBinary,
to_peer_id: data.peer_id,
answer,
offer_id: data.offer_id
}
if (this._trackerId) params.trackerid = this._trackerId
this._send(params)
})
peer.signal(data.offer)
this.client.emit('peer', peer)
}
if (data.answer && data.peer_id) {
const offerId = common.binaryToHex(data.offer_id)
peer = this.peers[offerId]
if (peer) {
peer.id = common.binaryToHex(data.peer_id)
peer.signal(data.answer)
this.client.emit('peer', peer)
clearTimeout(peer.trackerTimeout)
peer.trackerTimeout = null
delete this.peers[offerId]
} else {
debug(`got unexpected answer: ${JSON.stringify(data.answer)}`)
}
}
}
_onScrapeResponse (data) {
data = data.files || {}
const keys = Object.keys(data)
if (keys.length === 0) {
this.client.emit('warning', new Error('invalid scrape response'))
return
}
keys.forEach(infoHash => {
// TODO: optionally handle data.flags.min_request_interval
// (separate from announce interval)
const response = Object.assign(data[infoHash], {
announce: this.announceUrl,
infoHash: common.binaryToHex(infoHash)
})
this.client.emit('scrape', response)
})
}
_onSocketClose () {
if (this.destroyed) return
this.destroy()
this._startReconnectTimer()
}
_onSocketError (err) {
if (this.destroyed) return
this.destroy()
// errors will often happen if a tracker is offline, so don't treat it as fatal
this.client.emit('warning', err)
this._startReconnectTimer()
}
_startReconnectTimer () {
const ms = Math.floor(Math.random() * RECONNECT_VARIANCE) + Math.min(Math.pow(2, this.retries) * RECONNECT_MINIMUM, RECONNECT_MAXIMUM)
this.reconnecting = true
clearTimeout(this.reconnectTimer)
this.reconnectTimer = setTimeout(() => {
this.retries++
this._openSocket()
}, ms)
if (this.reconnectTimer.unref) this.reconnectTimer.unref()
debug('reconnecting socket in %s ms', ms)
}
_send (params) {
if (this.destroyed) return
this.expectingResponse = true
const message = JSON.stringify(params)
debug('send %s', message)
this.socket.send(message)
}
_generateOffers (numwant, cb) {
const self = this
const offers = []
debug('generating %s offers', numwant)
for (let i = 0; i < numwant; ++i) {
generateOffer()
}
checkDone()
function generateOffer () {
const offerId = randombytes(20).toString('hex')
debug('creating peer (from _generateOffers)')
const peer = self.peers[offerId] = self._createPeer({ initiator: true })
peer.once('signal', offer => {
offers.push({
offer,
offer_id: common.hexToBinary(offerId)
})
checkDone()
})
peer.trackerTimeout = setTimeout(() => {
debug('tracker timeout: destroying peer')
peer.trackerTimeout = null
delete self.peers[offerId]
peer.destroy()
}, OFFER_TIMEOUT)
if (peer.trackerTimeout.unref) peer.trackerTimeout.unref()
}
function checkDone () {
if (offers.length === numwant) {
debug('generated %s offers', numwant)
cb(offers)
}
}
}
_createPeer (opts) {
const self = this
opts = Object.assign({
trickle: false,
config: self.client._rtcConfig,
wrtc: self.client._wrtc
}, opts)
const peer = new Peer(opts)
peer.once('error', onError)
peer.once('connect', onConnect)
return peer
// Handle peer 'error' events that are fired *before* the peer is emitted in
// a 'peer' event.
function onError (err) {
self.client.emit('warning', new Error(`Connection error: ${err.message}`))
peer.destroy()
}
// Once the peer is emitted in a 'peer' event, then it's the consumer's
// responsibility to listen for errors, so the listeners are removed here.
function onConnect () {
peer.removeListener('error', onError)
peer.removeListener('connect', onConnect)
}
}
}
WebSocketTracker.prototype.DEFAULT_ANNOUNCE_INTERVAL = 30 * 1000 // 30 seconds
// Normally this shouldn't be accessed but is occasionally useful
WebSocketTracker._socketPool = socketPool
function noop () {}
module.exports = WebSocketTracker
},{"../common":34,"./tracker":32,"debug":35,"randombytes":195,"simple-peer":223,"simple-websocket":244}],34:[function(require,module,exports){
(function (Buffer){(function (){
/**
* Functions/constants needed by both the client and server.
*/
exports.DEFAULT_ANNOUNCE_PEERS = 50
exports.MAX_ANNOUNCE_PEERS = 82
exports.binaryToHex = function (str) {
if (typeof str !== 'string') {
str = String(str)
}
return Buffer.from(str, 'binary').toString('hex')
}
exports.hexToBinary = function (str) {
if (typeof str !== 'string') {
str = String(str)
}
return Buffer.from(str, 'hex').toString('binary')
}
var config = require('./common-node')
Object.assign(exports, config)
}).call(this)}).call(this,require("buffer").Buffer)
},{"./common-node":55,"buffer":60}],35:[function(require,module,exports){
arguments[4][13][0].apply(exports,arguments)
},{"./common":36,"_process":187,"dup":13}],36:[function(require,module,exports){
arguments[4][14][0].apply(exports,arguments)
},{"dup":14,"ms":37}],37:[function(require,module,exports){
arguments[4][15][0].apply(exports,arguments)
},{"dup":15}],38:[function(require,module,exports){
(function (Buffer){(function (){
/*! blob-to-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/* global Blob, FileReader */
module.exports = function blobToBuffer (blob, cb) {
if (typeof Blob === 'undefined' || !(blob instanceof Blob)) {
throw new Error('first argument must be a Blob')
}
if (typeof cb !== 'function') {
throw new Error('second argument must be a function')
}
const reader = new FileReader()
function onLoadEnd (e) {
reader.removeEventListener('loadend', onLoadEnd, false)
if (e.error) cb(e.error)
else cb(null, Buffer.from(reader.result))
}
reader.addEventListener('loadend', onLoadEnd, false)
reader.readAsArrayBuffer(blob)
}
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60}],39:[function(require,module,exports){
(function (Buffer){(function (){
const { Transform } = require('readable-stream')
class Block extends Transform {
constructor (size, opts = {}) {
super(opts)
if (typeof size === 'object') {
opts = size
size = opts.size
}
this.size = size || 512
const { nopad, zeroPadding = true } = opts
if (nopad) this._zeroPadding = false
else this._zeroPadding = !!zeroPadding
this._buffered = []
this._bufferedBytes = 0
}
_transform (buf, enc, next) {
this._bufferedBytes += buf.length
this._buffered.push(buf)
while (this._bufferedBytes >= this.size) {
const b = Buffer.concat(this._buffered)
this._bufferedBytes -= this.size
this.push(b.slice(0, this.size))
this._buffered = [ b.slice(this.size, b.length) ]
}
next()
}
_flush () {
if (this._bufferedBytes && this._zeroPadding) {
const zeroes = Buffer.alloc(this.size - this._bufferedBytes)
this._buffered.push(zeroes)
this.push(Buffer.concat(this._buffered))
this._buffered = null
} else if (this._bufferedBytes) {
this.push(Buffer.concat(this._buffered))
this._buffered = null
}
this.push(null)
}
}
module.exports = Block
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60,"readable-stream":54}],40:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],41:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":43,"./_stream_writable":45,"_process":187,"dup":17,"inherits":119}],42:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":44,"dup":18,"inherits":119}],43:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":40,"./_stream_duplex":41,"./internal/streams/async_iterator":46,"./internal/streams/buffer_list":47,"./internal/streams/destroy":48,"./internal/streams/from":50,"./internal/streams/state":52,"./internal/streams/stream":53,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],44:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":40,"./_stream_duplex":41,"dup":20,"inherits":119}],45:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":40,"./_stream_duplex":41,"./internal/streams/destroy":48,"./internal/streams/state":52,"./internal/streams/stream":53,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],46:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":49,"_process":187,"dup":22}],47:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],48:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],49:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":40,"dup":25}],50:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],51:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":40,"./end-of-stream":49,"dup":27}],52:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":40,"dup":28}],53:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],54:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":41,"./lib/_stream_passthrough.js":42,"./lib/_stream_readable.js":43,"./lib/_stream_transform.js":44,"./lib/_stream_writable.js":45,"./lib/internal/streams/end-of-stream.js":49,"./lib/internal/streams/pipeline.js":51,"dup":30}],55:[function(require,module,exports){
},{}],56:[function(require,module,exports){
arguments[4][55][0].apply(exports,arguments)
},{"dup":55}],57:[function(require,module,exports){
(function (Buffer){(function (){
function allocUnsafe (size) {
if (typeof size !== 'number') {
throw new TypeError('"size" argument must be a number')
}
if (size < 0) {
throw new RangeError('"size" argument must not be negative')
}
if (Buffer.allocUnsafe) {
return Buffer.allocUnsafe(size)
} else {
return new Buffer(size)
}
}
module.exports = allocUnsafe
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60}],58:[function(require,module,exports){
(function (Buffer){(function (){
var bufferFill = require('buffer-fill')
var allocUnsafe = require('buffer-alloc-unsafe')
module.exports = function alloc (size, fill, encoding) {
if (typeof size !== 'number') {
throw new TypeError('"size" argument must be a number')
}
if (size < 0) {
throw new RangeError('"size" argument must not be negative')
}
if (Buffer.alloc) {
return Buffer.alloc(size, fill, encoding)
}
var buffer = allocUnsafe(size)
if (size === 0) {
return buffer
}
if (fill === undefined) {
return bufferFill(buffer, 0)
}
if (typeof encoding !== 'string') {
encoding = undefined
}
return bufferFill(buffer, fill, encoding)
}
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60,"buffer-alloc-unsafe":57,"buffer-fill":59}],59:[function(require,module,exports){
(function (Buffer){(function (){
/* Node.js 6.4.0 and up has full support */
var hasFullSupport = (function () {
try {
if (!Buffer.isEncoding('latin1')) {
return false
}
var buf = Buffer.alloc ? Buffer.alloc(4) : new Buffer(4)
buf.fill('ab', 'ucs2')
return (buf.toString('hex') === '61006200')
} catch (_) {
return false
}
}())
function isSingleByte (val) {
return (val.length === 1 && val.charCodeAt(0) < 256)
}
function fillWithNumber (buffer, val, start, end) {
if (start < 0 || end > buffer.length) {
throw new RangeError('Out of range index')
}
start = start >>> 0
end = end === undefined ? buffer.length : end >>> 0
if (end > start) {
buffer.fill(val, start, end)
}
return buffer
}
function fillWithBuffer (buffer, val, start, end) {
if (start < 0 || end > buffer.length) {
throw new RangeError('Out of range index')
}
if (end <= start) {
return buffer
}
start = start >>> 0
end = end === undefined ? buffer.length : end >>> 0
var pos = start
var len = val.length
while (pos <= (end - len)) {
val.copy(buffer, pos)
pos += len
}
if (pos !== end) {
val.copy(buffer, pos, 0, end - pos)
}
return buffer
}
function fill (buffer, val, start, end, encoding) {
if (hasFullSupport) {
return buffer.fill(val, start, end, encoding)
}
if (typeof val === 'number') {
return fillWithNumber(buffer, val, start, end)
}
if (typeof val === 'string') {
if (typeof start === 'string') {
encoding = start
start = 0
end = buffer.length
} else if (typeof end === 'string') {
encoding = end
end = buffer.length
}
if (encoding !== undefined && typeof encoding !== 'string') {
throw new TypeError('encoding must be a string')
}
if (encoding === 'latin1') {
encoding = 'binary'
}
if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
throw new TypeError('Unknown encoding: ' + encoding)
}
if (val === '') {
return fillWithNumber(buffer, 0, start, end)
}
if (isSingleByte(val)) {
return fillWithNumber(buffer, val.charCodeAt(0), start, end)
}
val = new Buffer(val, encoding)
}
if (Buffer.isBuffer(val)) {
return fillWithBuffer(buffer, val, start, end)
}
// Other values (e.g. undefined, boolean, object) results in zero-fill
return fillWithNumber(buffer, 0, start, end)
}
module.exports = fill
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60}],60:[function(require,module,exports){
(function (Buffer){(function (){
/*!
* 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
}
}
Object.defineProperty(Buffer.prototype, 'parent', {
enumerable: true,
get: function () {
if (!Buffer.isBuffer(this)) return undefined
return this.buffer
}
})
Object.defineProperty(Buffer.prototype, 'offset', {
enumerable: true,
get: function () {
if (!Buffer.isBuffer(this)) return undefined
return this.byteOffset
}
})
function createBuffer (length) {
if (length > K_MAX_LENGTH) {
throw new RangeError('The value "' + length + '" is invalid for option "size"')
}
// 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 TypeError(
'The "string" argument must be of type string. Received type number'
)
}
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 != null &&
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 === 'string') {
return fromString(value, encodingOrOffset)
}
if (ArrayBuffer.isView(value)) {
return fromArrayLike(value)
}
if (value == null) {
throw TypeError(
'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
'or Array-like Object. Received type ' + (typeof value)
)
}
if (isInstance(value, ArrayBuffer) ||
(value && isInstance(value.buffer, ArrayBuffer))) {
return fromArrayBuffer(value, encodingOrOffset, length)
}
if (typeof value === 'number') {
throw new TypeError(
'The "value" argument must not be of type number. Received type number'
)
}
var valueOf = value.valueOf && value.valueOf()
if (valueOf != null && valueOf !== value) {
return Buffer.from(valueOf, encodingOrOffset, length)
}
var b = fromObject(value)
if (b) return b
if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null &&
typeof value[Symbol.toPrimitive] === 'function') {
return Buffer.from(
value[Symbol.toPrimitive]('string'), encodingOrOffset, length
)
}
throw new TypeError(
'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
'or Array-like Object. Received type ' + (typeof 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 of type number')
} else if (size < 0) {
throw new RangeError('The value "' + size + '" is invalid for option "size"')
}
}
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('Unknown encoding: ' + 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 outside of buffer bounds')
}
if (array.byteLength < byteOffset + (length || 0)) {
throw new RangeError('"length" is outside of buffer 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.length !== undefined) {
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)
}
}
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 &&
b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false
}
Buffer.compare = function compare (a, b) {
if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength)
if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength)
if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
throw new TypeError(
'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array'
)
}
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 (isInstance(buf, Uint8Array)) {
buf = Buffer.from(buf)
}
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 (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) {
return string.byteLength
}
if (typeof string !== 'string') {
throw new TypeError(
'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' +
'Received type ' + typeof string
)
}
var len = string.length
var mustMatch = (arguments.length > 2 && arguments[2] === true)
if (!mustMatch && 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':
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 mustMatch ? -1 : 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.toLocaleString = Buffer.prototype.toString
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
str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim()
if (this.length > max) str += ' ... '
return '<Buffer ' + str + '>'
}
Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
if (isInstance(target, Uint8Array)) {
target = Buffer.from(target, target.offset, target.byteLength)
}
if (!Buffer.isBuffer(target)) {
throw new TypeError(
'The "target" argument must be one of type Buffer or Uint8Array. ' +
'Received type ' + (typeof target)
)
}
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
}
}
var strLen = string.length
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 (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer')
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('Index out of range')
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
if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') {
// Use built-in when available, missing from IE11
this.copyWithin(targetStart, start, end)
} else if (this === target && start < targetStart && targetStart < end) {
// descending copy from end
for (var i = len - 1; i >= 0; --i) {
target[i + targetStart] = this[i + start]
}
} else {
Uint8Array.prototype.set.call(
target,
this.subarray(start, end),
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 (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)
}
if (val.length === 1) {
var code = val.charCodeAt(0)
if ((encoding === 'utf8' && code < 128) ||
encoding === 'latin1') {
// Fast path: If `val` fits into a single byte, use that numeric value.
val = code
}
}
} 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
: Buffer.from(val, encoding)
var len = bytes.length
if (len === 0) {
throw new TypeError('The value "' + val +
'" is invalid for argument "value"')
}
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 takes equal signs as end of the Base64 encoding
str = str.split('=')[0]
// 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
}
// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass
// the `instanceof` check but they should be treated as of that type.
// See: https://github.com/feross/buffer/issues/166
function isInstance (obj, type) {
return obj instanceof type ||
(obj != null && obj.constructor != null && obj.constructor.name != null &&
obj.constructor.name === type.name)
}
function numberIsNaN (obj) {
// For IE11 support
return obj !== obj // eslint-disable-line no-self-compare
}
}).call(this)}).call(this,require("buffer").Buffer)
},{"base64-js":4,"buffer":60,"ieee754":117}],61:[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"
}
},{}],62:[function(require,module,exports){
/*!
* bytes
* Copyright(c) 2012-2014 TJ Holowaychuk
* Copyright(c) 2015 Jed Watson
* MIT Licensed
*/
'use strict';
/**
* Module exports.
* @public
*/
module.exports = bytes;
module.exports.format = format;
module.exports.parse = parse;
/**
* Module variables.
* @private
*/
var formatThousandsRegExp = /\B(?=(\d{3})+(?!\d))/g;
var formatDecimalsRegExp = /(?:\.0*|(\.[^0]+)0+)$/;
var map = {
b: 1,
kb: 1 << 10,
mb: 1 << 20,
gb: 1 << 30,
tb: Math.pow(1024, 4),
pb: Math.pow(1024, 5),
};
var parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb|pb)$/i;
/**
* Convert the given value in bytes into a string or parse to string to an integer in bytes.
*
* @param {string|number} value
* @param {{
* case: [string],
* decimalPlaces: [number]
* fixedDecimals: [boolean]
* thousandsSeparator: [string]
* unitSeparator: [string]
* }} [options] bytes options.
*
* @returns {string|number|null}
*/
function bytes(value, options) {
if (typeof value === 'string') {
return parse(value);
}
if (typeof value === 'number') {
return format(value, options);
}
return null;
}
/**
* Format the given value in bytes into a string.
*
* If the value is negative, it is kept as such. If it is a float,
* it is rounded.
*
* @param {number} value
* @param {object} [options]
* @param {number} [options.decimalPlaces=2]
* @param {number} [options.fixedDecimals=false]
* @param {string} [options.thousandsSeparator=]
* @param {string} [options.unit=]
* @param {string} [options.unitSeparator=]
*
* @returns {string|null}
* @public
*/
function format(value, options) {
if (!Number.isFinite(value)) {
return null;
}
var mag = Math.abs(value);
var thousandsSeparator = (options && options.thousandsSeparator) || '';
var unitSeparator = (options && options.unitSeparator) || '';
var decimalPlaces = (options && options.decimalPlaces !== undefined) ? options.decimalPlaces : 2;
var fixedDecimals = Boolean(options && options.fixedDecimals);
var unit = (options && options.unit) || '';
if (!unit || !map[unit.toLowerCase()]) {
if (mag >= map.pb) {
unit = 'PB';
} else if (mag >= map.tb) {
unit = 'TB';
} else if (mag >= map.gb) {
unit = 'GB';
} else if (mag >= map.mb) {
unit = 'MB';
} else if (mag >= map.kb) {
unit = 'KB';
} else {
unit = 'B';
}
}
var val = value / map[unit.toLowerCase()];
var str = val.toFixed(decimalPlaces);
if (!fixedDecimals) {
str = str.replace(formatDecimalsRegExp, '$1');
}
if (thousandsSeparator) {
str = str.replace(formatThousandsRegExp, thousandsSeparator);
}
return str + unitSeparator + unit;
}
/**
* Parse the string value into an integer in bytes.
*
* If no unit is given, it is assumed the value is in bytes.
*
* @param {number|string} val
*
* @returns {number|null}
* @public
*/
function parse(val) {
if (typeof val === 'number' && !isNaN(val)) {
return val;
}
if (typeof val !== 'string') {
return null;
}
// Test if the string passed is valid
var results = parseRegExp.exec(val);
var floatValue;
var unit = 'b';
if (!results) {
// Nothing could be extracted from the given string
floatValue = parseInt(val, 10);
unit = 'b'
} else {
// Retrieve the value and the unit
floatValue = parseFloat(results[1]);
unit = results[4].toLowerCase();
}
return Math.floor(map[unit] * floatValue);
}
},{}],63:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],64:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":66,"./_stream_writable":68,"_process":187,"dup":17,"inherits":119}],65:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":67,"dup":18,"inherits":119}],66:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":63,"./_stream_duplex":64,"./internal/streams/async_iterator":69,"./internal/streams/buffer_list":70,"./internal/streams/destroy":71,"./internal/streams/from":73,"./internal/streams/state":75,"./internal/streams/stream":76,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],67:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":63,"./_stream_duplex":64,"dup":20,"inherits":119}],68:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":63,"./_stream_duplex":64,"./internal/streams/destroy":71,"./internal/streams/state":75,"./internal/streams/stream":76,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],69:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":72,"_process":187,"dup":22}],70:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],71:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],72:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":63,"dup":25}],73:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],74:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":63,"./end-of-stream":72,"dup":27}],75:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":63,"dup":28}],76:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],77:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":64,"./lib/_stream_passthrough.js":65,"./lib/_stream_readable.js":66,"./lib/_stream_transform.js":67,"./lib/_stream_writable.js":68,"./lib/internal/streams/end-of-stream.js":72,"./lib/internal/streams/pipeline.js":74,"dup":30}],78:[function(require,module,exports){
const BlockStream = require('block-stream2')
const stream = require('readable-stream')
class ChunkStoreWriteStream extends stream.Writable {
constructor (store, chunkLength, opts = {}) {
super(opts)
if (!store || !store.put || !store.get) {
throw new Error('First argument must be an abstract-chunk-store compliant store')
}
chunkLength = Number(chunkLength)
if (!chunkLength) throw new Error('Second argument must be a chunk length')
this._blockstream = new BlockStream(chunkLength, { zeroPadding: false })
this._outstandingPuts = 0
let index = 0
const onData = chunk => {
if (this.destroyed) return
this._outstandingPuts += 1
store.put(index, chunk, () => {
this._outstandingPuts -= 1
if (this._outstandingPuts === 0 && typeof this._finalCb === 'function') {
this._finalCb(null)
this._finalCb = null
}
})
index += 1
}
this._blockstream
.on('data', onData)
.on('error', err => { this.destroy(err) })
}
_write (chunk, encoding, callback) {
this._blockstream.write(chunk, encoding, callback)
}
_final (cb) {
this._blockstream.end()
this._blockstream.once('end', () => {
if (this._outstandingPuts === 0) cb(null)
else this._finalCb = cb
})
}
destroy (err) {
if (this.destroyed) return
this.destroyed = true
if (err) this.emit('error', err)
this.emit('close')
}
}
module.exports = ChunkStoreWriteStream
},{"block-stream2":39,"readable-stream":77}],79:[function(require,module,exports){
/*!
* clipboard.js v2.0.6
* https://clipboardjs.com/
*
* Licensed MIT © Zeno Rocha
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["ClipboardJS"] = factory();
else
root["ClipboardJS"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 6);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
function select(element) {
var selectedText;
if (element.nodeName === 'SELECT') {
element.focus();
selectedText = element.value;
}
else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
var isReadOnly = element.hasAttribute('readonly');
if (!isReadOnly) {
element.setAttribute('readonly', '');
}
element.select();
element.setSelectionRange(0, element.value.length);
if (!isReadOnly) {
element.removeAttribute('readonly');
}
selectedText = element.value;
}
else {
if (element.hasAttribute('contenteditable')) {
element.focus();
}
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
selectedText = selection.toString();
}
return selectedText;
}
module.exports = select;
/***/ }),
/* 1 */
/***/ (function(module, exports) {
function E () {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
}
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener () {
self.off(name, listener);
callback.apply(ctx, arguments);
};
listener._ = callback
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
(liveEvents.length)
? e[name] = liveEvents
: delete e[name];
return this;
}
};
module.exports = E;
module.exports.TinyEmitter = E;
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
var is = __webpack_require__(3);
var delegate = __webpack_require__(4);
/**
* Validates all params and calls the right
* listener function based on its target type.
*
* @param {String|HTMLElement|HTMLCollection|NodeList} target
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listen(target, type, callback) {
if (!target && !type && !callback) {
throw new Error('Missing required arguments');
}
if (!is.string(type)) {
throw new TypeError('Second argument must be a String');
}
if (!is.fn(callback)) {
throw new TypeError('Third argument must be a Function');
}
if (is.node(target)) {
return listenNode(target, type, callback);
}
else if (is.nodeList(target)) {
return listenNodeList(target, type, callback);
}
else if (is.string(target)) {
return listenSelector(target, type, callback);
}
else {
throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');
}
}
/**
* Adds an event listener to a HTML element
* and returns a remove listener function.
*
* @param {HTMLElement} node
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenNode(node, type, callback) {
node.addEventListener(type, callback);
return {
destroy: function() {
node.removeEventListener(type, callback);
}
}
}
/**
* Add an event listener to a list of HTML elements
* and returns a remove listener function.
*
* @param {NodeList|HTMLCollection} nodeList
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenNodeList(nodeList, type, callback) {
Array.prototype.forEach.call(nodeList, function(node) {
node.addEventListener(type, callback);
});
return {
destroy: function() {
Array.prototype.forEach.call(nodeList, function(node) {
node.removeEventListener(type, callback);
});
}
}
}
/**
* Add an event listener to a selector
* and returns a remove listener function.
*
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenSelector(selector, type, callback) {
return delegate(document.body, selector, type, callback);
}
module.exports = listen;
/***/ }),
/* 3 */
/***/ (function(module, exports) {
/**
* Check if argument is a HTML element.
*
* @param {Object} value
* @return {Boolean}
*/
exports.node = function(value) {
return value !== undefined
&& value instanceof HTMLElement
&& value.nodeType === 1;
};
/**
* Check if argument is a list of HTML elements.
*
* @param {Object} value
* @return {Boolean}
*/
exports.nodeList = function(value) {
var type = Object.prototype.toString.call(value);
return value !== undefined
&& (type === '[object NodeList]' || type === '[object HTMLCollection]')
&& ('length' in value)
&& (value.length === 0 || exports.node(value[0]));
};
/**
* Check if argument is a string.
*
* @param {Object} value
* @return {Boolean}
*/
exports.string = function(value) {
return typeof value === 'string'
|| value instanceof String;
};
/**
* Check if argument is a function.
*
* @param {Object} value
* @return {Boolean}
*/
exports.fn = function(value) {
var type = Object.prototype.toString.call(value);
return type === '[object Function]';
};
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
var closest = __webpack_require__(5);
/**
* Delegates event to a selector.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @param {Boolean} useCapture
* @return {Object}
*/
function _delegate(element, selector, type, callback, useCapture) {
var listenerFn = listener.apply(this, arguments);
element.addEventListener(type, listenerFn, useCapture);
return {
destroy: function() {
element.removeEventListener(type, listenerFn, useCapture);
}
}
}
/**
* Delegates event to a selector.
*
* @param {Element|String|Array} [elements]
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @param {Boolean} useCapture
* @return {Object}
*/
function delegate(elements, selector, type, callback, useCapture) {
// Handle the regular Element usage
if (typeof elements.addEventListener === 'function') {
return _delegate.apply(null, arguments);
}
// Handle Element-less usage, it defaults to global delegation
if (typeof type === 'function') {
// Use `document` as the first parameter, then apply arguments
// This is a short way to .unshift `arguments` without running into deoptimizations
return _delegate.bind(null, document).apply(null, arguments);
}
// Handle Selector-based usage
if (typeof elements === 'string') {
elements = document.querySelectorAll(elements);
}
// Handle Array-like based usage
return Array.prototype.map.call(elements, function (element) {
return _delegate(element, selector, type, callback, useCapture);
});
}
/**
* Finds closest match and invokes callback.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Function}
*/
function listener(element, selector, type, callback) {
return function(e) {
e.delegateTarget = closest(e.target, selector);
if (e.delegateTarget) {
callback.call(element, e);
}
}
}
module.exports = delegate;
/***/ }),
/* 5 */
/***/ (function(module, exports) {
var DOCUMENT_NODE_TYPE = 9;
/**
* A polyfill for Element.matches()
*/
if (typeof Element !== 'undefined' && !Element.prototype.matches) {
var proto = Element.prototype;
proto.matches = proto.matchesSelector ||
proto.mozMatchesSelector ||
proto.msMatchesSelector ||
proto.oMatchesSelector ||
proto.webkitMatchesSelector;
}
/**
* Finds the closest parent that matches a selector.
*
* @param {Element} element
* @param {String} selector
* @return {Function}
*/
function closest (element, selector) {
while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {
if (typeof element.matches === 'function' &&
element.matches(selector)) {
return element;
}
element = element.parentNode;
}
}
module.exports = closest;
/***/ }),
/* 6 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
// EXTERNAL MODULE: ./node_modules/select/src/select.js
var src_select = __webpack_require__(0);
var select_default = /*#__PURE__*/__webpack_require__.n(src_select);
// CONCATENATED MODULE: ./src/clipboard-action.js
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Inner class which performs selection from either `text` or `target`
* properties and then executes copy or cut operations.
*/
var clipboard_action_ClipboardAction = function () {
/**
* @param {Object} options
*/
function ClipboardAction(options) {
_classCallCheck(this, ClipboardAction);
this.resolveOptions(options);
this.initSelection();
}
/**
* Defines base properties passed from constructor.
* @param {Object} options
*/
_createClass(ClipboardAction, [{
key: 'resolveOptions',
value: function resolveOptions() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
this.action = options.action;
this.container = options.container;
this.emitter = options.emitter;
this.target = options.target;
this.text = options.text;
this.trigger = options.trigger;
this.selectedText = '';
}
/**
* Decides which selection strategy is going to be applied based
* on the existence of `text` and `target` properties.
*/
}, {
key: 'initSelection',
value: function initSelection() {
if (this.text) {
this.selectFake();
} else if (this.target) {
this.selectTarget();
}
}
/**
* Creates a fake textarea element, sets its value from `text` property,
* and makes a selection on it.
*/
}, {
key: 'selectFake',
value: function selectFake() {
var _this = this;
var isRTL = document.documentElement.getAttribute('dir') == 'rtl';
this.removeFake();
this.fakeHandlerCallback = function () {
return _this.removeFake();
};
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;
this.fakeElem = document.createElement('textarea');
// Prevent zooming on iOS
this.fakeElem.style.fontSize = '12pt';
// Reset box model
this.fakeElem.style.border = '0';
this.fakeElem.style.padding = '0';
this.fakeElem.style.margin = '0';
// Move element out of screen horizontally
this.fakeElem.style.position = 'absolute';
this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px';
// Move element to the same position vertically
var yPosition = window.pageYOffset || document.documentElement.scrollTop;
this.fakeElem.style.top = yPosition + 'px';
this.fakeElem.setAttribute('readonly', '');
this.fakeElem.value = this.text;
this.container.appendChild(this.fakeElem);
this.selectedText = select_default()(this.fakeElem);
this.copyText();
}
/**
* Only removes the fake element after another click event, that way
* a user can hit `Ctrl+C` to copy because selection still exists.
*/
}, {
key: 'removeFake',
value: function removeFake() {
if (this.fakeHandler) {
this.container.removeEventListener('click', this.fakeHandlerCallback);
this.fakeHandler = null;
this.fakeHandlerCallback = null;
}
if (this.fakeElem) {
this.container.removeChild(this.fakeElem);
this.fakeElem = null;
}
}
/**
* Selects the content from element passed on `target` property.
*/
}, {
key: 'selectTarget',
value: function selectTarget() {
this.selectedText = select_default()(this.target);
this.copyText();
}
/**
* Executes the copy operation based on the current selection.
*/
}, {
key: 'copyText',
value: function copyText() {
var succeeded = void 0;
try {
succeeded = document.execCommand(this.action);
} catch (err) {
succeeded = false;
}
this.handleResult(succeeded);
}
/**
* Fires an event based on the copy operation result.
* @param {Boolean} succeeded
*/
}, {
key: 'handleResult',
value: function handleResult(succeeded) {
this.emitter.emit(succeeded ? 'success' : 'error', {
action: this.action,
text: this.selectedText,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
});
}
/**
* Moves focus away from `target` and back to the trigger, removes current selection.
*/
}, {
key: 'clearSelection',
value: function clearSelection() {
if (this.trigger) {
this.trigger.focus();
}
document.activeElement.blur();
window.getSelection().removeAllRanges();
}
/**
* Sets the `action` to be performed which can be either 'copy' or 'cut'.
* @param {String} action
*/
}, {
key: 'destroy',
/**
* Destroy lifecycle.
*/
value: function destroy() {
this.removeFake();
}
}, {
key: 'action',
set: function set() {
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy';
this._action = action;
if (this._action !== 'copy' && this._action !== 'cut') {
throw new Error('Invalid "action" value, use either "copy" or "cut"');
}
}
/**
* Gets the `action` property.
* @return {String}
*/
,
get: function get() {
return this._action;
}
/**
* Sets the `target` property using an element
* that will be have its content copied.
* @param {Element} target
*/
}, {
key: 'target',
set: function set(target) {
if (target !== undefined) {
if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) {
if (this.action === 'copy' && target.hasAttribute('disabled')) {
throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');
}
if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {
throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');
}
this._target = target;
} else {
throw new Error('Invalid "target" value, use a valid Element');
}
}
}
/**
* Gets the `target` property.
* @return {String|HTMLElement}
*/
,
get: function get() {
return this._target;
}
}]);
return ClipboardAction;
}();
/* harmony default export */ var clipboard_action = (clipboard_action_ClipboardAction);
// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js
var tiny_emitter = __webpack_require__(1);
var tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);
// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js
var listen = __webpack_require__(2);
var listen_default = /*#__PURE__*/__webpack_require__.n(listen);
// CONCATENATED MODULE: ./src/clipboard.js
var clipboard_typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var clipboard_createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function clipboard_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/**
* Base class which takes one or more elements, adds event listeners to them,
* and instantiates a new `ClipboardAction` on each click.
*/
var clipboard_Clipboard = function (_Emitter) {
_inherits(Clipboard, _Emitter);
/**
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
* @param {Object} options
*/
function Clipboard(trigger, options) {
clipboard_classCallCheck(this, Clipboard);
var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this));
_this.resolveOptions(options);
_this.listenClick(trigger);
return _this;
}
/**
* Defines if attributes would be resolved using internal setter functions
* or custom functions that were passed in the constructor.
* @param {Object} options
*/
clipboard_createClass(Clipboard, [{
key: 'resolveOptions',
value: function resolveOptions() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
this.action = typeof options.action === 'function' ? options.action : this.defaultAction;
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;
this.text = typeof options.text === 'function' ? options.text : this.defaultText;
this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;
}
/**
* Adds a click event listener to the passed trigger.
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
*/
}, {
key: 'listenClick',
value: function listenClick(trigger) {
var _this2 = this;
this.listener = listen_default()(trigger, 'click', function (e) {
return _this2.onClick(e);
});
}
/**
* Defines a new `ClipboardAction` on each click event.
* @param {Event} e
*/
}, {
key: 'onClick',
value: function onClick(e) {
var trigger = e.delegateTarget || e.currentTarget;
if (this.clipboardAction) {
this.clipboardAction = null;
}
this.clipboardAction = new clipboard_action({
action: this.action(trigger),
target: this.target(trigger),
text: this.text(trigger),
container: this.container,
trigger: trigger,
emitter: this
});
}
/**
* Default `action` lookup function.
* @param {Element} trigger
*/
}, {
key: 'defaultAction',
value: function defaultAction(trigger) {
return getAttributeValue('action', trigger);
}
/**
* Default `target` lookup function.
* @param {Element} trigger
*/
}, {
key: 'defaultTarget',
value: function defaultTarget(trigger) {
var selector = getAttributeValue('target', trigger);
if (selector) {
return document.querySelector(selector);
}
}
/**
* Returns the support of the given action, or all actions if no action is
* given.
* @param {String} [action]
*/
}, {
key: 'defaultText',
/**
* Default `text` lookup function.
* @param {Element} trigger
*/
value: function defaultText(trigger) {
return getAttributeValue('text', trigger);
}
/**
* Destroy lifecycle.
*/
}, {
key: 'destroy',
value: function destroy() {
this.listener.destroy();
if (this.clipboardAction) {
this.clipboardAction.destroy();
this.clipboardAction = null;
}
}
}], [{
key: 'isSupported',
value: function isSupported() {
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];
var actions = typeof action === 'string' ? [action] : action;
var support = !!document.queryCommandSupported;
actions.forEach(function (action) {
support = support && !!document.queryCommandSupported(action);
});
return support;
}
}]);
return Clipboard;
}(tiny_emitter_default.a);
/**
* Helper function to retrieve attribute value.
* @param {String} suffix
* @param {Element} element
*/
function getAttributeValue(suffix, element) {
var attribute = 'data-clipboard-' + suffix;
if (!element.hasAttribute(attribute)) {
return;
}
return element.getAttribute(attribute);
}
/* harmony default export */ var clipboard = __webpack_exports__["default"] = (clipboard_Clipboard);
/***/ })
/******/ ])["default"];
});
},{}],80:[function(require,module,exports){
(function (process,global,Buffer){(function (){
/*! create-torrent. MIT License. WebTorrent LLC <https://webtorrent.io/opensource> */
const bencode = require('bencode')
const BlockStream = require('block-stream2')
const calcPieceLength = require('piece-length')
const corePath = require('path')
const FileReadStream = require('filestream/read')
const isFile = require('is-file')
const junk = require('junk')
const MultiStream = require('multistream')
const once = require('once')
const parallel = require('run-parallel')
const sha1 = require('simple-sha1')
const stream = require('readable-stream')
const getFiles = require('./get-files') // browser exclude
// TODO: When Node 10 support is dropped, replace this with Array.prototype.flat
function flat (arr1) {
return arr1.reduce(
(acc, val) => Array.isArray(val)
? acc.concat(flat(val))
: acc.concat(val),
[]
)
}
const announceList = [
['udp://tracker.leechers-paradise.org:6969'],
['udp://tracker.coppersurfer.tk:6969'],
['udp://tracker.opentrackr.org:1337'],
['udp://explodie.org:6969'],
['udp://tracker.empire-js.us:1337'],
['wss://tracker.btorrent.xyz'],
['wss://tracker.openwebtorrent.com']
]
/**
* Create a torrent.
* @param {string|File|FileList|Buffer|Stream|Array.<string|File|Buffer|Stream>} input
* @param {Object} opts
* @param {string=} opts.name
* @param {Date=} opts.creationDate
* @param {string=} opts.comment
* @param {string=} opts.createdBy
* @param {boolean|number=} opts.private
* @param {number=} opts.pieceLength
* @param {Array.<Array.<string>>=} opts.announceList
* @param {Array.<string>=} opts.urlList
* @param {Object=} opts.info
* @param {function} cb
* @return {Buffer} buffer of .torrent file data
*/
function createTorrent (input, opts, cb) {
if (typeof opts === 'function') [opts, cb] = [cb, opts]
opts = opts ? Object.assign({}, opts) : {}
_parseInput(input, opts, (err, files, singleFileTorrent) => {
if (err) return cb(err)
opts.singleFileTorrent = singleFileTorrent
onFiles(files, opts, cb)
})
}
function parseInput (input, opts, cb) {
if (typeof opts === 'function') [opts, cb] = [cb, opts]
opts = opts ? Object.assign({}, opts) : {}
_parseInput(input, opts, cb)
}
/**
* Parse input file and return file information.
*/
function _parseInput (input, opts, cb) {
if (isFileList(input)) input = Array.from(input)
if (!Array.isArray(input)) input = [input]
if (input.length === 0) throw new Error('invalid input type')
input.forEach(item => {
if (item == null) throw new Error(`invalid input type: ${item}`)
})
// In Electron, use the true file path
input = input.map(item => {
if (isBlob(item) && typeof item.path === 'string' && typeof getFiles === 'function') return item.path
return item
})
// If there's just one file, allow the name to be set by `opts.name`
if (input.length === 1 && typeof input[0] !== 'string' && !input[0].name) input[0].name = opts.name
let commonPrefix = null
input.forEach((item, i) => {
if (typeof item === 'string') {
return
}
let path = item.fullPath || item.name
if (!path) {
path = `Unknown File ${i + 1}`
item.unknownName = true
}
item.path = path.split('/')
// Remove initial slash
if (!item.path[0]) {
item.path.shift()
}
if (item.path.length < 2) { // No real prefix
commonPrefix = null
} else if (i === 0 && input.length > 1) { // The first file has a prefix
commonPrefix = item.path[0]
} else if (item.path[0] !== commonPrefix) { // The prefix doesn't match
commonPrefix = null
}
})
// remove junk files
input = input.filter(item => {
if (typeof item === 'string') {
return true
}
const filename = item.path[item.path.length - 1]
return notHidden(filename) && junk.not(filename)
})
if (commonPrefix) {
input.forEach(item => {
const pathless = (Buffer.isBuffer(item) || isReadable(item)) && !item.path
if (typeof item === 'string' || pathless) return
item.path.shift()
})
}
if (!opts.name && commonPrefix) {
opts.name = commonPrefix
}
if (!opts.name) {
// use first user-set file name
input.some(item => {
if (typeof item === 'string') {
opts.name = corePath.basename(item)
return true
} else if (!item.unknownName) {
opts.name = item.path[item.path.length - 1]
return true
}
})
}
if (!opts.name) {
opts.name = `Unnamed Torrent ${Date.now()}`
}
const numPaths = input.reduce((sum, item) => sum + Number(typeof item === 'string'), 0)
let isSingleFileTorrent = (input.length === 1)
if (input.length === 1 && typeof input[0] === 'string') {
if (typeof getFiles !== 'function') {
throw new Error('filesystem paths do not work in the browser')
}
// If there's a single path, verify it's a file before deciding this is a single
// file torrent
isFile(input[0], (err, pathIsFile) => {
if (err) return cb(err)
isSingleFileTorrent = pathIsFile
processInput()
})
} else {
process.nextTick(() => {
processInput()
})
}
function processInput () {
parallel(input.map(item => cb => {
const file = {}
if (isBlob(item)) {
file.getStream = getBlobStream(item)
file.length = item.size
} else if (Buffer.isBuffer(item)) {
file.getStream = getBufferStream(item)
file.length = item.length
} else if (isReadable(item)) {
file.getStream = getStreamStream(item, file)
file.length = 0
} else if (typeof item === 'string') {
if (typeof getFiles !== 'function') {
throw new Error('filesystem paths do not work in the browser')
}
const keepRoot = numPaths > 1 || isSingleFileTorrent
getFiles(item, keepRoot, cb)
return // early return!
} else {
throw new Error('invalid input type')
}
file.path = item.path
cb(null, file)
}), (err, files) => {
if (err) return cb(err)
files = flat(files)
cb(null, files, isSingleFileTorrent)
})
}
}
function notHidden (file) {
return file[0] !== '.'
}
function getPieceList (files, pieceLength, cb) {
cb = once(cb)
const pieces = []
let length = 0
const streams = files.map(file => file.getStream)
let remainingHashes = 0
let pieceNum = 0
let ended = false
const multistream = new MultiStream(streams)
const blockstream = new BlockStream(pieceLength, { zeroPadding: false })
multistream.on('error', onError)
multistream
.pipe(blockstream)
.on('data', onData)
.on('end', onEnd)
.on('error', onError)
function onData (chunk) {
length += chunk.length
const i = pieceNum
sha1(chunk, hash => {
pieces[i] = hash
remainingHashes -= 1
maybeDone()
})
remainingHashes += 1
pieceNum += 1
}
function onEnd () {
ended = true
maybeDone()
}
function onError (err) {
cleanup()
cb(err)
}
function cleanup () {
multistream.removeListener('error', onError)
blockstream.removeListener('data', onData)
blockstream.removeListener('end', onEnd)
blockstream.removeListener('error', onError)
}
function maybeDone () {
if (ended && remainingHashes === 0) {
cleanup()
cb(null, Buffer.from(pieces.join(''), 'hex'), length)
}
}
}
function onFiles (files, opts, cb) {
let announceList = opts.announceList
if (!announceList) {
if (typeof opts.announce === 'string') announceList = [[opts.announce]]
else if (Array.isArray(opts.announce)) {
announceList = opts.announce.map(u => [u])
}
}
if (!announceList) announceList = []
if (global.WEBTORRENT_ANNOUNCE) {
if (typeof global.WEBTORRENT_ANNOUNCE === 'string') {
announceList.push([[global.WEBTORRENT_ANNOUNCE]])
} else if (Array.isArray(global.WEBTORRENT_ANNOUNCE)) {
announceList = announceList.concat(global.WEBTORRENT_ANNOUNCE.map(u => [u]))
}
}
// When no trackers specified, use some reasonable defaults
if (opts.announce === undefined && opts.announceList === undefined) {
announceList = announceList.concat(module.exports.announceList)
}
if (typeof opts.urlList === 'string') opts.urlList = [opts.urlList]
const torrent = {
info: {
name: opts.name
},
'creation date': Math.ceil((Number(opts.creationDate) || Date.now()) / 1000),
encoding: 'UTF-8'
}
if (announceList.length !== 0) {
torrent.announce = announceList[0][0]
torrent['announce-list'] = announceList
}
if (opts.comment !== undefined) torrent.comment = opts.comment
if (opts.createdBy !== undefined) torrent['created by'] = opts.createdBy
if (opts.private !== undefined) torrent.info.private = Number(opts.private)
if (opts.info !== undefined) Object.assign(torrent.info, opts.info)
// "ssl-cert" key is for SSL torrents, see:
// - http://blog.libtorrent.org/2012/01/bittorrent-over-ssl/
// - http://www.libtorrent.org/manual-ref.html#ssl-torrents
// - http://www.libtorrent.org/reference-Create_Torrents.html
if (opts.sslCert !== undefined) torrent.info['ssl-cert'] = opts.sslCert
if (opts.urlList !== undefined) torrent['url-list'] = opts.urlList
const pieceLength = opts.pieceLength || calcPieceLength(files.reduce(sumLength, 0))
torrent.info['piece length'] = pieceLength
getPieceList(files, pieceLength, (err, pieces, torrentLength) => {
if (err) return cb(err)
torrent.info.pieces = pieces
files.forEach(file => {
delete file.getStream
})
if (opts.singleFileTorrent) {
torrent.info.length = torrentLength
} else {
torrent.info.files = files
}
cb(null, bencode.encode(torrent))
})
}
/**
* Accumulator to sum file lengths
* @param {number} sum
* @param {Object} file
* @return {number}
*/
function sumLength (sum, file) {
return sum + file.length
}
/**
* Check if `obj` is a W3C `Blob` object (which `File` inherits from)
* @param {*} obj
* @return {boolean}
*/
function isBlob (obj) {
return typeof Blob !== 'undefined' && obj instanceof Blob
}
/**
* Check if `obj` is a W3C `FileList` object
* @param {*} obj
* @return {boolean}
*/
function isFileList (obj) {
return typeof FileList !== 'undefined' && obj instanceof FileList
}
/**
* Check if `obj` is a node Readable stream
* @param {*} obj
* @return {boolean}
*/
function isReadable (obj) {
return typeof obj === 'object' && obj != null && typeof obj.pipe === 'function'
}
/**
* Convert a `File` to a lazy readable stream.
* @param {File|Blob} file
* @return {function}
*/
function getBlobStream (file) {
return () => new FileReadStream(file)
}
/**
* Convert a `Buffer` to a lazy readable stream.
* @param {Buffer} buffer
* @return {function}
*/
function getBufferStream (buffer) {
return () => {
const s = new stream.PassThrough()
s.end(buffer)
return s
}
}
/**
* Convert a readable stream to a lazy readable stream. Adds instrumentation to track
* the number of bytes in the stream and set `file.length`.
*
* @param {Stream} readable
* @param {Object} file
* @return {function}
*/
function getStreamStream (readable, file) {
return () => {
const counter = new stream.Transform()
counter._transform = function (buf, enc, done) {
file.length += buf.length
this.push(buf)
done()
}
readable.pipe(counter)
return counter
}
}
module.exports = createTorrent
module.exports.parseInput = parseInput
module.exports.announceList = announceList
}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
},{"./get-files":55,"_process":187,"bencode":7,"block-stream2":39,"buffer":60,"filestream/read":114,"is-file":121,"junk":123,"multistream":166,"once":183,"path":185,"piece-length":186,"readable-stream":95,"run-parallel":218,"simple-sha1":242}],81:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],82:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":84,"./_stream_writable":86,"_process":187,"dup":17,"inherits":119}],83:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":85,"dup":18,"inherits":119}],84:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":81,"./_stream_duplex":82,"./internal/streams/async_iterator":87,"./internal/streams/buffer_list":88,"./internal/streams/destroy":89,"./internal/streams/from":91,"./internal/streams/state":93,"./internal/streams/stream":94,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],85:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":81,"./_stream_duplex":82,"dup":20,"inherits":119}],86:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":81,"./_stream_duplex":82,"./internal/streams/destroy":89,"./internal/streams/state":93,"./internal/streams/stream":94,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],87:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":90,"_process":187,"dup":22}],88:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],89:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],90:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":81,"dup":25}],91:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],92:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":81,"./end-of-stream":90,"dup":27}],93:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":81,"dup":28}],94:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],95:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":82,"./lib/_stream_passthrough.js":83,"./lib/_stream_readable.js":84,"./lib/_stream_transform.js":85,"./lib/_stream_writable.js":86,"./lib/internal/streams/end-of-stream.js":90,"./lib/internal/streams/pipeline.js":92,"dup":30}],96:[function(require,module,exports){
var once = require('once');
var noop = function() {};
var isRequest = function(stream) {
return stream.setHeader && typeof stream.abort === 'function';
};
var isChildProcess = function(stream) {
return stream.stdio && Array.isArray(stream.stdio) && stream.stdio.length === 3
};
var eos = function(stream, opts, callback) {
if (typeof opts === 'function') return eos(stream, null, opts);
if (!opts) opts = {};
callback = once(callback || noop);
var ws = stream._writableState;
var rs = stream._readableState;
var readable = opts.readable || (opts.readable !== false && stream.readable);
var writable = opts.writable || (opts.writable !== false && stream.writable);
var onlegacyfinish = function() {
if (!stream.writable) onfinish();
};
var onfinish = function() {
writable = false;
if (!readable) callback.call(stream);
};
var onend = function() {
readable = false;
if (!writable) callback.call(stream);
};
var onexit = function(exitCode) {
callback.call(stream, exitCode ? new Error('exited with error code: ' + exitCode) : null);
};
var onerror = function(err) {
callback.call(stream, err);
};
var onclose = function() {
if (readable && !(rs && rs.ended)) return callback.call(stream, new Error('premature close'));
if (writable && !(ws && ws.ended)) return callback.call(stream, new Error('premature close'));
};
var onrequest = function() {
stream.req.on('finish', onfinish);
};
if (isRequest(stream)) {
stream.on('complete', onfinish);
stream.on('abort', onclose);
if (stream.req) onrequest();
else stream.on('request', onrequest);
} else if (writable && !ws) { // legacy streams
stream.on('end', onlegacyfinish);
stream.on('close', onlegacyfinish);
}
if (isChildProcess(stream)) stream.on('exit', onexit);
stream.on('end', onend);
stream.on('finish', onfinish);
if (opts.error !== false) stream.on('error', onerror);
stream.on('close', onclose);
return function() {
stream.removeListener('complete', onfinish);
stream.removeListener('abort', onclose);
stream.removeListener('request', onrequest);
if (stream.req) stream.req.removeListener('finish', onfinish);
stream.removeListener('end', onlegacyfinish);
stream.removeListener('close', onlegacyfinish);
stream.removeListener('finish', onfinish);
stream.removeListener('exit', onexit);
stream.removeListener('end', onend);
stream.removeListener('error', onerror);
stream.removeListener('close', onclose);
};
};
module.exports = eos;
},{"once":183}],97:[function(require,module,exports){
'use strict';
function assign(obj, props) {
for (const key in props) {
Object.defineProperty(obj, key, {
value: props[key],
enumerable: true,
configurable: true,
});
}
return obj;
}
function createError(err, code, props) {
if (!err || typeof err === 'string') {
throw new TypeError('Please pass an Error to err-code');
}
if (!props) {
props = {};
}
if (typeof code === 'object') {
props = code;
code = undefined;
}
if (code != null) {
props.code = code;
}
try {
return assign(err, props);
} catch (_) {
props.message = err.message;
props.stack = err.stack;
const ErrClass = function () {};
ErrClass.prototype = Object.create(Object.getPrototypeOf(err));
return assign(new ErrClass(), props);
}
}
module.exports = createError;
},{}],98:[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 R = typeof Reflect === 'object' ? Reflect : null
var ReflectApply = R && typeof R.apply === 'function'
? R.apply
: function ReflectApply(target, receiver, args) {
return Function.prototype.apply.call(target, receiver, args);
}
var ReflectOwnKeys
if (R && typeof R.ownKeys === 'function') {
ReflectOwnKeys = R.ownKeys
} else if (Object.getOwnPropertySymbols) {
ReflectOwnKeys = function ReflectOwnKeys(target) {
return Object.getOwnPropertyNames(target)
.concat(Object.getOwnPropertySymbols(target));
};
} else {
ReflectOwnKeys = function ReflectOwnKeys(target) {
return Object.getOwnPropertyNames(target);
};
}
function ProcessEmitWarning(warning) {
if (console && console.warn) console.warn(warning);
}
var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
return value !== value;
}
function EventEmitter() {
EventEmitter.init.call(this);
}
module.exports = EventEmitter;
module.exports.once = once;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._eventsCount = 0;
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.
var defaultMaxListeners = 10;
function checkListener(listener) {
if (typeof listener !== 'function') {
throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
}
}
Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
enumerable: true,
get: function() {
return defaultMaxListeners;
},
set: function(arg) {
if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
}
defaultMaxListeners = arg;
}
});
EventEmitter.init = function() {
if (this._events === undefined ||
this._events === Object.getPrototypeOf(this)._events) {
this._events = Object.create(null);
this._eventsCount = 0;
}
this._maxListeners = this._maxListeners || undefined;
};
// 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 setMaxListeners(n) {
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
}
this._maxListeners = n;
return this;
};
function _getMaxListeners(that) {
if (that._maxListeners === undefined)
return EventEmitter.defaultMaxListeners;
return that._maxListeners;
}
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
return _getMaxListeners(this);
};
EventEmitter.prototype.emit = function emit(type) {
var args = [];
for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
var doError = (type === 'error');
var events = this._events;
if (events !== undefined)
doError = (doError && events.error === undefined);
else if (!doError)
return false;
// If there is no 'error' event listener then throw.
if (doError) {
var er;
if (args.length > 0)
er = args[0];
if (er instanceof Error) {
// Note: The comments on the `throw` lines are intentional, they show
// up in Node's output if this results in an unhandled exception.
throw er; // Unhandled 'error' event
}
// At least give some kind of context to the user
var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
err.context = er;
throw err; // Unhandled 'error' event
}
var handler = events[type];
if (handler === undefined)
return false;
if (typeof handler === 'function') {
ReflectApply(handler, this, args);
} else {
var len = handler.length;
var listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i)
ReflectApply(listeners[i], this, args);
}
return true;
};
function _addListener(target, type, listener, prepend) {
var m;
var events;
var existing;
checkListener(listener);
events = target._events;
if (events === undefined) {
events = target._events = Object.create(null);
target._eventsCount = 0;
} else {
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (events.newListener !== undefined) {
target.emit('newListener', type,
listener.listener ? listener.listener : listener);
// Re-assign `events` because a newListener handler could have caused the
// this._events to be assigned to a new object
events = target._events;
}
existing = events[type];
}
if (existing === undefined) {
// Optimize the case of one listener. Don't need the extra array object.
existing = events[type] = listener;
++target._eventsCount;
} else {
if (typeof existing === 'function') {
// Adding the second element, need to change to array.
existing = events[type] =
prepend ? [listener, existing] : [existing, listener];
// If we've already got an array, just append.
} else if (prepend) {
existing.unshift(listener);
} else {
existing.push(listener);
}
// Check for listener leak
m = _getMaxListeners(target);
if (m > 0 && existing.length > m && !existing.warned) {
existing.warned = true;
// No error code for this since it is a Warning
// eslint-disable-next-line no-restricted-syntax
var w = new Error('Possible EventEmitter memory leak detected. ' +
existing.length + ' ' + String(type) + ' listeners ' +
'added. Use emitter.setMaxListeners() to ' +
'increase limit');
w.name = 'MaxListenersExceededWarning';
w.emitter = target;
w.type = type;
w.count = existing.length;
ProcessEmitWarning(w);
}
}
return target;
}
EventEmitter.prototype.addListener = function addListener(type, listener) {
return _addListener(this, type, listener, false);
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.prependListener =
function prependListener(type, listener) {
return _addListener(this, type, listener, true);
};
function onceWrapper() {
if (!this.fired) {
this.target.removeListener(this.type, this.wrapFn);
this.fired = true;
if (arguments.length === 0)
return this.listener.call(this.target);
return this.listener.apply(this.target, arguments);
}
}
function _onceWrap(target, type, listener) {
var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
var wrapped = onceWrapper.bind(state);
wrapped.listener = listener;
state.wrapFn = wrapped;
return wrapped;
}
EventEmitter.prototype.once = function once(type, listener) {
checkListener(listener);
this.on(type, _onceWrap(this, type, listener));
return this;
};
EventEmitter.prototype.prependOnceListener =
function prependOnceListener(type, listener) {
checkListener(listener);
this.prependListener(type, _onceWrap(this, type, listener));
return this;
};
// Emits a 'removeListener' event if and only if the listener was removed.
EventEmitter.prototype.removeListener =
function removeListener(type, listener) {
var list, events, position, i, originalListener;
checkListener(listener);
events = this._events;
if (events === undefined)
return this;
list = events[type];
if (list === undefined)
return this;
if (list === listener || list.listener === listener) {
if (--this._eventsCount === 0)
this._events = Object.create(null);
else {
delete events[type];
if (events.removeListener)
this.emit('removeListener', type, list.listener || listener);
}
} else if (typeof list !== 'function') {
position = -1;
for (i = list.length - 1; i >= 0; i--) {
if (list[i] === listener || list[i].listener === listener) {
originalListener = list[i].listener;
position = i;
break;
}
}
if (position < 0)
return this;
if (position === 0)
list.shift();
else {
spliceOne(list, position);
}
if (list.length === 1)
events[type] = list[0];
if (events.removeListener !== undefined)
this.emit('removeListener', type, originalListener || listener);
}
return this;
};
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
EventEmitter.prototype.removeAllListeners =
function removeAllListeners(type) {
var listeners, events, i;
events = this._events;
if (events === undefined)
return this;
// not listening for removeListener, no need to emit
if (events.removeListener === undefined) {
if (arguments.length === 0) {
this._events = Object.create(null);
this._eventsCount = 0;
} else if (events[type] !== undefined) {
if (--this._eventsCount === 0)
this._events = Object.create(null);
else
delete events[type];
}
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
var keys = Object.keys(events);
var key;
for (i = 0; i < keys.length; ++i) {
key = keys[i];
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = Object.create(null);
this._eventsCount = 0;
return this;
}
listeners = events[type];
if (typeof listeners === 'function') {
this.removeListener(type, listeners);
} else if (listeners !== undefined) {
// LIFO order
for (i = listeners.length - 1; i >= 0; i--) {
this.removeListener(type, listeners[i]);
}
}
return this;
};
function _listeners(target, type, unwrap) {
var events = target._events;
if (events === undefined)
return [];
var evlistener = events[type];
if (evlistener === undefined)
return [];
if (typeof evlistener === 'function')
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
return unwrap ?
unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
}
EventEmitter.prototype.listeners = function listeners(type) {
return _listeners(this, type, true);
};
EventEmitter.prototype.rawListeners = function rawListeners(type) {
return _listeners(this, type, false);
};
EventEmitter.listenerCount = function(emitter, type) {
if (typeof emitter.listenerCount === 'function') {
return emitter.listenerCount(type);
} else {
return listenerCount.call(emitter, type);
}
};
EventEmitter.prototype.listenerCount = listenerCount;
function listenerCount(type) {
var events = this._events;
if (events !== undefined) {
var evlistener = events[type];
if (typeof evlistener === 'function') {
return 1;
} else if (evlistener !== undefined) {
return evlistener.length;
}
}
return 0;
}
EventEmitter.prototype.eventNames = function eventNames() {
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
};
function arrayClone(arr, n) {
var copy = new Array(n);
for (var i = 0; i < n; ++i)
copy[i] = arr[i];
return copy;
}
function spliceOne(list, index) {
for (; index + 1 < list.length; index++)
list[index] = list[index + 1];
list.pop();
}
function unwrapListeners(arr) {
var ret = new Array(arr.length);
for (var i = 0; i < ret.length; ++i) {
ret[i] = arr[i].listener || arr[i];
}
return ret;
}
function once(emitter, name) {
return new Promise(function (resolve, reject) {
function eventListener() {
if (errorListener !== undefined) {
emitter.removeListener('error', errorListener);
}
resolve([].slice.call(arguments));
};
var errorListener;
// Adding an error listener is not optional because
// if an error is thrown on an event emitter we cannot
// guarantee that the actual event we are waiting will
// be fired. The result could be a silent way to create
// memory or file descriptor leaks, which is something
// we should avoid.
if (name !== 'error') {
errorListener = function errorListener(err) {
emitter.removeListener(name, eventListener);
reject(err);
};
emitter.once('error', errorListener);
}
emitter.once(name, eventListener);
});
}
},{}],99:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],100:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":102,"./_stream_writable":104,"_process":187,"dup":17,"inherits":119}],101:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":103,"dup":18,"inherits":119}],102:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":99,"./_stream_duplex":100,"./internal/streams/async_iterator":105,"./internal/streams/buffer_list":106,"./internal/streams/destroy":107,"./internal/streams/from":109,"./internal/streams/state":111,"./internal/streams/stream":112,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],103:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":99,"./_stream_duplex":100,"dup":20,"inherits":119}],104:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":99,"./_stream_duplex":100,"./internal/streams/destroy":107,"./internal/streams/state":111,"./internal/streams/stream":112,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],105:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":108,"_process":187,"dup":22}],106:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],107:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],108:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":99,"dup":25}],109:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],110:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":99,"./end-of-stream":108,"dup":27}],111:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":99,"dup":28}],112:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],113:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":100,"./lib/_stream_passthrough.js":101,"./lib/_stream_readable.js":102,"./lib/_stream_transform.js":103,"./lib/_stream_writable.js":104,"./lib/internal/streams/end-of-stream.js":108,"./lib/internal/streams/pipeline.js":110,"dup":30}],114:[function(require,module,exports){
/* global FileReader */
const { Readable } = require('readable-stream')
const toBuffer = require('typedarray-to-buffer')
class FileReadStream extends Readable {
constructor (file, opts = {}) {
super(opts)
// save the read offset
this._offset = 0
this._ready = false
this._file = file
this._size = file.size
this._chunkSize = opts.chunkSize || Math.max(this._size / 1000, 200 * 1024)
// create the reader
const reader = new FileReader()
reader.onload = () => {
// get the data chunk
this.push(toBuffer(reader.result))
}
reader.onerror = () => {
this.emit('error', reader.error)
}
this.reader = reader
// generate the header blocks that we will send as part of the initial payload
this._generateHeaderBlocks(file, opts, (err, blocks) => {
// if we encountered an error, emit it
if (err) {
return this.emit('error', err)
}
// push the header blocks out to the stream
if (Array.isArray(blocks)) {
blocks.forEach(block => this.push(block))
}
this._ready = true
this.emit('_ready')
})
}
_generateHeaderBlocks (file, opts, callback) {
callback(null, [])
}
_read () {
if (!this._ready) {
this.once('_ready', this._read.bind(this))
return
}
const startOffset = this._offset
let endOffset = this._offset + this._chunkSize
if (endOffset > this._size) endOffset = this._size
if (startOffset === this._size) {
this.destroy()
this.push(null)
return
}
this.reader.readAsArrayBuffer(this._file.slice(startOffset, endOffset))
// update the stream offset
this._offset = endOffset
}
destroy () {
this._file = null
if (this.reader) {
this.reader.onload = null
this.reader.onerror = null
try { this.reader.abort() } catch (e) {};
}
this.reader = null
}
}
module.exports = FileReadStream
},{"readable-stream":113,"typedarray-to-buffer":296}],115:[function(require,module,exports){
// originally pulled out of simple-peer
module.exports = function getBrowserRTC () {
if (typeof window === 'undefined') return null
var wrtc = {
RTCPeerConnection: window.RTCPeerConnection || window.mozRTCPeerConnection ||
window.webkitRTCPeerConnection,
RTCSessionDescription: window.RTCSessionDescription ||
window.mozRTCSessionDescription || window.webkitRTCSessionDescription,
RTCIceCandidate: window.RTCIceCandidate || window.mozRTCIceCandidate ||
window.webkitRTCIceCandidate
}
if (!wrtc.RTCPeerConnection) return null
return wrtc
}
},{}],116:[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":264,"url":299}],117:[function(require,module,exports){
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
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
}
},{}],118:[function(require,module,exports){
/*! immediate-chunk-store. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
// TODO: remove when window.queueMicrotask() is well supported
const queueMicrotask = require('queue-microtask')
class ImmediateStore {
constructor (store) {
this.store = store
this.chunkLength = store.chunkLength
if (!this.store || !this.store.get || !this.store.put) {
throw new Error('First argument must be abstract-chunk-store compliant')
}
this.mem = []
}
put (index, buf, cb) {
this.mem[index] = buf
this.store.put(index, buf, err => {
this.mem[index] = null
if (cb) cb(err)
})
}
get (index, opts, cb) {
if (typeof opts === 'function') return this.get(index, null, opts)
let memoryBuffer = this.mem[index]
// if the chunk isn't in the immediate memory cache
if (!memoryBuffer) {
return this.store.get(index, opts, cb)
}
if (opts) {
const start = opts.offset || 0
const end = opts.length ? (start + opts.length) : memoryBuffer.length
memoryBuffer = memoryBuffer.slice(start, end)
}
// queueMicrotask to ensure the function is async
queueMicrotask(() => {
if (cb) cb(null, memoryBuffer)
})
}
close (cb) {
this.store.close(cb)
}
destroy (cb) {
this.store.destroy(cb)
}
}
module.exports = ImmediateStore
},{"queue-microtask":193}],119:[function(require,module,exports){
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
if (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) {
if (superCtor) {
ctor.super_ = superCtor
var TempCtor = function () {}
TempCtor.prototype = superCtor.prototype
ctor.prototype = new TempCtor()
ctor.prototype.constructor = ctor
}
}
}
},{}],120:[function(require,module,exports){
/* (c) 2016 Ari Porad (@ariporad) <http://ariporad.com>. License: ariporad.mit-license.org */
// Partially from http://stackoverflow.com/a/94049/1928484, and from another SO answer, which told me that the highest
// char code that's ascii is 127, but I can't find the link for. Sorry.
var MAX_ASCII_CHAR_CODE = 127;
module.exports = function isAscii(str) {
for (var i = 0, strLen = str.length; i < strLen; ++i) {
if (str.charCodeAt(i) > MAX_ASCII_CHAR_CODE) return false;
}
return true;
};
},{}],121:[function(require,module,exports){
'use strict';
var fs = require('fs');
module.exports = function isFile(path, cb){
if(!cb)return isFileSync(path);
fs.stat(path, function(err, stats){
if(err)return cb(err);
return cb(null, stats.isFile());
});
};
module.exports.sync = isFileSync;
function isFileSync(path){
return fs.existsSync(path) && fs.statSync(path).isFile();
}
},{"fs":56}],122:[function(require,module,exports){
module.exports = isTypedArray
isTypedArray.strict = isStrictTypedArray
isTypedArray.loose = isLooseTypedArray
var toString = Object.prototype.toString
var names = {
'[object Int8Array]': true
, '[object Int16Array]': true
, '[object Int32Array]': true
, '[object Uint8Array]': true
, '[object Uint8ClampedArray]': true
, '[object Uint16Array]': true
, '[object Uint32Array]': true
, '[object Float32Array]': true
, '[object Float64Array]': true
}
function isTypedArray(arr) {
return (
isStrictTypedArray(arr)
|| isLooseTypedArray(arr)
)
}
function isStrictTypedArray(arr) {
return (
arr instanceof Int8Array
|| arr instanceof Int16Array
|| arr instanceof Int32Array
|| arr instanceof Uint8Array
|| arr instanceof Uint8ClampedArray
|| arr instanceof Uint16Array
|| arr instanceof Uint32Array
|| arr instanceof Float32Array
|| arr instanceof Float64Array
)
}
function isLooseTypedArray(arr) {
return names[toString.call(arr)]
}
},{}],123:[function(require,module,exports){
'use strict';
const blacklist = [
// # All
'^npm-debug\\.log$', // Error log for npm
'^\\..*\\.swp$', // Swap file for vim state
// # macOS
'^\\.DS_Store$', // Stores custom folder attributes
'^\\.AppleDouble$', // Stores additional file resources
'^\\.LSOverride$', // Contains the absolute path to the app to be used
'^Icon\\r$', // Custom Finder icon: http://superuser.com/questions/298785/icon-file-on-os-x-desktop
'^\\._.*', // Thumbnail
'^\\.Spotlight-V100(?:$|\\/)', // Directory that might appear on external disk
'\\.Trashes', // File that might appear on external disk
'^__MACOSX$', // Resource fork
// # Linux
'~$', // Backup file
// # Windows
'^Thumbs\\.db$', // Image file cache
'^ehthumbs\\.db$', // Folder config file
'^Desktop\\.ini$', // Stores custom folder attributes
'@eaDir$' // Synology Diskstation "hidden" folder where the server stores thumbnails
];
exports.re = () => {
throw new Error('`junk.re` was renamed to `junk.regex`');
};
exports.regex = new RegExp(blacklist.join('|'));
exports.is = filename => exports.regex.test(filename);
exports.not = filename => !exports.is(filename);
// TODO: Remove this for the next major release
exports.default = module.exports;
},{}],124:[function(require,module,exports){
(function (Buffer){(function (){
/*! magnet-uri. MIT License. WebTorrent LLC <https://webtorrent.io/opensource> */
module.exports = magnetURIDecode
module.exports.decode = magnetURIDecode
module.exports.encode = magnetURIEncode
const base32 = require('thirty-two')
const bep53Range = require('bep53-range')
/**
* Parse a magnet URI and return an object of keys/values
*
* @param {string} uri
* @return {Object} parsed uri
*/
function magnetURIDecode (uri) {
const result = {}
// Support 'magnet:' and 'stream-magnet:' uris
const data = uri.split('magnet:?')[1]
const params = (data && data.length >= 0)
? data.split('&')
: []
params.forEach(param => {
const keyval = param.split('=')
// This keyval is invalid, skip it
if (keyval.length !== 2) return
const key = keyval[0]
let val = keyval[1]
// Clean up torrent name
if (key === 'dn') val = decodeURIComponent(val).replace(/\+/g, ' ')
// Address tracker (tr), exact source (xs), and acceptable source (as) are encoded
// URIs, so decode them
if (key === 'tr' || key === 'xs' || key === 'as' || key === 'ws') {
val = decodeURIComponent(val)
}
// Return keywords as an array
if (key === 'kt') val = decodeURIComponent(val).split('+')
// Cast file index (ix) to a number
if (key === 'ix') val = Number(val)
// bep53
if (key === 'so') val = bep53Range.parse(decodeURIComponent(val).split(','))
// If there are repeated parameters, return an array of values
if (result[key]) {
if (!Array.isArray(result[key])) {
result[key] = [result[key]]
}
result[key].push(val)
} else {
result[key] = val
}
})
// Convenience properties for parity with `parse-torrent-file` module
let m
if (result.xt) {
const xts = Array.isArray(result.xt) ? result.xt : [result.xt]
xts.forEach(xt => {
if ((m = xt.match(/^urn:btih:(.{40})/))) {
result.infoHash = m[1].toLowerCase()
} else if ((m = xt.match(/^urn:btih:(.{32})/))) {
const decodedStr = base32.decode(m[1])
result.infoHash = Buffer.from(decodedStr, 'binary').toString('hex')
}
})
}
if (result.infoHash) result.infoHashBuffer = Buffer.from(result.infoHash, 'hex')
if (result.dn) result.name = result.dn
if (result.kt) result.keywords = result.kt
result.announce = []
if (typeof result.tr === 'string' || Array.isArray(result.tr)) {
result.announce = result.announce.concat(result.tr)
}
result.urlList = []
if (typeof result.as === 'string' || Array.isArray(result.as)) {
result.urlList = result.urlList.concat(result.as)
}
if (typeof result.ws === 'string' || Array.isArray(result.ws)) {
result.urlList = result.urlList.concat(result.ws)
}
result.peerAddresses = []
if (typeof result['x.pe'] === 'string' || Array.isArray(result['x.pe'])) {
result.peerAddresses = result.peerAddresses.concat(result['x.pe'])
}
// remove duplicates by converting to Set and back
result.announce = Array.from(new Set(result.announce))
result.urlList = Array.from(new Set(result.urlList))
result.peerAddresses = Array.from(new Set(result.peerAddresses))
return result
}
function magnetURIEncode (obj) {
obj = Object.assign({}, obj) // clone obj, so we can mutate it
// support using convenience names, in addition to spec names
// (example: `infoHash` for `xt`, `name` for `dn`)
if (obj.infoHashBuffer) obj.xt = `urn:btih:${obj.infoHashBuffer.toString('hex')}`
if (obj.infoHash) obj.xt = `urn:btih:${obj.infoHash}`
if (obj.name) obj.dn = obj.name
if (obj.keywords) obj.kt = obj.keywords
if (obj.announce) obj.tr = obj.announce
if (obj.urlList) {
obj.ws = obj.urlList
delete obj.as
}
if (obj.peerAddresses) obj['x.pe'] = obj.peerAddresses
let result = 'magnet:?'
Object.keys(obj)
.filter(key => key.length === 2 || key === 'x.pe')
.forEach((key, i) => {
const values = Array.isArray(obj[key]) ? obj[key] : [obj[key]]
values.forEach((val, j) => {
if ((i > 0 || j > 0) && ((key !== 'kt' && key !== 'so') || j === 0)) result += '&'
if (key === 'dn') val = encodeURIComponent(val).replace(/%20/g, '+')
if (key === 'tr' || key === 'xs' || key === 'as' || key === 'ws') {
val = encodeURIComponent(val)
}
if (key === 'kt') val = encodeURIComponent(val)
if (key === 'so') return
if (key === 'kt' && j > 0) result += `+${val}`
else result += `${key}=${val}`
})
if (key === 'so') result += `${key}=${bep53Range.compose(values)}`
})
return result
}
}).call(this)}).call(this,require("buffer").Buffer)
},{"bep53-range":8,"buffer":60,"thirty-two":287}],125:[function(require,module,exports){
/*! mediasource. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
module.exports = MediaElementWrapper
var inherits = require('inherits')
var stream = require('readable-stream')
var toArrayBuffer = require('to-arraybuffer')
var MediaSource = typeof window !== 'undefined' && window.MediaSource
var DEFAULT_BUFFER_DURATION = 60 // seconds
function MediaElementWrapper (elem, opts) {
var self = this
if (!(self instanceof MediaElementWrapper)) return new MediaElementWrapper(elem, opts)
if (!MediaSource) throw new Error('web browser lacks MediaSource support')
if (!opts) opts = {}
self._debug = opts.debug
self._bufferDuration = opts.bufferDuration || DEFAULT_BUFFER_DURATION
self._elem = elem
self._mediaSource = new MediaSource()
self._streams = []
self.detailedError = null
self._errorHandler = function () {
self._elem.removeEventListener('error', self._errorHandler)
var streams = self._streams.slice()
streams.forEach(function (stream) {
stream.destroy(self._elem.error)
})
}
self._elem.addEventListener('error', self._errorHandler)
self._elem.src = window.URL.createObjectURL(self._mediaSource)
}
/*
* `obj` can be a previous value returned by this function
* or a string
*/
MediaElementWrapper.prototype.createWriteStream = function (obj) {
var self = this
return new MediaSourceStream(self, obj)
}
/*
* Use to trigger an error on the underlying media element
*/
MediaElementWrapper.prototype.error = function (err) {
var self = this
// be careful not to overwrite any existing detailedError values
if (!self.detailedError) {
self.detailedError = err
}
self._dumpDebugData()
try {
self._mediaSource.endOfStream('decode')
} catch (err) {}
try {
// Attempt to clean up object URL
window.URL.revokeObjectURL(self._elem.src)
} catch (err) {}
}
/*
* When self._debug is set, dump all data to files
*/
MediaElementWrapper.prototype._dumpDebugData = function () {
var self = this
if (self._debug) {
self._debug = false // prevent multiple dumps on multiple errors
self._streams.forEach(function (stream, i) {
downloadBuffers(stream._debugBuffers, 'mediasource-stream-' + i)
})
}
}
inherits(MediaSourceStream, stream.Writable)
function MediaSourceStream (wrapper, obj) {
var self = this
stream.Writable.call(self)
self._wrapper = wrapper
self._elem = wrapper._elem
self._mediaSource = wrapper._mediaSource
self._allStreams = wrapper._streams
self._allStreams.push(self)
self._bufferDuration = wrapper._bufferDuration
self._sourceBuffer = null
self._debugBuffers = []
self._openHandler = function () {
self._onSourceOpen()
}
self._flowHandler = function () {
self._flow()
}
self._errorHandler = function (err) {
if (!self.destroyed) {
self.emit('error', err)
}
}
if (typeof obj === 'string') {
self._type = obj
// Need to create a new sourceBuffer
if (self._mediaSource.readyState === 'open') {
self._createSourceBuffer()
} else {
self._mediaSource.addEventListener('sourceopen', self._openHandler)
}
} else if (obj._sourceBuffer === null) {
obj.destroy()
self._type = obj._type // The old stream was created but hasn't finished initializing
self._mediaSource.addEventListener('sourceopen', self._openHandler)
} else if (obj._sourceBuffer) {
obj.destroy()
self._type = obj._type
self._sourceBuffer = obj._sourceBuffer // Copy over the old sourceBuffer
self._debugBuffers = obj._debugBuffers // Copy over previous debug data
self._sourceBuffer.addEventListener('updateend', self._flowHandler)
self._sourceBuffer.addEventListener('error', self._errorHandler)
} else {
throw new Error('The argument to MediaElementWrapper.createWriteStream must be a string or a previous stream returned from that function')
}
self._elem.addEventListener('timeupdate', self._flowHandler)
self.on('error', function (err) {
self._wrapper.error(err)
})
self.on('finish', function () {
if (self.destroyed) return
self._finished = true
if (self._allStreams.every(function (other) { return other._finished })) {
self._wrapper._dumpDebugData()
try {
self._mediaSource.endOfStream()
} catch (err) {}
}
})
}
MediaSourceStream.prototype._onSourceOpen = function () {
var self = this
if (self.destroyed) return
self._mediaSource.removeEventListener('sourceopen', self._openHandler)
self._createSourceBuffer()
}
MediaSourceStream.prototype.destroy = function (err) {
var self = this
if (self.destroyed) return
self.destroyed = true
// Remove from allStreams
self._allStreams.splice(self._allStreams.indexOf(self), 1)
self._mediaSource.removeEventListener('sourceopen', self._openHandler)
self._elem.removeEventListener('timeupdate', self._flowHandler)
if (self._sourceBuffer) {
self._sourceBuffer.removeEventListener('updateend', self._flowHandler)
self._sourceBuffer.removeEventListener('error', self._errorHandler)
if (self._mediaSource.readyState === 'open') {
self._sourceBuffer.abort()
}
}
if (err) self.emit('error', err)
self.emit('close')
}
MediaSourceStream.prototype._createSourceBuffer = function () {
var self = this
if (self.destroyed) return
if (MediaSource.isTypeSupported(self._type)) {
self._sourceBuffer = self._mediaSource.addSourceBuffer(self._type)
self._sourceBuffer.addEventListener('updateend', self._flowHandler)
self._sourceBuffer.addEventListener('error', self._errorHandler)
if (self._cb) {
var cb = self._cb
self._cb = null
cb()
}
} else {
self.destroy(new Error('The provided type is not supported'))
}
}
MediaSourceStream.prototype._write = function (chunk, encoding, cb) {
var self = this
if (self.destroyed) return
if (!self._sourceBuffer) {
self._cb = function (err) {
if (err) return cb(err)
self._write(chunk, encoding, cb)
}
return
}
if (self._sourceBuffer.updating) {
return cb(new Error('Cannot append buffer while source buffer updating'))
}
var arr = toArrayBuffer(chunk)
if (self._wrapper._debug) {
self._debugBuffers.push(arr)
}
try {
self._sourceBuffer.appendBuffer(arr)
} catch (err) {
// appendBuffer can throw for a number of reasons, most notably when the data
// being appended is invalid or if appendBuffer is called after another error
// already occurred on the media element. In Chrome, there may be useful debugging
// info in chrome://media-internals
self.destroy(err)
return
}
self._cb = cb
}
MediaSourceStream.prototype._flow = function () {
var self = this
if (self.destroyed || !self._sourceBuffer || self._sourceBuffer.updating) {
return
}
if (self._mediaSource.readyState === 'open') {
// check buffer size
if (self._getBufferDuration() > self._bufferDuration) {
return
}
}
if (self._cb) {
var cb = self._cb
self._cb = null
cb()
}
}
// TODO: if zero actually works in all browsers, remove the logic associated with this below
var EPSILON = 0
MediaSourceStream.prototype._getBufferDuration = function () {
var self = this
var buffered = self._sourceBuffer.buffered
var currentTime = self._elem.currentTime
var bufferEnd = -1 // end of the buffer
// This is a little over complex because some browsers seem to separate the
// buffered region into multiple sections with slight gaps.
for (var i = 0; i < buffered.length; i++) {
var start = buffered.start(i)
var end = buffered.end(i) + EPSILON
if (start > currentTime) {
// Reached past the joined buffer
break
} else if (bufferEnd >= 0 || currentTime <= end) {
// Found the start/continuation of the joined buffer
bufferEnd = end
}
}
var bufferedTime = bufferEnd - currentTime
if (bufferedTime < 0) {
bufferedTime = 0
}
return bufferedTime
}
function downloadBuffers (bufs, name) {
var a = document.createElement('a')
a.href = window.URL.createObjectURL(new window.Blob(bufs))
a.download = name
a.click()
}
},{"inherits":119,"readable-stream":140,"to-arraybuffer":290}],126:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],127:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":129,"./_stream_writable":131,"_process":187,"dup":17,"inherits":119}],128:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":130,"dup":18,"inherits":119}],129:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":126,"./_stream_duplex":127,"./internal/streams/async_iterator":132,"./internal/streams/buffer_list":133,"./internal/streams/destroy":134,"./internal/streams/from":136,"./internal/streams/state":138,"./internal/streams/stream":139,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],130:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":126,"./_stream_duplex":127,"dup":20,"inherits":119}],131:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":126,"./_stream_duplex":127,"./internal/streams/destroy":134,"./internal/streams/state":138,"./internal/streams/stream":139,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],132:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":135,"_process":187,"dup":22}],133:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],134:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],135:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":126,"dup":25}],136:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],137:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":126,"./end-of-stream":135,"dup":27}],138:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":126,"dup":28}],139:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],140:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":127,"./lib/_stream_passthrough.js":128,"./lib/_stream_readable.js":129,"./lib/_stream_transform.js":130,"./lib/_stream_writable.js":131,"./lib/internal/streams/end-of-stream.js":135,"./lib/internal/streams/pipeline.js":137,"dup":30}],141:[function(require,module,exports){
(function (process){(function (){
module.exports = Storage
function Storage (chunkLength, opts) {
if (!(this instanceof Storage)) return new Storage(chunkLength, opts)
if (!opts) opts = {}
this.chunkLength = Number(chunkLength)
if (!this.chunkLength) throw new Error('First argument must be a chunk length')
this.chunks = []
this.closed = false
this.length = Number(opts.length) || Infinity
if (this.length !== Infinity) {
this.lastChunkLength = (this.length % this.chunkLength) || this.chunkLength
this.lastChunkIndex = Math.ceil(this.length / this.chunkLength) - 1
}
}
Storage.prototype.put = function (index, buf, cb) {
if (this.closed) return nextTick(cb, new Error('Storage is closed'))
var isLastChunk = (index === this.lastChunkIndex)
if (isLastChunk && buf.length !== this.lastChunkLength) {
return nextTick(cb, new Error('Last chunk length must be ' + this.lastChunkLength))
}
if (!isLastChunk && buf.length !== this.chunkLength) {
return nextTick(cb, new Error('Chunk length must be ' + this.chunkLength))
}
this.chunks[index] = buf
nextTick(cb, null)
}
Storage.prototype.get = function (index, opts, cb) {
if (typeof opts === 'function') return this.get(index, null, opts)
if (this.closed) return nextTick(cb, new Error('Storage is closed'))
var buf = this.chunks[index]
if (!buf) {
var err = new Error('Chunk not found')
err.notFound = true
return nextTick(cb, err)
}
if (!opts) return nextTick(cb, null, buf)
var offset = opts.offset || 0
var len = opts.length || (buf.length - offset)
nextTick(cb, null, buf.slice(offset, len + offset))
}
Storage.prototype.close = Storage.prototype.destroy = function (cb) {
if (this.closed) return nextTick(cb, new Error('Storage is closed'))
this.closed = true
this.chunks = null
nextTick(cb, null)
}
function nextTick (cb, err, val) {
process.nextTick(function () {
if (cb) cb(err, val)
})
}
}).call(this)}).call(this,require('_process'))
},{"_process":187}],142:[function(require,module,exports){
module.exports={
"application/1d-interleaved-parityfec": {
"source": "iana"
},
"application/3gpdash-qoe-report+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/3gpp-ims+xml": {
"source": "iana",
"compressible": true
},
"application/a2l": {
"source": "iana"
},
"application/activemessage": {
"source": "iana"
},
"application/activity+json": {
"source": "iana",
"compressible": true
},
"application/alto-costmap+json": {
"source": "iana",
"compressible": true
},
"application/alto-costmapfilter+json": {
"source": "iana",
"compressible": true
},
"application/alto-directory+json": {
"source": "iana",
"compressible": true
},
"application/alto-endpointcost+json": {
"source": "iana",
"compressible": true
},
"application/alto-endpointcostparams+json": {
"source": "iana",
"compressible": true
},
"application/alto-endpointprop+json": {
"source": "iana",
"compressible": true
},
"application/alto-endpointpropparams+json": {
"source": "iana",
"compressible": true
},
"application/alto-error+json": {
"source": "iana",
"compressible": true
},
"application/alto-networkmap+json": {
"source": "iana",
"compressible": true
},
"application/alto-networkmapfilter+json": {
"source": "iana",
"compressible": true
},
"application/alto-updatestreamcontrol+json": {
"source": "iana",
"compressible": true
},
"application/alto-updatestreamparams+json": {
"source": "iana",
"compressible": true
},
"application/aml": {
"source": "iana"
},
"application/andrew-inset": {
"source": "iana",
"extensions": ["ez"]
},
"application/applefile": {
"source": "iana"
},
"application/applixware": {
"source": "apache",
"extensions": ["aw"]
},
"application/atf": {
"source": "iana"
},
"application/atfx": {
"source": "iana"
},
"application/atom+xml": {
"source": "iana",
"compressible": true,
"extensions": ["atom"]
},
"application/atomcat+xml": {
"source": "iana",
"compressible": true,
"extensions": ["atomcat"]
},
"application/atomdeleted+xml": {
"source": "iana",
"compressible": true,
"extensions": ["atomdeleted"]
},
"application/atomicmail": {
"source": "iana"
},
"application/atomsvc+xml": {
"source": "iana",
"compressible": true,
"extensions": ["atomsvc"]
},
"application/atsc-dwd+xml": {
"source": "iana",
"compressible": true,
"extensions": ["dwd"]
},
"application/atsc-dynamic-event-message": {
"source": "iana"
},
"application/atsc-held+xml": {
"source": "iana",
"compressible": true,
"extensions": ["held"]
},
"application/atsc-rdt+json": {
"source": "iana",
"compressible": true
},
"application/atsc-rsat+xml": {
"source": "iana",
"compressible": true,
"extensions": ["rsat"]
},
"application/atxml": {
"source": "iana"
},
"application/auth-policy+xml": {
"source": "iana",
"compressible": true
},
"application/bacnet-xdd+zip": {
"source": "iana",
"compressible": false
},
"application/batch-smtp": {
"source": "iana"
},
"application/bdoc": {
"compressible": false,
"extensions": ["bdoc"]
},
"application/beep+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/calendar+json": {
"source": "iana",
"compressible": true
},
"application/calendar+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xcs"]
},
"application/call-completion": {
"source": "iana"
},
"application/cals-1840": {
"source": "iana"
},
"application/cap+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/cbor": {
"source": "iana"
},
"application/cbor-seq": {
"source": "iana"
},
"application/cccex": {
"source": "iana"
},
"application/ccmp+xml": {
"source": "iana",
"compressible": true
},
"application/ccxml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["ccxml"]
},
"application/cdfx+xml": {
"source": "iana",
"compressible": true,
"extensions": ["cdfx"]
},
"application/cdmi-capability": {
"source": "iana",
"extensions": ["cdmia"]
},
"application/cdmi-container": {
"source": "iana",
"extensions": ["cdmic"]
},
"application/cdmi-domain": {
"source": "iana",
"extensions": ["cdmid"]
},
"application/cdmi-object": {
"source": "iana",
"extensions": ["cdmio"]
},
"application/cdmi-queue": {
"source": "iana",
"extensions": ["cdmiq"]
},
"application/cdni": {
"source": "iana"
},
"application/cea": {
"source": "iana"
},
"application/cea-2018+xml": {
"source": "iana",
"compressible": true
},
"application/cellml+xml": {
"source": "iana",
"compressible": true
},
"application/cfw": {
"source": "iana"
},
"application/clue+xml": {
"source": "iana",
"compressible": true
},
"application/clue_info+xml": {
"source": "iana",
"compressible": true
},
"application/cms": {
"source": "iana"
},
"application/cnrp+xml": {
"source": "iana",
"compressible": true
},
"application/coap-group+json": {
"source": "iana",
"compressible": true
},
"application/coap-payload": {
"source": "iana"
},
"application/commonground": {
"source": "iana"
},
"application/conference-info+xml": {
"source": "iana",
"compressible": true
},
"application/cose": {
"source": "iana"
},
"application/cose-key": {
"source": "iana"
},
"application/cose-key-set": {
"source": "iana"
},
"application/cpl+xml": {
"source": "iana",
"compressible": true
},
"application/csrattrs": {
"source": "iana"
},
"application/csta+xml": {
"source": "iana",
"compressible": true
},
"application/cstadata+xml": {
"source": "iana",
"compressible": true
},
"application/csvm+json": {
"source": "iana",
"compressible": true
},
"application/cu-seeme": {
"source": "apache",
"extensions": ["cu"]
},
"application/cwt": {
"source": "iana"
},
"application/cybercash": {
"source": "iana"
},
"application/dart": {
"compressible": true
},
"application/dash+xml": {
"source": "iana",
"compressible": true,
"extensions": ["mpd"]
},
"application/dashdelta": {
"source": "iana"
},
"application/davmount+xml": {
"source": "iana",
"compressible": true,
"extensions": ["davmount"]
},
"application/dca-rft": {
"source": "iana"
},
"application/dcd": {
"source": "iana"
},
"application/dec-dx": {
"source": "iana"
},
"application/dialog-info+xml": {
"source": "iana",
"compressible": true
},
"application/dicom": {
"source": "iana"
},
"application/dicom+json": {
"source": "iana",
"compressible": true
},
"application/dicom+xml": {
"source": "iana",
"compressible": true
},
"application/dii": {
"source": "iana"
},
"application/dit": {
"source": "iana"
},
"application/dns": {
"source": "iana"
},
"application/dns+json": {
"source": "iana",
"compressible": true
},
"application/dns-message": {
"source": "iana"
},
"application/docbook+xml": {
"source": "apache",
"compressible": true,
"extensions": ["dbk"]
},
"application/dots+cbor": {
"source": "iana"
},
"application/dskpp+xml": {
"source": "iana",
"compressible": true
},
"application/dssc+der": {
"source": "iana",
"extensions": ["dssc"]
},
"application/dssc+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xdssc"]
},
"application/dvcs": {
"source": "iana"
},
"application/ecmascript": {
"source": "iana",
"compressible": true,
"extensions": ["ecma","es"]
},
"application/edi-consent": {
"source": "iana"
},
"application/edi-x12": {
"source": "iana",
"compressible": false
},
"application/edifact": {
"source": "iana",
"compressible": false
},
"application/efi": {
"source": "iana"
},
"application/emergencycalldata.comment+xml": {
"source": "iana",
"compressible": true
},
"application/emergencycalldata.control+xml": {
"source": "iana",
"compressible": true
},
"application/emergencycalldata.deviceinfo+xml": {
"source": "iana",
"compressible": true
},
"application/emergencycalldata.ecall.msd": {
"source": "iana"
},
"application/emergencycalldata.providerinfo+xml": {
"source": "iana",
"compressible": true
},
"application/emergencycalldata.serviceinfo+xml": {
"source": "iana",
"compressible": true
},
"application/emergencycalldata.subscriberinfo+xml": {
"source": "iana",
"compressible": true
},
"application/emergencycalldata.veds+xml": {
"source": "iana",
"compressible": true
},
"application/emma+xml": {
"source": "iana",
"compressible": true,
"extensions": ["emma"]
},
"application/emotionml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["emotionml"]
},
"application/encaprtp": {
"source": "iana"
},
"application/epp+xml": {
"source": "iana",
"compressible": true
},
"application/epub+zip": {
"source": "iana",
"compressible": false,
"extensions": ["epub"]
},
"application/eshop": {
"source": "iana"
},
"application/exi": {
"source": "iana",
"extensions": ["exi"]
},
"application/expect-ct-report+json": {
"source": "iana",
"compressible": true
},
"application/fastinfoset": {
"source": "iana"
},
"application/fastsoap": {
"source": "iana"
},
"application/fdt+xml": {
"source": "iana",
"compressible": true,
"extensions": ["fdt"]
},
"application/fhir+json": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/fhir+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/fido.trusted-apps+json": {
"compressible": true
},
"application/fits": {
"source": "iana"
},
"application/flexfec": {
"source": "iana"
},
"application/font-sfnt": {
"source": "iana"
},
"application/font-tdpfr": {
"source": "iana",
"extensions": ["pfr"]
},
"application/font-woff": {
"source": "iana",
"compressible": false
},
"application/framework-attributes+xml": {
"source": "iana",
"compressible": true
},
"application/geo+json": {
"source": "iana",
"compressible": true,
"extensions": ["geojson"]
},
"application/geo+json-seq": {
"source": "iana"
},
"application/geopackage+sqlite3": {
"source": "iana"
},
"application/geoxacml+xml": {
"source": "iana",
"compressible": true
},
"application/gltf-buffer": {
"source": "iana"
},
"application/gml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["gml"]
},
"application/gpx+xml": {
"source": "apache",
"compressible": true,
"extensions": ["gpx"]
},
"application/gxf": {
"source": "apache",
"extensions": ["gxf"]
},
"application/gzip": {
"source": "iana",
"compressible": false,
"extensions": ["gz"]
},
"application/h224": {
"source": "iana"
},
"application/held+xml": {
"source": "iana",
"compressible": true
},
"application/hjson": {
"extensions": ["hjson"]
},
"application/http": {
"source": "iana"
},
"application/hyperstudio": {
"source": "iana",
"extensions": ["stk"]
},
"application/ibe-key-request+xml": {
"source": "iana",
"compressible": true
},
"application/ibe-pkg-reply+xml": {
"source": "iana",
"compressible": true
},
"application/ibe-pp-data": {
"source": "iana"
},
"application/iges": {
"source": "iana"
},
"application/im-iscomposing+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/index": {
"source": "iana"
},
"application/index.cmd": {
"source": "iana"
},
"application/index.obj": {
"source": "iana"
},
"application/index.response": {
"source": "iana"
},
"application/index.vnd": {
"source": "iana"
},
"application/inkml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["ink","inkml"]
},
"application/iotp": {
"source": "iana"
},
"application/ipfix": {
"source": "iana",
"extensions": ["ipfix"]
},
"application/ipp": {
"source": "iana"
},
"application/isup": {
"source": "iana"
},
"application/its+xml": {
"source": "iana",
"compressible": true,
"extensions": ["its"]
},
"application/java-archive": {
"source": "apache",
"compressible": false,
"extensions": ["jar","war","ear"]
},
"application/java-serialized-object": {
"source": "apache",
"compressible": false,
"extensions": ["ser"]
},
"application/java-vm": {
"source": "apache",
"compressible": false,
"extensions": ["class"]
},
"application/javascript": {
"source": "iana",
"charset": "UTF-8",
"compressible": true,
"extensions": ["js","mjs"]
},
"application/jf2feed+json": {
"source": "iana",
"compressible": true
},
"application/jose": {
"source": "iana"
},
"application/jose+json": {
"source": "iana",
"compressible": true
},
"application/jrd+json": {
"source": "iana",
"compressible": true
},
"application/json": {
"source": "iana",
"charset": "UTF-8",
"compressible": true,
"extensions": ["json","map"]
},
"application/json-patch+json": {
"source": "iana",
"compressible": true
},
"application/json-seq": {
"source": "iana"
},
"application/json5": {
"extensions": ["json5"]
},
"application/jsonml+json": {
"source": "apache",
"compressible": true,
"extensions": ["jsonml"]
},
"application/jwk+json": {
"source": "iana",
"compressible": true
},
"application/jwk-set+json": {
"source": "iana",
"compressible": true
},
"application/jwt": {
"source": "iana"
},
"application/kpml-request+xml": {
"source": "iana",
"compressible": true
},
"application/kpml-response+xml": {
"source": "iana",
"compressible": true
},
"application/ld+json": {
"source": "iana",
"compressible": true,
"extensions": ["jsonld"]
},
"application/lgr+xml": {
"source": "iana",
"compressible": true,
"extensions": ["lgr"]
},
"application/link-format": {
"source": "iana"
},
"application/load-control+xml": {
"source": "iana",
"compressible": true
},
"application/lost+xml": {
"source": "iana",
"compressible": true,
"extensions": ["lostxml"]
},
"application/lostsync+xml": {
"source": "iana",
"compressible": true
},
"application/lpf+zip": {
"source": "iana",
"compressible": false
},
"application/lxf": {
"source": "iana"
},
"application/mac-binhex40": {
"source": "iana",
"extensions": ["hqx"]
},
"application/mac-compactpro": {
"source": "apache",
"extensions": ["cpt"]
},
"application/macwriteii": {
"source": "iana"
},
"application/mads+xml": {
"source": "iana",
"compressible": true,
"extensions": ["mads"]
},
"application/manifest+json": {
"charset": "UTF-8",
"compressible": true,
"extensions": ["webmanifest"]
},
"application/marc": {
"source": "iana",
"extensions": ["mrc"]
},
"application/marcxml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["mrcx"]
},
"application/mathematica": {
"source": "iana",
"extensions": ["ma","nb","mb"]
},
"application/mathml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["mathml"]
},
"application/mathml-content+xml": {
"source": "iana",
"compressible": true
},
"application/mathml-presentation+xml": {
"source": "iana",
"compressible": true
},
"application/mbms-associated-procedure-description+xml": {
"source": "iana",
"compressible": true
},
"application/mbms-deregister+xml": {
"source": "iana",
"compressible": true
},
"application/mbms-envelope+xml": {
"source": "iana",
"compressible": true
},
"application/mbms-msk+xml": {
"source": "iana",
"compressible": true
},
"application/mbms-msk-response+xml": {
"source": "iana",
"compressible": true
},
"application/mbms-protection-description+xml": {
"source": "iana",
"compressible": true
},
"application/mbms-reception-report+xml": {
"source": "iana",
"compressible": true
},
"application/mbms-register+xml": {
"source": "iana",
"compressible": true
},
"application/mbms-register-response+xml": {
"source": "iana",
"compressible": true
},
"application/mbms-schedule+xml": {
"source": "iana",
"compressible": true
},
"application/mbms-user-service-description+xml": {
"source": "iana",
"compressible": true
},
"application/mbox": {
"source": "iana",
"extensions": ["mbox"]
},
"application/media-policy-dataset+xml": {
"source": "iana",
"compressible": true
},
"application/media_control+xml": {
"source": "iana",
"compressible": true
},
"application/mediaservercontrol+xml": {
"source": "iana",
"compressible": true,
"extensions": ["mscml"]
},
"application/merge-patch+json": {
"source": "iana",
"compressible": true
},
"application/metalink+xml": {
"source": "apache",
"compressible": true,
"extensions": ["metalink"]
},
"application/metalink4+xml": {
"source": "iana",
"compressible": true,
"extensions": ["meta4"]
},
"application/mets+xml": {
"source": "iana",
"compressible": true,
"extensions": ["mets"]
},
"application/mf4": {
"source": "iana"
},
"application/mikey": {
"source": "iana"
},
"application/mipc": {
"source": "iana"
},
"application/mmt-aei+xml": {
"source": "iana",
"compressible": true,
"extensions": ["maei"]
},
"application/mmt-usd+xml": {
"source": "iana",
"compressible": true,
"extensions": ["musd"]
},
"application/mods+xml": {
"source": "iana",
"compressible": true,
"extensions": ["mods"]
},
"application/moss-keys": {
"source": "iana"
},
"application/moss-signature": {
"source": "iana"
},
"application/mosskey-data": {
"source": "iana"
},
"application/mosskey-request": {
"source": "iana"
},
"application/mp21": {
"source": "iana",
"extensions": ["m21","mp21"]
},
"application/mp4": {
"source": "iana",
"extensions": ["mp4s","m4p"]
},
"application/mpeg4-generic": {
"source": "iana"
},
"application/mpeg4-iod": {
"source": "iana"
},
"application/mpeg4-iod-xmt": {
"source": "iana"
},
"application/mrb-consumer+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xdf"]
},
"application/mrb-publish+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xdf"]
},
"application/msc-ivr+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/msc-mixer+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/msword": {
"source": "iana",
"compressible": false,
"extensions": ["doc","dot"]
},
"application/mud+json": {
"source": "iana",
"compressible": true
},
"application/multipart-core": {
"source": "iana"
},
"application/mxf": {
"source": "iana",
"extensions": ["mxf"]
},
"application/n-quads": {
"source": "iana",
"extensions": ["nq"]
},
"application/n-triples": {
"source": "iana",
"extensions": ["nt"]
},
"application/nasdata": {
"source": "iana"
},
"application/news-checkgroups": {
"source": "iana",
"charset": "US-ASCII"
},
"application/news-groupinfo": {
"source": "iana",
"charset": "US-ASCII"
},
"application/news-transmission": {
"source": "iana"
},
"application/nlsml+xml": {
"source": "iana",
"compressible": true
},
"application/node": {
"source": "iana",
"extensions": ["cjs"]
},
"application/nss": {
"source": "iana"
},
"application/ocsp-request": {
"source": "iana"
},
"application/ocsp-response": {
"source": "iana"
},
"application/octet-stream": {
"source": "iana",
"compressible": false,
"extensions": ["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"]
},
"application/oda": {
"source": "iana",
"extensions": ["oda"]
},
"application/odm+xml": {
"source": "iana",
"compressible": true
},
"application/odx": {
"source": "iana"
},
"application/oebps-package+xml": {
"source": "iana",
"compressible": true,
"extensions": ["opf"]
},
"application/ogg": {
"source": "iana",
"compressible": false,
"extensions": ["ogx"]
},
"application/omdoc+xml": {
"source": "apache",
"compressible": true,
"extensions": ["omdoc"]
},
"application/onenote": {
"source": "apache",
"extensions": ["onetoc","onetoc2","onetmp","onepkg"]
},
"application/oscore": {
"source": "iana"
},
"application/oxps": {
"source": "iana",
"extensions": ["oxps"]
},
"application/p2p-overlay+xml": {
"source": "iana",
"compressible": true,
"extensions": ["relo"]
},
"application/parityfec": {
"source": "iana"
},
"application/passport": {
"source": "iana"
},
"application/patch-ops-error+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xer"]
},
"application/pdf": {
"source": "iana",
"compressible": false,
"extensions": ["pdf"]
},
"application/pdx": {
"source": "iana"
},
"application/pem-certificate-chain": {
"source": "iana"
},
"application/pgp-encrypted": {
"source": "iana",
"compressible": false,
"extensions": ["pgp"]
},
"application/pgp-keys": {
"source": "iana"
},
"application/pgp-signature": {
"source": "iana",
"extensions": ["asc","sig"]
},
"application/pics-rules": {
"source": "apache",
"extensions": ["prf"]
},
"application/pidf+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/pidf-diff+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/pkcs10": {
"source": "iana",
"extensions": ["p10"]
},
"application/pkcs12": {
"source": "iana"
},
"application/pkcs7-mime": {
"source": "iana",
"extensions": ["p7m","p7c"]
},
"application/pkcs7-signature": {
"source": "iana",
"extensions": ["p7s"]
},
"application/pkcs8": {
"source": "iana",
"extensions": ["p8"]
},
"application/pkcs8-encrypted": {
"source": "iana"
},
"application/pkix-attr-cert": {
"source": "iana",
"extensions": ["ac"]
},
"application/pkix-cert": {
"source": "iana",
"extensions": ["cer"]
},
"application/pkix-crl": {
"source": "iana",
"extensions": ["crl"]
},
"application/pkix-pkipath": {
"source": "iana",
"extensions": ["pkipath"]
},
"application/pkixcmp": {
"source": "iana",
"extensions": ["pki"]
},
"application/pls+xml": {
"source": "iana",
"compressible": true,
"extensions": ["pls"]
},
"application/poc-settings+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/postscript": {
"source": "iana",
"compressible": true,
"extensions": ["ai","eps","ps"]
},
"application/ppsp-tracker+json": {
"source": "iana",
"compressible": true
},
"application/problem+json": {
"source": "iana",
"compressible": true
},
"application/problem+xml": {
"source": "iana",
"compressible": true
},
"application/provenance+xml": {
"source": "iana",
"compressible": true,
"extensions": ["provx"]
},
"application/prs.alvestrand.titrax-sheet": {
"source": "iana"
},
"application/prs.cww": {
"source": "iana",
"extensions": ["cww"]
},
"application/prs.hpub+zip": {
"source": "iana",
"compressible": false
},
"application/prs.nprend": {
"source": "iana"
},
"application/prs.plucker": {
"source": "iana"
},
"application/prs.rdf-xml-crypt": {
"source": "iana"
},
"application/prs.xsf+xml": {
"source": "iana",
"compressible": true
},
"application/pskc+xml": {
"source": "iana",
"compressible": true,
"extensions": ["pskcxml"]
},
"application/pvd+json": {
"source": "iana",
"compressible": true
},
"application/qsig": {
"source": "iana"
},
"application/raml+yaml": {
"compressible": true,
"extensions": ["raml"]
},
"application/raptorfec": {
"source": "iana"
},
"application/rdap+json": {
"source": "iana",
"compressible": true
},
"application/rdf+xml": {
"source": "iana",
"compressible": true,
"extensions": ["rdf","owl"]
},
"application/reginfo+xml": {
"source": "iana",
"compressible": true,
"extensions": ["rif"]
},
"application/relax-ng-compact-syntax": {
"source": "iana",
"extensions": ["rnc"]
},
"application/remote-printing": {
"source": "iana"
},
"application/reputon+json": {
"source": "iana",
"compressible": true
},
"application/resource-lists+xml": {
"source": "iana",
"compressible": true,
"extensions": ["rl"]
},
"application/resource-lists-diff+xml": {
"source": "iana",
"compressible": true,
"extensions": ["rld"]
},
"application/rfc+xml": {
"source": "iana",
"compressible": true
},
"application/riscos": {
"source": "iana"
},
"application/rlmi+xml": {
"source": "iana",
"compressible": true
},
"application/rls-services+xml": {
"source": "iana",
"compressible": true,
"extensions": ["rs"]
},
"application/route-apd+xml": {
"source": "iana",
"compressible": true,
"extensions": ["rapd"]
},
"application/route-s-tsid+xml": {
"source": "iana",
"compressible": true,
"extensions": ["sls"]
},
"application/route-usd+xml": {
"source": "iana",
"compressible": true,
"extensions": ["rusd"]
},
"application/rpki-ghostbusters": {
"source": "iana",
"extensions": ["gbr"]
},
"application/rpki-manifest": {
"source": "iana",
"extensions": ["mft"]
},
"application/rpki-publication": {
"source": "iana"
},
"application/rpki-roa": {
"source": "iana",
"extensions": ["roa"]
},
"application/rpki-updown": {
"source": "iana"
},
"application/rsd+xml": {
"source": "apache",
"compressible": true,
"extensions": ["rsd"]
},
"application/rss+xml": {
"source": "apache",
"compressible": true,
"extensions": ["rss"]
},
"application/rtf": {
"source": "iana",
"compressible": true,
"extensions": ["rtf"]
},
"application/rtploopback": {
"source": "iana"
},
"application/rtx": {
"source": "iana"
},
"application/samlassertion+xml": {
"source": "iana",
"compressible": true
},
"application/samlmetadata+xml": {
"source": "iana",
"compressible": true
},
"application/sbe": {
"source": "iana"
},
"application/sbml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["sbml"]
},
"application/scaip+xml": {
"source": "iana",
"compressible": true
},
"application/scim+json": {
"source": "iana",
"compressible": true
},
"application/scvp-cv-request": {
"source": "iana",
"extensions": ["scq"]
},
"application/scvp-cv-response": {
"source": "iana",
"extensions": ["scs"]
},
"application/scvp-vp-request": {
"source": "iana",
"extensions": ["spq"]
},
"application/scvp-vp-response": {
"source": "iana",
"extensions": ["spp"]
},
"application/sdp": {
"source": "iana",
"extensions": ["sdp"]
},
"application/secevent+jwt": {
"source": "iana"
},
"application/senml+cbor": {
"source": "iana"
},
"application/senml+json": {
"source": "iana",
"compressible": true
},
"application/senml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["senmlx"]
},
"application/senml-etch+cbor": {
"source": "iana"
},
"application/senml-etch+json": {
"source": "iana",
"compressible": true
},
"application/senml-exi": {
"source": "iana"
},
"application/sensml+cbor": {
"source": "iana"
},
"application/sensml+json": {
"source": "iana",
"compressible": true
},
"application/sensml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["sensmlx"]
},
"application/sensml-exi": {
"source": "iana"
},
"application/sep+xml": {
"source": "iana",
"compressible": true
},
"application/sep-exi": {
"source": "iana"
},
"application/session-info": {
"source": "iana"
},
"application/set-payment": {
"source": "iana"
},
"application/set-payment-initiation": {
"source": "iana",
"extensions": ["setpay"]
},
"application/set-registration": {
"source": "iana"
},
"application/set-registration-initiation": {
"source": "iana",
"extensions": ["setreg"]
},
"application/sgml": {
"source": "iana"
},
"application/sgml-open-catalog": {
"source": "iana"
},
"application/shf+xml": {
"source": "iana",
"compressible": true,
"extensions": ["shf"]
},
"application/sieve": {
"source": "iana",
"extensions": ["siv","sieve"]
},
"application/simple-filter+xml": {
"source": "iana",
"compressible": true
},
"application/simple-message-summary": {
"source": "iana"
},
"application/simplesymbolcontainer": {
"source": "iana"
},
"application/sipc": {
"source": "iana"
},
"application/slate": {
"source": "iana"
},
"application/smil": {
"source": "iana"
},
"application/smil+xml": {
"source": "iana",
"compressible": true,
"extensions": ["smi","smil"]
},
"application/smpte336m": {
"source": "iana"
},
"application/soap+fastinfoset": {
"source": "iana"
},
"application/soap+xml": {
"source": "iana",
"compressible": true
},
"application/sparql-query": {
"source": "iana",
"extensions": ["rq"]
},
"application/sparql-results+xml": {
"source": "iana",
"compressible": true,
"extensions": ["srx"]
},
"application/spirits-event+xml": {
"source": "iana",
"compressible": true
},
"application/sql": {
"source": "iana"
},
"application/srgs": {
"source": "iana",
"extensions": ["gram"]
},
"application/srgs+xml": {
"source": "iana",
"compressible": true,
"extensions": ["grxml"]
},
"application/sru+xml": {
"source": "iana",
"compressible": true,
"extensions": ["sru"]
},
"application/ssdl+xml": {
"source": "apache",
"compressible": true,
"extensions": ["ssdl"]
},
"application/ssml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["ssml"]
},
"application/stix+json": {
"source": "iana",
"compressible": true
},
"application/swid+xml": {
"source": "iana",
"compressible": true,
"extensions": ["swidtag"]
},
"application/tamp-apex-update": {
"source": "iana"
},
"application/tamp-apex-update-confirm": {
"source": "iana"
},
"application/tamp-community-update": {
"source": "iana"
},
"application/tamp-community-update-confirm": {
"source": "iana"
},
"application/tamp-error": {
"source": "iana"
},
"application/tamp-sequence-adjust": {
"source": "iana"
},
"application/tamp-sequence-adjust-confirm": {
"source": "iana"
},
"application/tamp-status-query": {
"source": "iana"
},
"application/tamp-status-response": {
"source": "iana"
},
"application/tamp-update": {
"source": "iana"
},
"application/tamp-update-confirm": {
"source": "iana"
},
"application/tar": {
"compressible": true
},
"application/taxii+json": {
"source": "iana",
"compressible": true
},
"application/td+json": {
"source": "iana",
"compressible": true
},
"application/tei+xml": {
"source": "iana",
"compressible": true,
"extensions": ["tei","teicorpus"]
},
"application/tetra_isi": {
"source": "iana"
},
"application/thraud+xml": {
"source": "iana",
"compressible": true,
"extensions": ["tfi"]
},
"application/timestamp-query": {
"source": "iana"
},
"application/timestamp-reply": {
"source": "iana"
},
"application/timestamped-data": {
"source": "iana",
"extensions": ["tsd"]
},
"application/tlsrpt+gzip": {
"source": "iana"
},
"application/tlsrpt+json": {
"source": "iana",
"compressible": true
},
"application/tnauthlist": {
"source": "iana"
},
"application/toml": {
"compressible": true,
"extensions": ["toml"]
},
"application/trickle-ice-sdpfrag": {
"source": "iana"
},
"application/trig": {
"source": "iana"
},
"application/ttml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["ttml"]
},
"application/tve-trigger": {
"source": "iana"
},
"application/tzif": {
"source": "iana"
},
"application/tzif-leap": {
"source": "iana"
},
"application/ulpfec": {
"source": "iana"
},
"application/urc-grpsheet+xml": {
"source": "iana",
"compressible": true
},
"application/urc-ressheet+xml": {
"source": "iana",
"compressible": true,
"extensions": ["rsheet"]
},
"application/urc-targetdesc+xml": {
"source": "iana",
"compressible": true
},
"application/urc-uisocketdesc+xml": {
"source": "iana",
"compressible": true
},
"application/vcard+json": {
"source": "iana",
"compressible": true
},
"application/vcard+xml": {
"source": "iana",
"compressible": true
},
"application/vemmi": {
"source": "iana"
},
"application/vividence.scriptfile": {
"source": "apache"
},
"application/vnd.1000minds.decision-model+xml": {
"source": "iana",
"compressible": true,
"extensions": ["1km"]
},
"application/vnd.3gpp-prose+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp-prose-pc3ch+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp-v2x-local-service-information": {
"source": "iana"
},
"application/vnd.3gpp.access-transfer-events+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.bsf+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.gmop+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mc-signalling-ear": {
"source": "iana"
},
"application/vnd.3gpp.mcdata-affiliation-command+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcdata-info+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcdata-payload": {
"source": "iana"
},
"application/vnd.3gpp.mcdata-service-config+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcdata-signalling": {
"source": "iana"
},
"application/vnd.3gpp.mcdata-ue-config+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcdata-user-profile+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcptt-affiliation-command+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcptt-floor-request+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcptt-info+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcptt-location-info+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcptt-mbms-usage-info+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcptt-service-config+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcptt-signed+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcptt-ue-config+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcptt-ue-init-config+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcptt-user-profile+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcvideo-affiliation-command+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcvideo-affiliation-info+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcvideo-info+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcvideo-location-info+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcvideo-mbms-usage-info+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcvideo-service-config+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcvideo-transmission-request+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcvideo-ue-config+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mcvideo-user-profile+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.mid-call+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.pic-bw-large": {
"source": "iana",
"extensions": ["plb"]
},
"application/vnd.3gpp.pic-bw-small": {
"source": "iana",
"extensions": ["psb"]
},
"application/vnd.3gpp.pic-bw-var": {
"source": "iana",
"extensions": ["pvb"]
},
"application/vnd.3gpp.sms": {
"source": "iana"
},
"application/vnd.3gpp.sms+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.srvcc-ext+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.srvcc-info+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.state-and-event-info+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp.ussd+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp2.bcmcsinfo+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.3gpp2.sms": {
"source": "iana"
},
"application/vnd.3gpp2.tcap": {
"source": "iana",
"extensions": ["tcap"]
},
"application/vnd.3lightssoftware.imagescal": {
"source": "iana"
},
"application/vnd.3m.post-it-notes": {
"source": "iana",
"extensions": ["pwn"]
},
"application/vnd.accpac.simply.aso": {
"source": "iana",
"extensions": ["aso"]
},
"application/vnd.accpac.simply.imp": {
"source": "iana",
"extensions": ["imp"]
},
"application/vnd.acucobol": {
"source": "iana",
"extensions": ["acu"]
},
"application/vnd.acucorp": {
"source": "iana",
"extensions": ["atc","acutc"]
},
"application/vnd.adobe.air-application-installer-package+zip": {
"source": "apache",
"compressible": false,
"extensions": ["air"]
},
"application/vnd.adobe.flash.movie": {
"source": "iana"
},
"application/vnd.adobe.formscentral.fcdt": {
"source": "iana",
"extensions": ["fcdt"]
},
"application/vnd.adobe.fxp": {
"source": "iana",
"extensions": ["fxp","fxpl"]
},
"application/vnd.adobe.partial-upload": {
"source": "iana"
},
"application/vnd.adobe.xdp+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xdp"]
},
"application/vnd.adobe.xfdf": {
"source": "iana",
"extensions": ["xfdf"]
},
"application/vnd.aether.imp": {
"source": "iana"
},
"application/vnd.afpc.afplinedata": {
"source": "iana"
},
"application/vnd.afpc.afplinedata-pagedef": {
"source": "iana"
},
"application/vnd.afpc.foca-charset": {
"source": "iana"
},
"application/vnd.afpc.foca-codedfont": {
"source": "iana"
},
"application/vnd.afpc.foca-codepage": {
"source": "iana"
},
"application/vnd.afpc.modca": {
"source": "iana"
},
"application/vnd.afpc.modca-formdef": {
"source": "iana"
},
"application/vnd.afpc.modca-mediummap": {
"source": "iana"
},
"application/vnd.afpc.modca-objectcontainer": {
"source": "iana"
},
"application/vnd.afpc.modca-overlay": {
"source": "iana"
},
"application/vnd.afpc.modca-pagesegment": {
"source": "iana"
},
"application/vnd.ah-barcode": {
"source": "iana"
},
"application/vnd.ahead.space": {
"source": "iana",
"extensions": ["ahead"]
},
"application/vnd.airzip.filesecure.azf": {
"source": "iana",
"extensions": ["azf"]
},
"application/vnd.airzip.filesecure.azs": {
"source": "iana",
"extensions": ["azs"]
},
"application/vnd.amadeus+json": {
"source": "iana",
"compressible": true
},
"application/vnd.amazon.ebook": {
"source": "apache",
"extensions": ["azw"]
},
"application/vnd.amazon.mobi8-ebook": {
"source": "iana"
},
"application/vnd.americandynamics.acc": {
"source": "iana",
"extensions": ["acc"]
},
"application/vnd.amiga.ami": {
"source": "iana",
"extensions": ["ami"]
},
"application/vnd.amundsen.maze+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.android.ota": {
"source": "iana"
},
"application/vnd.android.package-archive": {
"source": "apache",
"compressible": false,
"extensions": ["apk"]
},
"application/vnd.anki": {
"source": "iana"
},
"application/vnd.anser-web-certificate-issue-initiation": {
"source": "iana",
"extensions": ["cii"]
},
"application/vnd.anser-web-funds-transfer-initiation": {
"source": "apache",
"extensions": ["fti"]
},
"application/vnd.antix.game-component": {
"source": "iana",
"extensions": ["atx"]
},
"application/vnd.apache.thrift.binary": {
"source": "iana"
},
"application/vnd.apache.thrift.compact": {
"source": "iana"
},
"application/vnd.apache.thrift.json": {
"source": "iana"
},
"application/vnd.api+json": {
"source": "iana",
"compressible": true
},
"application/vnd.aplextor.warrp+json": {
"source": "iana",
"compressible": true
},
"application/vnd.apothekende.reservation+json": {
"source": "iana",
"compressible": true
},
"application/vnd.apple.installer+xml": {
"source": "iana",
"compressible": true,
"extensions": ["mpkg"]
},
"application/vnd.apple.keynote": {
"source": "iana",
"extensions": ["keynote"]
},
"application/vnd.apple.mpegurl": {
"source": "iana",
"extensions": ["m3u8"]
},
"application/vnd.apple.numbers": {
"source": "iana",
"extensions": ["numbers"]
},
"application/vnd.apple.pages": {
"source": "iana",
"extensions": ["pages"]
},
"application/vnd.apple.pkpass": {
"compressible": false,
"extensions": ["pkpass"]
},
"application/vnd.arastra.swi": {
"source": "iana"
},
"application/vnd.aristanetworks.swi": {
"source": "iana",
"extensions": ["swi"]
},
"application/vnd.artisan+json": {
"source": "iana",
"compressible": true
},
"application/vnd.artsquare": {
"source": "iana"
},
"application/vnd.astraea-software.iota": {
"source": "iana",
"extensions": ["iota"]
},
"application/vnd.audiograph": {
"source": "iana",
"extensions": ["aep"]
},
"application/vnd.autopackage": {
"source": "iana"
},
"application/vnd.avalon+json": {
"source": "iana",
"compressible": true
},
"application/vnd.avistar+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.balsamiq.bmml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["bmml"]
},
"application/vnd.balsamiq.bmpr": {
"source": "iana"
},
"application/vnd.banana-accounting": {
"source": "iana"
},
"application/vnd.bbf.usp.error": {
"source": "iana"
},
"application/vnd.bbf.usp.msg": {
"source": "iana"
},
"application/vnd.bbf.usp.msg+json": {
"source": "iana",
"compressible": true
},
"application/vnd.bekitzur-stech+json": {
"source": "iana",
"compressible": true
},
"application/vnd.bint.med-content": {
"source": "iana"
},
"application/vnd.biopax.rdf+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.blink-idb-value-wrapper": {
"source": "iana"
},
"application/vnd.blueice.multipass": {
"source": "iana",
"extensions": ["mpm"]
},
"application/vnd.bluetooth.ep.oob": {
"source": "iana"
},
"application/vnd.bluetooth.le.oob": {
"source": "iana"
},
"application/vnd.bmi": {
"source": "iana",
"extensions": ["bmi"]
},
"application/vnd.bpf": {
"source": "iana"
},
"application/vnd.bpf3": {
"source": "iana"
},
"application/vnd.businessobjects": {
"source": "iana",
"extensions": ["rep"]
},
"application/vnd.byu.uapi+json": {
"source": "iana",
"compressible": true
},
"application/vnd.cab-jscript": {
"source": "iana"
},
"application/vnd.canon-cpdl": {
"source": "iana"
},
"application/vnd.canon-lips": {
"source": "iana"
},
"application/vnd.capasystems-pg+json": {
"source": "iana",
"compressible": true
},
"application/vnd.cendio.thinlinc.clientconf": {
"source": "iana"
},
"application/vnd.century-systems.tcp_stream": {
"source": "iana"
},
"application/vnd.chemdraw+xml": {
"source": "iana",
"compressible": true,
"extensions": ["cdxml"]
},
"application/vnd.chess-pgn": {
"source": "iana"
},
"application/vnd.chipnuts.karaoke-mmd": {
"source": "iana",
"extensions": ["mmd"]
},
"application/vnd.ciedi": {
"source": "iana"
},
"application/vnd.cinderella": {
"source": "iana",
"extensions": ["cdy"]
},
"application/vnd.cirpack.isdn-ext": {
"source": "iana"
},
"application/vnd.citationstyles.style+xml": {
"source": "iana",
"compressible": true,
"extensions": ["csl"]
},
"application/vnd.claymore": {
"source": "iana",
"extensions": ["cla"]
},
"application/vnd.cloanto.rp9": {
"source": "iana",
"extensions": ["rp9"]
},
"application/vnd.clonk.c4group": {
"source": "iana",
"extensions": ["c4g","c4d","c4f","c4p","c4u"]
},
"application/vnd.cluetrust.cartomobile-config": {
"source": "iana",
"extensions": ["c11amc"]
},
"application/vnd.cluetrust.cartomobile-config-pkg": {
"source": "iana",
"extensions": ["c11amz"]
},
"application/vnd.coffeescript": {
"source": "iana"
},
"application/vnd.collabio.xodocuments.document": {
"source": "iana"
},
"application/vnd.collabio.xodocuments.document-template": {
"source": "iana"
},
"application/vnd.collabio.xodocuments.presentation": {
"source": "iana"
},
"application/vnd.collabio.xodocuments.presentation-template": {
"source": "iana"
},
"application/vnd.collabio.xodocuments.spreadsheet": {
"source": "iana"
},
"application/vnd.collabio.xodocuments.spreadsheet-template": {
"source": "iana"
},
"application/vnd.collection+json": {
"source": "iana",
"compressible": true
},
"application/vnd.collection.doc+json": {
"source": "iana",
"compressible": true
},
"application/vnd.collection.next+json": {
"source": "iana",
"compressible": true
},
"application/vnd.comicbook+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.comicbook-rar": {
"source": "iana"
},
"application/vnd.commerce-battelle": {
"source": "iana"
},
"application/vnd.commonspace": {
"source": "iana",
"extensions": ["csp"]
},
"application/vnd.contact.cmsg": {
"source": "iana",
"extensions": ["cdbcmsg"]
},
"application/vnd.coreos.ignition+json": {
"source": "iana",
"compressible": true
},
"application/vnd.cosmocaller": {
"source": "iana",
"extensions": ["cmc"]
},
"application/vnd.crick.clicker": {
"source": "iana",
"extensions": ["clkx"]
},
"application/vnd.crick.clicker.keyboard": {
"source": "iana",
"extensions": ["clkk"]
},
"application/vnd.crick.clicker.palette": {
"source": "iana",
"extensions": ["clkp"]
},
"application/vnd.crick.clicker.template": {
"source": "iana",
"extensions": ["clkt"]
},
"application/vnd.crick.clicker.wordbank": {
"source": "iana",
"extensions": ["clkw"]
},
"application/vnd.criticaltools.wbs+xml": {
"source": "iana",
"compressible": true,
"extensions": ["wbs"]
},
"application/vnd.cryptii.pipe+json": {
"source": "iana",
"compressible": true
},
"application/vnd.crypto-shade-file": {
"source": "iana"
},
"application/vnd.ctc-posml": {
"source": "iana",
"extensions": ["pml"]
},
"application/vnd.ctct.ws+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.cups-pdf": {
"source": "iana"
},
"application/vnd.cups-postscript": {
"source": "iana"
},
"application/vnd.cups-ppd": {
"source": "iana",
"extensions": ["ppd"]
},
"application/vnd.cups-raster": {
"source": "iana"
},
"application/vnd.cups-raw": {
"source": "iana"
},
"application/vnd.curl": {
"source": "iana"
},
"application/vnd.curl.car": {
"source": "apache",
"extensions": ["car"]
},
"application/vnd.curl.pcurl": {
"source": "apache",
"extensions": ["pcurl"]
},
"application/vnd.cyan.dean.root+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.cybank": {
"source": "iana"
},
"application/vnd.d2l.coursepackage1p0+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.dart": {
"source": "iana",
"compressible": true,
"extensions": ["dart"]
},
"application/vnd.data-vision.rdz": {
"source": "iana",
"extensions": ["rdz"]
},
"application/vnd.datapackage+json": {
"source": "iana",
"compressible": true
},
"application/vnd.dataresource+json": {
"source": "iana",
"compressible": true
},
"application/vnd.dbf": {
"source": "iana"
},
"application/vnd.debian.binary-package": {
"source": "iana"
},
"application/vnd.dece.data": {
"source": "iana",
"extensions": ["uvf","uvvf","uvd","uvvd"]
},
"application/vnd.dece.ttml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["uvt","uvvt"]
},
"application/vnd.dece.unspecified": {
"source": "iana",
"extensions": ["uvx","uvvx"]
},
"application/vnd.dece.zip": {
"source": "iana",
"extensions": ["uvz","uvvz"]
},
"application/vnd.denovo.fcselayout-link": {
"source": "iana",
"extensions": ["fe_launch"]
},
"application/vnd.desmume.movie": {
"source": "iana"
},
"application/vnd.dir-bi.plate-dl-nosuffix": {
"source": "iana"
},
"application/vnd.dm.delegation+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.dna": {
"source": "iana",
"extensions": ["dna"]
},
"application/vnd.document+json": {
"source": "iana",
"compressible": true
},
"application/vnd.dolby.mlp": {
"source": "apache",
"extensions": ["mlp"]
},
"application/vnd.dolby.mobile.1": {
"source": "iana"
},
"application/vnd.dolby.mobile.2": {
"source": "iana"
},
"application/vnd.doremir.scorecloud-binary-document": {
"source": "iana"
},
"application/vnd.dpgraph": {
"source": "iana",
"extensions": ["dpg"]
},
"application/vnd.dreamfactory": {
"source": "iana",
"extensions": ["dfac"]
},
"application/vnd.drive+json": {
"source": "iana",
"compressible": true
},
"application/vnd.ds-keypoint": {
"source": "apache",
"extensions": ["kpxx"]
},
"application/vnd.dtg.local": {
"source": "iana"
},
"application/vnd.dtg.local.flash": {
"source": "iana"
},
"application/vnd.dtg.local.html": {
"source": "iana"
},
"application/vnd.dvb.ait": {
"source": "iana",
"extensions": ["ait"]
},
"application/vnd.dvb.dvbisl+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.dvb.dvbj": {
"source": "iana"
},
"application/vnd.dvb.esgcontainer": {
"source": "iana"
},
"application/vnd.dvb.ipdcdftnotifaccess": {
"source": "iana"
},
"application/vnd.dvb.ipdcesgaccess": {
"source": "iana"
},
"application/vnd.dvb.ipdcesgaccess2": {
"source": "iana"
},
"application/vnd.dvb.ipdcesgpdd": {
"source": "iana"
},
"application/vnd.dvb.ipdcroaming": {
"source": "iana"
},
"application/vnd.dvb.iptv.alfec-base": {
"source": "iana"
},
"application/vnd.dvb.iptv.alfec-enhancement": {
"source": "iana"
},
"application/vnd.dvb.notif-aggregate-root+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.dvb.notif-container+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.dvb.notif-generic+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.dvb.notif-ia-msglist+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.dvb.notif-ia-registration-request+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.dvb.notif-ia-registration-response+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.dvb.notif-init+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.dvb.pfr": {
"source": "iana"
},
"application/vnd.dvb.service": {
"source": "iana",
"extensions": ["svc"]
},
"application/vnd.dxr": {
"source": "iana"
},
"application/vnd.dynageo": {
"source": "iana",
"extensions": ["geo"]
},
"application/vnd.dzr": {
"source": "iana"
},
"application/vnd.easykaraoke.cdgdownload": {
"source": "iana"
},
"application/vnd.ecdis-update": {
"source": "iana"
},
"application/vnd.ecip.rlp": {
"source": "iana"
},
"application/vnd.ecowin.chart": {
"source": "iana",
"extensions": ["mag"]
},
"application/vnd.ecowin.filerequest": {
"source": "iana"
},
"application/vnd.ecowin.fileupdate": {
"source": "iana"
},
"application/vnd.ecowin.series": {
"source": "iana"
},
"application/vnd.ecowin.seriesrequest": {
"source": "iana"
},
"application/vnd.ecowin.seriesupdate": {
"source": "iana"
},
"application/vnd.efi.img": {
"source": "iana"
},
"application/vnd.efi.iso": {
"source": "iana"
},
"application/vnd.emclient.accessrequest+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.enliven": {
"source": "iana",
"extensions": ["nml"]
},
"application/vnd.enphase.envoy": {
"source": "iana"
},
"application/vnd.eprints.data+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.epson.esf": {
"source": "iana",
"extensions": ["esf"]
},
"application/vnd.epson.msf": {
"source": "iana",
"extensions": ["msf"]
},
"application/vnd.epson.quickanime": {
"source": "iana",
"extensions": ["qam"]
},
"application/vnd.epson.salt": {
"source": "iana",
"extensions": ["slt"]
},
"application/vnd.epson.ssf": {
"source": "iana",
"extensions": ["ssf"]
},
"application/vnd.ericsson.quickcall": {
"source": "iana"
},
"application/vnd.espass-espass+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.eszigno3+xml": {
"source": "iana",
"compressible": true,
"extensions": ["es3","et3"]
},
"application/vnd.etsi.aoc+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.asic-e+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.etsi.asic-s+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.etsi.cug+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.iptvcommand+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.iptvdiscovery+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.iptvprofile+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.iptvsad-bc+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.iptvsad-cod+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.iptvsad-npvr+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.iptvservice+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.iptvsync+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.iptvueprofile+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.mcid+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.mheg5": {
"source": "iana"
},
"application/vnd.etsi.overload-control-policy-dataset+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.pstn+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.sci+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.simservs+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.timestamp-token": {
"source": "iana"
},
"application/vnd.etsi.tsl+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.etsi.tsl.der": {
"source": "iana"
},
"application/vnd.eudora.data": {
"source": "iana"
},
"application/vnd.evolv.ecig.profile": {
"source": "iana"
},
"application/vnd.evolv.ecig.settings": {
"source": "iana"
},
"application/vnd.evolv.ecig.theme": {
"source": "iana"
},
"application/vnd.exstream-empower+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.exstream-package": {
"source": "iana"
},
"application/vnd.ezpix-album": {
"source": "iana",
"extensions": ["ez2"]
},
"application/vnd.ezpix-package": {
"source": "iana",
"extensions": ["ez3"]
},
"application/vnd.f-secure.mobile": {
"source": "iana"
},
"application/vnd.fastcopy-disk-image": {
"source": "iana"
},
"application/vnd.fdf": {
"source": "iana",
"extensions": ["fdf"]
},
"application/vnd.fdsn.mseed": {
"source": "iana",
"extensions": ["mseed"]
},
"application/vnd.fdsn.seed": {
"source": "iana",
"extensions": ["seed","dataless"]
},
"application/vnd.ffsns": {
"source": "iana"
},
"application/vnd.ficlab.flb+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.filmit.zfc": {
"source": "iana"
},
"application/vnd.fints": {
"source": "iana"
},
"application/vnd.firemonkeys.cloudcell": {
"source": "iana"
},
"application/vnd.flographit": {
"source": "iana",
"extensions": ["gph"]
},
"application/vnd.fluxtime.clip": {
"source": "iana",
"extensions": ["ftc"]
},
"application/vnd.font-fontforge-sfd": {
"source": "iana"
},
"application/vnd.framemaker": {
"source": "iana",
"extensions": ["fm","frame","maker","book"]
},
"application/vnd.frogans.fnc": {
"source": "iana",
"extensions": ["fnc"]
},
"application/vnd.frogans.ltf": {
"source": "iana",
"extensions": ["ltf"]
},
"application/vnd.fsc.weblaunch": {
"source": "iana",
"extensions": ["fsc"]
},
"application/vnd.fujitsu.oasys": {
"source": "iana",
"extensions": ["oas"]
},
"application/vnd.fujitsu.oasys2": {
"source": "iana",
"extensions": ["oa2"]
},
"application/vnd.fujitsu.oasys3": {
"source": "iana",
"extensions": ["oa3"]
},
"application/vnd.fujitsu.oasysgp": {
"source": "iana",
"extensions": ["fg5"]
},
"application/vnd.fujitsu.oasysprs": {
"source": "iana",
"extensions": ["bh2"]
},
"application/vnd.fujixerox.art-ex": {
"source": "iana"
},
"application/vnd.fujixerox.art4": {
"source": "iana"
},
"application/vnd.fujixerox.ddd": {
"source": "iana",
"extensions": ["ddd"]
},
"application/vnd.fujixerox.docuworks": {
"source": "iana",
"extensions": ["xdw"]
},
"application/vnd.fujixerox.docuworks.binder": {
"source": "iana",
"extensions": ["xbd"]
},
"application/vnd.fujixerox.docuworks.container": {
"source": "iana"
},
"application/vnd.fujixerox.hbpl": {
"source": "iana"
},
"application/vnd.fut-misnet": {
"source": "iana"
},
"application/vnd.futoin+cbor": {
"source": "iana"
},
"application/vnd.futoin+json": {
"source": "iana",
"compressible": true
},
"application/vnd.fuzzysheet": {
"source": "iana",
"extensions": ["fzs"]
},
"application/vnd.genomatix.tuxedo": {
"source": "iana",
"extensions": ["txd"]
},
"application/vnd.gentics.grd+json": {
"source": "iana",
"compressible": true
},
"application/vnd.geo+json": {
"source": "iana",
"compressible": true
},
"application/vnd.geocube+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.geogebra.file": {
"source": "iana",
"extensions": ["ggb"]
},
"application/vnd.geogebra.tool": {
"source": "iana",
"extensions": ["ggt"]
},
"application/vnd.geometry-explorer": {
"source": "iana",
"extensions": ["gex","gre"]
},
"application/vnd.geonext": {
"source": "iana",
"extensions": ["gxt"]
},
"application/vnd.geoplan": {
"source": "iana",
"extensions": ["g2w"]
},
"application/vnd.geospace": {
"source": "iana",
"extensions": ["g3w"]
},
"application/vnd.gerber": {
"source": "iana"
},
"application/vnd.globalplatform.card-content-mgt": {
"source": "iana"
},
"application/vnd.globalplatform.card-content-mgt-response": {
"source": "iana"
},
"application/vnd.gmx": {
"source": "iana",
"extensions": ["gmx"]
},
"application/vnd.google-apps.document": {
"compressible": false,
"extensions": ["gdoc"]
},
"application/vnd.google-apps.presentation": {
"compressible": false,
"extensions": ["gslides"]
},
"application/vnd.google-apps.spreadsheet": {
"compressible": false,
"extensions": ["gsheet"]
},
"application/vnd.google-earth.kml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["kml"]
},
"application/vnd.google-earth.kmz": {
"source": "iana",
"compressible": false,
"extensions": ["kmz"]
},
"application/vnd.gov.sk.e-form+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.gov.sk.e-form+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.gov.sk.xmldatacontainer+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.grafeq": {
"source": "iana",
"extensions": ["gqf","gqs"]
},
"application/vnd.gridmp": {
"source": "iana"
},
"application/vnd.groove-account": {
"source": "iana",
"extensions": ["gac"]
},
"application/vnd.groove-help": {
"source": "iana",
"extensions": ["ghf"]
},
"application/vnd.groove-identity-message": {
"source": "iana",
"extensions": ["gim"]
},
"application/vnd.groove-injector": {
"source": "iana",
"extensions": ["grv"]
},
"application/vnd.groove-tool-message": {
"source": "iana",
"extensions": ["gtm"]
},
"application/vnd.groove-tool-template": {
"source": "iana",
"extensions": ["tpl"]
},
"application/vnd.groove-vcard": {
"source": "iana",
"extensions": ["vcg"]
},
"application/vnd.hal+json": {
"source": "iana",
"compressible": true
},
"application/vnd.hal+xml": {
"source": "iana",
"compressible": true,
"extensions": ["hal"]
},
"application/vnd.handheld-entertainment+xml": {
"source": "iana",
"compressible": true,
"extensions": ["zmm"]
},
"application/vnd.hbci": {
"source": "iana",
"extensions": ["hbci"]
},
"application/vnd.hc+json": {
"source": "iana",
"compressible": true
},
"application/vnd.hcl-bireports": {
"source": "iana"
},
"application/vnd.hdt": {
"source": "iana"
},
"application/vnd.heroku+json": {
"source": "iana",
"compressible": true
},
"application/vnd.hhe.lesson-player": {
"source": "iana",
"extensions": ["les"]
},
"application/vnd.hp-hpgl": {
"source": "iana",
"extensions": ["hpgl"]
},
"application/vnd.hp-hpid": {
"source": "iana",
"extensions": ["hpid"]
},
"application/vnd.hp-hps": {
"source": "iana",
"extensions": ["hps"]
},
"application/vnd.hp-jlyt": {
"source": "iana",
"extensions": ["jlt"]
},
"application/vnd.hp-pcl": {
"source": "iana",
"extensions": ["pcl"]
},
"application/vnd.hp-pclxl": {
"source": "iana",
"extensions": ["pclxl"]
},
"application/vnd.httphone": {
"source": "iana"
},
"application/vnd.hydrostatix.sof-data": {
"source": "iana",
"extensions": ["sfd-hdstx"]
},
"application/vnd.hyper+json": {
"source": "iana",
"compressible": true
},
"application/vnd.hyper-item+json": {
"source": "iana",
"compressible": true
},
"application/vnd.hyperdrive+json": {
"source": "iana",
"compressible": true
},
"application/vnd.hzn-3d-crossword": {
"source": "iana"
},
"application/vnd.ibm.afplinedata": {
"source": "iana"
},
"application/vnd.ibm.electronic-media": {
"source": "iana"
},
"application/vnd.ibm.minipay": {
"source": "iana",
"extensions": ["mpy"]
},
"application/vnd.ibm.modcap": {
"source": "iana",
"extensions": ["afp","listafp","list3820"]
},
"application/vnd.ibm.rights-management": {
"source": "iana",
"extensions": ["irm"]
},
"application/vnd.ibm.secure-container": {
"source": "iana",
"extensions": ["sc"]
},
"application/vnd.iccprofile": {
"source": "iana",
"extensions": ["icc","icm"]
},
"application/vnd.ieee.1905": {
"source": "iana"
},
"application/vnd.igloader": {
"source": "iana",
"extensions": ["igl"]
},
"application/vnd.imagemeter.folder+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.imagemeter.image+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.immervision-ivp": {
"source": "iana",
"extensions": ["ivp"]
},
"application/vnd.immervision-ivu": {
"source": "iana",
"extensions": ["ivu"]
},
"application/vnd.ims.imsccv1p1": {
"source": "iana"
},
"application/vnd.ims.imsccv1p2": {
"source": "iana"
},
"application/vnd.ims.imsccv1p3": {
"source": "iana"
},
"application/vnd.ims.lis.v2.result+json": {
"source": "iana",
"compressible": true
},
"application/vnd.ims.lti.v2.toolconsumerprofile+json": {
"source": "iana",
"compressible": true
},
"application/vnd.ims.lti.v2.toolproxy+json": {
"source": "iana",
"compressible": true
},
"application/vnd.ims.lti.v2.toolproxy.id+json": {
"source": "iana",
"compressible": true
},
"application/vnd.ims.lti.v2.toolsettings+json": {
"source": "iana",
"compressible": true
},
"application/vnd.ims.lti.v2.toolsettings.simple+json": {
"source": "iana",
"compressible": true
},
"application/vnd.informedcontrol.rms+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.informix-visionary": {
"source": "iana"
},
"application/vnd.infotech.project": {
"source": "iana"
},
"application/vnd.infotech.project+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.innopath.wamp.notification": {
"source": "iana"
},
"application/vnd.insors.igm": {
"source": "iana",
"extensions": ["igm"]
},
"application/vnd.intercon.formnet": {
"source": "iana",
"extensions": ["xpw","xpx"]
},
"application/vnd.intergeo": {
"source": "iana",
"extensions": ["i2g"]
},
"application/vnd.intertrust.digibox": {
"source": "iana"
},
"application/vnd.intertrust.nncp": {
"source": "iana"
},
"application/vnd.intu.qbo": {
"source": "iana",
"extensions": ["qbo"]
},
"application/vnd.intu.qfx": {
"source": "iana",
"extensions": ["qfx"]
},
"application/vnd.iptc.g2.catalogitem+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.iptc.g2.conceptitem+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.iptc.g2.knowledgeitem+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.iptc.g2.newsitem+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.iptc.g2.newsmessage+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.iptc.g2.packageitem+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.iptc.g2.planningitem+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.ipunplugged.rcprofile": {
"source": "iana",
"extensions": ["rcprofile"]
},
"application/vnd.irepository.package+xml": {
"source": "iana",
"compressible": true,
"extensions": ["irp"]
},
"application/vnd.is-xpr": {
"source": "iana",
"extensions": ["xpr"]
},
"application/vnd.isac.fcs": {
"source": "iana",
"extensions": ["fcs"]
},
"application/vnd.iso11783-10+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.jam": {
"source": "iana",
"extensions": ["jam"]
},
"application/vnd.japannet-directory-service": {
"source": "iana"
},
"application/vnd.japannet-jpnstore-wakeup": {
"source": "iana"
},
"application/vnd.japannet-payment-wakeup": {
"source": "iana"
},
"application/vnd.japannet-registration": {
"source": "iana"
},
"application/vnd.japannet-registration-wakeup": {
"source": "iana"
},
"application/vnd.japannet-setstore-wakeup": {
"source": "iana"
},
"application/vnd.japannet-verification": {
"source": "iana"
},
"application/vnd.japannet-verification-wakeup": {
"source": "iana"
},
"application/vnd.jcp.javame.midlet-rms": {
"source": "iana",
"extensions": ["rms"]
},
"application/vnd.jisp": {
"source": "iana",
"extensions": ["jisp"]
},
"application/vnd.joost.joda-archive": {
"source": "iana",
"extensions": ["joda"]
},
"application/vnd.jsk.isdn-ngn": {
"source": "iana"
},
"application/vnd.kahootz": {
"source": "iana",
"extensions": ["ktz","ktr"]
},
"application/vnd.kde.karbon": {
"source": "iana",
"extensions": ["karbon"]
},
"application/vnd.kde.kchart": {
"source": "iana",
"extensions": ["chrt"]
},
"application/vnd.kde.kformula": {
"source": "iana",
"extensions": ["kfo"]
},
"application/vnd.kde.kivio": {
"source": "iana",
"extensions": ["flw"]
},
"application/vnd.kde.kontour": {
"source": "iana",
"extensions": ["kon"]
},
"application/vnd.kde.kpresenter": {
"source": "iana",
"extensions": ["kpr","kpt"]
},
"application/vnd.kde.kspread": {
"source": "iana",
"extensions": ["ksp"]
},
"application/vnd.kde.kword": {
"source": "iana",
"extensions": ["kwd","kwt"]
},
"application/vnd.kenameaapp": {
"source": "iana",
"extensions": ["htke"]
},
"application/vnd.kidspiration": {
"source": "iana",
"extensions": ["kia"]
},
"application/vnd.kinar": {
"source": "iana",
"extensions": ["kne","knp"]
},
"application/vnd.koan": {
"source": "iana",
"extensions": ["skp","skd","skt","skm"]
},
"application/vnd.kodak-descriptor": {
"source": "iana",
"extensions": ["sse"]
},
"application/vnd.las": {
"source": "iana"
},
"application/vnd.las.las+json": {
"source": "iana",
"compressible": true
},
"application/vnd.las.las+xml": {
"source": "iana",
"compressible": true,
"extensions": ["lasxml"]
},
"application/vnd.laszip": {
"source": "iana"
},
"application/vnd.leap+json": {
"source": "iana",
"compressible": true
},
"application/vnd.liberty-request+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.llamagraphics.life-balance.desktop": {
"source": "iana",
"extensions": ["lbd"]
},
"application/vnd.llamagraphics.life-balance.exchange+xml": {
"source": "iana",
"compressible": true,
"extensions": ["lbe"]
},
"application/vnd.logipipe.circuit+zip": {
"source": "iana",
"compressible": false
},
"application/vnd.loom": {
"source": "iana"
},
"application/vnd.lotus-1-2-3": {
"source": "iana",
"extensions": ["123"]
},
"application/vnd.lotus-approach": {
"source": "iana",
"extensions": ["apr"]
},
"application/vnd.lotus-freelance": {
"source": "iana",
"extensions": ["pre"]
},
"application/vnd.lotus-notes": {
"source": "iana",
"extensions": ["nsf"]
},
"application/vnd.lotus-organizer": {
"source": "iana",
"extensions": ["org"]
},
"application/vnd.lotus-screencam": {
"source": "iana",
"extensions": ["scm"]
},
"application/vnd.lotus-wordpro": {
"source": "iana",
"extensions": ["lwp"]
},
"application/vnd.macports.portpkg": {
"source": "iana",
"extensions": ["portpkg"]
},
"application/vnd.mapbox-vector-tile": {
"source": "iana"
},
"application/vnd.marlin.drm.actiontoken+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.marlin.drm.conftoken+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.marlin.drm.license+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.marlin.drm.mdcf": {
"source": "iana"
},
"application/vnd.mason+json": {
"source": "iana",
"compressible": true
},
"application/vnd.maxmind.maxmind-db": {
"source": "iana"
},
"application/vnd.mcd": {
"source": "iana",
"extensions": ["mcd"]
},
"application/vnd.medcalcdata": {
"source": "iana",
"extensions": ["mc1"]
},
"application/vnd.mediastation.cdkey": {
"source": "iana",
"extensions": ["cdkey"]
},
"application/vnd.meridian-slingshot": {
"source": "iana"
},
"application/vnd.mfer": {
"source": "iana",
"extensions": ["mwf"]
},
"application/vnd.mfmp": {
"source": "iana",
"extensions": ["mfm"]
},
"application/vnd.micro+json": {
"source": "iana",
"compressible": true
},
"application/vnd.micrografx.flo": {
"source": "iana",
"extensions": ["flo"]
},
"application/vnd.micrografx.igx": {
"source": "iana",
"extensions": ["igx"]
},
"application/vnd.microsoft.portable-executable": {
"source": "iana"
},
"application/vnd.microsoft.windows.thumbnail-cache": {
"source": "iana"
},
"application/vnd.miele+json": {
"source": "iana",
"compressible": true
},
"application/vnd.mif": {
"source": "iana",
"extensions": ["mif"]
},
"application/vnd.minisoft-hp3000-save": {
"source": "iana"
},
"application/vnd.mitsubishi.misty-guard.trustweb": {
"source": "iana"
},
"application/vnd.mobius.daf": {
"source": "iana",
"extensions": ["daf"]
},
"application/vnd.mobius.dis": {
"source": "iana",
"extensions": ["dis"]
},
"application/vnd.mobius.mbk": {
"source": "iana",
"extensions": ["mbk"]
},
"application/vnd.mobius.mqy": {
"source": "iana",
"extensions": ["mqy"]
},
"application/vnd.mobius.msl": {
"source": "iana",
"extensions": ["msl"]
},
"application/vnd.mobius.plc": {
"source": "iana",
"extensions": ["plc"]
},
"application/vnd.mobius.txf": {
"source": "iana",
"extensions": ["txf"]
},
"application/vnd.mophun.application": {
"source": "iana",
"extensions": ["mpn"]
},
"application/vnd.mophun.certificate": {
"source": "iana",
"extensions": ["mpc"]
},
"application/vnd.motorola.flexsuite": {
"source": "iana"
},
"application/vnd.motorola.flexsuite.adsi": {
"source": "iana"
},
"application/vnd.motorola.flexsuite.fis": {
"source": "iana"
},
"application/vnd.motorola.flexsuite.gotap": {
"source": "iana"
},
"application/vnd.motorola.flexsuite.kmr": {
"source": "iana"
},
"application/vnd.motorola.flexsuite.ttc": {
"source": "iana"
},
"application/vnd.motorola.flexsuite.wem": {
"source": "iana"
},
"application/vnd.motorola.iprm": {
"source": "iana"
},
"application/vnd.mozilla.xul+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xul"]
},
"application/vnd.ms-3mfdocument": {
"source": "iana"
},
"application/vnd.ms-artgalry": {
"source": "iana",
"extensions": ["cil"]
},
"application/vnd.ms-asf": {
"source": "iana"
},
"application/vnd.ms-cab-compressed": {
"source": "iana",
"extensions": ["cab"]
},
"application/vnd.ms-color.iccprofile": {
"source": "apache"
},
"application/vnd.ms-excel": {
"source": "iana",
"compressible": false,
"extensions": ["xls","xlm","xla","xlc","xlt","xlw"]
},
"application/vnd.ms-excel.addin.macroenabled.12": {
"source": "iana",
"extensions": ["xlam"]
},
"application/vnd.ms-excel.sheet.binary.macroenabled.12": {
"source": "iana",
"extensions": ["xlsb"]
},
"application/vnd.ms-excel.sheet.macroenabled.12": {
"source": "iana",
"extensions": ["xlsm"]
},
"application/vnd.ms-excel.template.macroenabled.12": {
"source": "iana",
"extensions": ["xltm"]
},
"application/vnd.ms-fontobject": {
"source": "iana",
"compressible": true,
"extensions": ["eot"]
},
"application/vnd.ms-htmlhelp": {
"source": "iana",
"extensions": ["chm"]
},
"application/vnd.ms-ims": {
"source": "iana",
"extensions": ["ims"]
},
"application/vnd.ms-lrm": {
"source": "iana",
"extensions": ["lrm"]
},
"application/vnd.ms-office.activex+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.ms-officetheme": {
"source": "iana",
"extensions": ["thmx"]
},
"application/vnd.ms-opentype": {
"source": "apache",
"compressible": true
},
"application/vnd.ms-outlook": {
"compressible": false,
"extensions": ["msg"]
},
"application/vnd.ms-package.obfuscated-opentype": {
"source": "apache"
},
"application/vnd.ms-pki.seccat": {
"source": "apache",
"extensions": ["cat"]
},
"application/vnd.ms-pki.stl": {
"source": "apache",
"extensions": ["stl"]
},
"application/vnd.ms-playready.initiator+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.ms-powerpoint": {
"source": "iana",
"compressible": false,
"extensions": ["ppt","pps","pot"]
},
"application/vnd.ms-powerpoint.addin.macroenabled.12": {
"source": "iana",
"extensions": ["ppam"]
},
"application/vnd.ms-powerpoint.presentation.macroenabled.12": {
"source": "iana",
"extensions": ["pptm"]
},
"application/vnd.ms-powerpoint.slide.macroenabled.12": {
"source": "iana",
"extensions": ["sldm"]
},
"application/vnd.ms-powerpoint.slideshow.macroenabled.12": {
"source": "iana",
"extensions": ["ppsm"]
},
"application/vnd.ms-powerpoint.template.macroenabled.12": {
"source": "iana",
"extensions": ["potm"]
},
"application/vnd.ms-printdevicecapabilities+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.ms-printing.printticket+xml": {
"source": "apache",
"compressible": true
},
"application/vnd.ms-printschematicket+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.ms-project": {
"source": "iana",
"extensions": ["mpp","mpt"]
},
"application/vnd.ms-tnef": {
"source": "iana"
},
"application/vnd.ms-windows.devicepairing": {
"source": "iana"
},
"application/vnd.ms-windows.nwprinting.oob": {
"source": "iana"
},
"application/vnd.ms-windows.printerpairing": {
"source": "iana"
},
"application/vnd.ms-windows.wsd.oob": {
"source": "iana"
},
"application/vnd.ms-wmdrm.lic-chlg-req": {
"source": "iana"
},
"application/vnd.ms-wmdrm.lic-resp": {
"source": "iana"
},
"application/vnd.ms-wmdrm.meter-chlg-req": {
"source": "iana"
},
"application/vnd.ms-wmdrm.meter-resp": {
"source": "iana"
},
"application/vnd.ms-word.document.macroenabled.12": {
"source": "iana",
"extensions": ["docm"]
},
"application/vnd.ms-word.template.macroenabled.12": {
"source": "iana",
"extensions": ["dotm"]
},
"application/vnd.ms-works": {
"source": "iana",
"extensions": ["wps","wks","wcm","wdb"]
},
"application/vnd.ms-wpl": {
"source": "iana",
"extensions": ["wpl"]
},
"application/vnd.ms-xpsdocument": {
"source": "iana",
"compressible": false,
"extensions": ["xps"]
},
"application/vnd.msa-disk-image": {
"source": "iana"
},
"application/vnd.mseq": {
"source": "iana",
"extensions": ["mseq"]
},
"application/vnd.msign": {
"source": "iana"
},
"application/vnd.multiad.creator": {
"source": "iana"
},
"application/vnd.multiad.creator.cif": {
"source": "iana"
},
"application/vnd.music-niff": {
"source": "iana"
},
"application/vnd.musician": {
"source": "iana",
"extensions": ["mus"]
},
"application/vnd.muvee.style": {
"source": "iana",
"extensions": ["msty"]
},
"application/vnd.mynfc": {
"source": "iana",
"extensions": ["taglet"]
},
"application/vnd.ncd.control": {
"source": "iana"
},
"application/vnd.ncd.reference": {
"source": "iana"
},
"application/vnd.nearst.inv+json": {
"source": "iana",
"compressible": true
},
"application/vnd.nervana": {
"source": "iana"
},
"application/vnd.netfpx": {
"source": "iana"
},
"application/vnd.neurolanguage.nlu": {
"source": "iana",
"extensions": ["nlu"]
},
"application/vnd.nimn": {
"source": "iana"
},
"application/vnd.nintendo.nitro.rom": {
"source": "iana"
},
"application/vnd.nintendo.snes.rom": {
"source": "iana"
},
"application/vnd.nitf": {
"source": "iana",
"extensions": ["ntf","nitf"]
},
"application/vnd.noblenet-directory": {
"source": "iana",
"extensions": ["nnd"]
},
"application/vnd.noblenet-sealer": {
"source": "iana",
"extensions": ["nns"]
},
"application/vnd.noblenet-web": {
"source": "iana",
"extensions": ["nnw"]
},
"application/vnd.nokia.catalogs": {
"source": "iana"
},
"application/vnd.nokia.conml+wbxml": {
"source": "iana"
},
"application/vnd.nokia.conml+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.nokia.iptv.config+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.nokia.isds-radio-presets": {
"source": "iana"
},
"application/vnd.nokia.landmark+wbxml": {
"source": "iana"
},
"application/vnd.nokia.landmark+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.nokia.landmarkcollection+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.nokia.n-gage.ac+xml": {
"source": "iana",
"compressible": true,
"extensions": ["ac"]
},
"application/vnd.nokia.n-gage.data": {
"source": "iana",
"extensions": ["ngdat"]
},
"application/vnd.nokia.n-gage.symbian.install": {
"source": "iana",
"extensions": ["n-gage"]
},
"application/vnd.nokia.ncd": {
"source": "iana"
},
"application/vnd.nokia.pcd+wbxml": {
"source": "iana"
},
"application/vnd.nokia.pcd+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.nokia.radio-preset": {
"source": "iana",
"extensions": ["rpst"]
},
"application/vnd.nokia.radio-presets": {
"source": "iana",
"extensions": ["rpss"]
},
"application/vnd.novadigm.edm": {
"source": "iana",
"extensions": ["edm"]
},
"application/vnd.novadigm.edx": {
"source": "iana",
"extensions": ["edx"]
},
"application/vnd.novadigm.ext": {
"source": "iana",
"extensions": ["ext"]
},
"application/vnd.ntt-local.content-share": {
"source": "iana"
},
"application/vnd.ntt-local.file-transfer": {
"source": "iana"
},
"application/vnd.ntt-local.ogw_remote-access": {
"source": "iana"
},
"application/vnd.ntt-local.sip-ta_remote": {
"source": "iana"
},
"application/vnd.ntt-local.sip-ta_tcp_stream": {
"source": "iana"
},
"application/vnd.oasis.opendocument.chart": {
"source": "iana",
"extensions": ["odc"]
},
"application/vnd.oasis.opendocument.chart-template": {
"source": "iana",
"extensions": ["otc"]
},
"application/vnd.oasis.opendocument.database": {
"source": "iana",
"extensions": ["odb"]
},
"application/vnd.oasis.opendocument.formula": {
"source": "iana",
"extensions": ["odf"]
},
"application/vnd.oasis.opendocument.formula-template": {
"source": "iana",
"extensions": ["odft"]
},
"application/vnd.oasis.opendocument.graphics": {
"source": "iana",
"compressible": false,
"extensions": ["odg"]
},
"application/vnd.oasis.opendocument.graphics-template": {
"source": "iana",
"extensions": ["otg"]
},
"application/vnd.oasis.opendocument.image": {
"source": "iana",
"extensions": ["odi"]
},
"application/vnd.oasis.opendocument.image-template": {
"source": "iana",
"extensions": ["oti"]
},
"application/vnd.oasis.opendocument.presentation": {
"source": "iana",
"compressible": false,
"extensions": ["odp"]
},
"application/vnd.oasis.opendocument.presentation-template": {
"source": "iana",
"extensions": ["otp"]
},
"application/vnd.oasis.opendocument.spreadsheet": {
"source": "iana",
"compressible": false,
"extensions": ["ods"]
},
"application/vnd.oasis.opendocument.spreadsheet-template": {
"source": "iana",
"extensions": ["ots"]
},
"application/vnd.oasis.opendocument.text": {
"source": "iana",
"compressible": false,
"extensions": ["odt"]
},
"application/vnd.oasis.opendocument.text-master": {
"source": "iana",
"extensions": ["odm"]
},
"application/vnd.oasis.opendocument.text-template": {
"source": "iana",
"extensions": ["ott"]
},
"application/vnd.oasis.opendocument.text-web": {
"source": "iana",
"extensions": ["oth"]
},
"application/vnd.obn": {
"source": "iana"
},
"application/vnd.ocf+cbor": {
"source": "iana"
},
"application/vnd.oci.image.manifest.v1+json": {
"source": "iana",
"compressible": true
},
"application/vnd.oftn.l10n+json": {
"source": "iana",
"compressible": true
},
"application/vnd.oipf.contentaccessdownload+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oipf.contentaccessstreaming+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oipf.cspg-hexbinary": {
"source": "iana"
},
"application/vnd.oipf.dae.svg+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oipf.dae.xhtml+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oipf.mippvcontrolmessage+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oipf.pae.gem": {
"source": "iana"
},
"application/vnd.oipf.spdiscovery+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oipf.spdlist+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oipf.ueprofile+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oipf.userprofile+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.olpc-sugar": {
"source": "iana",
"extensions": ["xo"]
},
"application/vnd.oma-scws-config": {
"source": "iana"
},
"application/vnd.oma-scws-http-request": {
"source": "iana"
},
"application/vnd.oma-scws-http-response": {
"source": "iana"
},
"application/vnd.oma.bcast.associated-procedure-parameter+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.bcast.drm-trigger+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.bcast.imd+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.bcast.ltkm": {
"source": "iana"
},
"application/vnd.oma.bcast.notification+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.bcast.provisioningtrigger": {
"source": "iana"
},
"application/vnd.oma.bcast.sgboot": {
"source": "iana"
},
"application/vnd.oma.bcast.sgdd+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.bcast.sgdu": {
"source": "iana"
},
"application/vnd.oma.bcast.simple-symbol-container": {
"source": "iana"
},
"application/vnd.oma.bcast.smartcard-trigger+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.bcast.sprov+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.bcast.stkm": {
"source": "iana"
},
"application/vnd.oma.cab-address-book+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.cab-feature-handler+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.cab-pcc+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.cab-subs-invite+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.cab-user-prefs+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.dcd": {
"source": "iana"
},
"application/vnd.oma.dcdc": {
"source": "iana"
},
"application/vnd.oma.dd2+xml": {
"source": "iana",
"compressible": true,
"extensions": ["dd2"]
},
"application/vnd.oma.drm.risd+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.group-usage-list+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.lwm2m+json": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.lwm2m+tlv": {
"source": "iana"
},
"application/vnd.oma.pal+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.poc.detailed-progress-report+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.poc.final-report+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.poc.groups+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.poc.invocation-descriptor+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.poc.optimized-progress-report+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.push": {
"source": "iana"
},
"application/vnd.oma.scidm.messages+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oma.xcap-directory+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.omads-email+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/vnd.omads-file+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/vnd.omads-folder+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/vnd.omaloc-supl-init": {
"source": "iana"
},
"application/vnd.onepager": {
"source": "iana"
},
"application/vnd.onepagertamp": {
"source": "iana"
},
"application/vnd.onepagertamx": {
"source": "iana"
},
"application/vnd.onepagertat": {
"source": "iana"
},
"application/vnd.onepagertatp": {
"source": "iana"
},
"application/vnd.onepagertatx": {
"source": "iana"
},
"application/vnd.openblox.game+xml": {
"source": "iana",
"compressible": true,
"extensions": ["obgx"]
},
"application/vnd.openblox.game-binary": {
"source": "iana"
},
"application/vnd.openeye.oeb": {
"source": "iana"
},
"application/vnd.openofficeorg.extension": {
"source": "apache",
"extensions": ["oxt"]
},
"application/vnd.openstreetmap.data+xml": {
"source": "iana",
"compressible": true,
"extensions": ["osm"]
},
"application/vnd.openxmlformats-officedocument.custom-properties+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.customxmlproperties+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.drawing+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.drawingml.chart+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.extended-properties+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.comments+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.presentation": {
"source": "iana",
"compressible": false,
"extensions": ["pptx"]
},
"application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.presprops+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.slide": {
"source": "iana",
"extensions": ["sldx"]
},
"application/vnd.openxmlformats-officedocument.presentationml.slide+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.slideshow": {
"source": "iana",
"extensions": ["ppsx"]
},
"application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.tags+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.template": {
"source": "iana",
"extensions": ["potx"]
},
"application/vnd.openxmlformats-officedocument.presentationml.template.main+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
"source": "iana",
"compressible": false,
"extensions": ["xlsx"]
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.template": {
"source": "iana",
"extensions": ["xltx"]
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.theme+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.themeoverride+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.vmldrawing": {
"source": "iana"
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
"source": "iana",
"compressible": false,
"extensions": ["docx"]
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.template": {
"source": "iana",
"extensions": ["dotx"]
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-package.core-properties+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.openxmlformats-package.relationships+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oracle.resource+json": {
"source": "iana",
"compressible": true
},
"application/vnd.orange.indata": {
"source": "iana"
},
"application/vnd.osa.netdeploy": {
"source": "iana"
},
"application/vnd.osgeo.mapguide.package": {
"source": "iana",
"extensions": ["mgp"]
},
"application/vnd.osgi.bundle": {
"source": "iana"
},
"application/vnd.osgi.dp": {
"source": "iana",
"extensions": ["dp"]
},
"application/vnd.osgi.subsystem": {
"source": "iana",
"extensions": ["esa"]
},
"application/vnd.otps.ct-kip+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.oxli.countgraph": {
"source": "iana"
},
"application/vnd.pagerduty+json": {
"source": "iana",
"compressible": true
},
"application/vnd.palm": {
"source": "iana",
"extensions": ["pdb","pqa","oprc"]
},
"application/vnd.panoply": {
"source": "iana"
},
"application/vnd.paos.xml": {
"source": "iana"
},
"application/vnd.patentdive": {
"source": "iana"
},
"application/vnd.patientecommsdoc": {
"source": "iana"
},
"application/vnd.pawaafile": {
"source": "iana",
"extensions": ["paw"]
},
"application/vnd.pcos": {
"source": "iana"
},
"application/vnd.pg.format": {
"source": "iana",
"extensions": ["str"]
},
"application/vnd.pg.osasli": {
"source": "iana",
"extensions": ["ei6"]
},
"application/vnd.piaccess.application-licence": {
"source": "iana"
},
"application/vnd.picsel": {
"source": "iana",
"extensions": ["efif"]
},
"application/vnd.pmi.widget": {
"source": "iana",
"extensions": ["wg"]
},
"application/vnd.poc.group-advertisement+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.pocketlearn": {
"source": "iana",
"extensions": ["plf"]
},
"application/vnd.powerbuilder6": {
"source": "iana",
"extensions": ["pbd"]
},
"application/vnd.powerbuilder6-s": {
"source": "iana"
},
"application/vnd.powerbuilder7": {
"source": "iana"
},
"application/vnd.powerbuilder7-s": {
"source": "iana"
},
"application/vnd.powerbuilder75": {
"source": "iana"
},
"application/vnd.powerbuilder75-s": {
"source": "iana"
},
"application/vnd.preminet": {
"source": "iana"
},
"application/vnd.previewsystems.box": {
"source": "iana",
"extensions": ["box"]
},
"application/vnd.proteus.magazine": {
"source": "iana",
"extensions": ["mgz"]
},
"application/vnd.psfs": {
"source": "iana"
},
"application/vnd.publishare-delta-tree": {
"source": "iana",
"extensions": ["qps"]
},
"application/vnd.pvi.ptid1": {
"source": "iana",
"extensions": ["ptid"]
},
"application/vnd.pwg-multiplexed": {
"source": "iana"
},
"application/vnd.pwg-xhtml-print+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.qualcomm.brew-app-res": {
"source": "iana"
},
"application/vnd.quarantainenet": {
"source": "iana"
},
"application/vnd.quark.quarkxpress": {
"source": "iana",
"extensions": ["qxd","qxt","qwd","qwt","qxl","qxb"]
},
"application/vnd.quobject-quoxdocument": {
"source": "iana"
},
"application/vnd.radisys.moml+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-audit+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-audit-conf+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-audit-conn+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-audit-dialog+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-audit-stream+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-conf+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-dialog+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-dialog-base+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-dialog-fax-detect+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-dialog-fax-sendrecv+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-dialog-group+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-dialog-speech+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.radisys.msml-dialog-transform+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.rainstor.data": {
"source": "iana"
},
"application/vnd.rapid": {
"source": "iana"
},
"application/vnd.rar": {
"source": "iana"
},
"application/vnd.realvnc.bed": {
"source": "iana",
"extensions": ["bed"]
},
"application/vnd.recordare.musicxml": {
"source": "iana",
"extensions": ["mxl"]
},
"application/vnd.recordare.musicxml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["musicxml"]
},
"application/vnd.renlearn.rlprint": {
"source": "iana"
},
"application/vnd.restful+json": {
"source": "iana",
"compressible": true
},
"application/vnd.rig.cryptonote": {
"source": "iana",
"extensions": ["cryptonote"]
},
"application/vnd.rim.cod": {
"source": "apache",
"extensions": ["cod"]
},
"application/vnd.rn-realmedia": {
"source": "apache",
"extensions": ["rm"]
},
"application/vnd.rn-realmedia-vbr": {
"source": "apache",
"extensions": ["rmvb"]
},
"application/vnd.route66.link66+xml": {
"source": "iana",
"compressible": true,
"extensions": ["link66"]
},
"application/vnd.rs-274x": {
"source": "iana"
},
"application/vnd.ruckus.download": {
"source": "iana"
},
"application/vnd.s3sms": {
"source": "iana"
},
"application/vnd.sailingtracker.track": {
"source": "iana",
"extensions": ["st"]
},
"application/vnd.sar": {
"source": "iana"
},
"application/vnd.sbm.cid": {
"source": "iana"
},
"application/vnd.sbm.mid2": {
"source": "iana"
},
"application/vnd.scribus": {
"source": "iana"
},
"application/vnd.sealed.3df": {
"source": "iana"
},
"application/vnd.sealed.csf": {
"source": "iana"
},
"application/vnd.sealed.doc": {
"source": "iana"
},
"application/vnd.sealed.eml": {
"source": "iana"
},
"application/vnd.sealed.mht": {
"source": "iana"
},
"application/vnd.sealed.net": {
"source": "iana"
},
"application/vnd.sealed.ppt": {
"source": "iana"
},
"application/vnd.sealed.tiff": {
"source": "iana"
},
"application/vnd.sealed.xls": {
"source": "iana"
},
"application/vnd.sealedmedia.softseal.html": {
"source": "iana"
},
"application/vnd.sealedmedia.softseal.pdf": {
"source": "iana"
},
"application/vnd.seemail": {
"source": "iana",
"extensions": ["see"]
},
"application/vnd.sema": {
"source": "iana",
"extensions": ["sema"]
},
"application/vnd.semd": {
"source": "iana",
"extensions": ["semd"]
},
"application/vnd.semf": {
"source": "iana",
"extensions": ["semf"]
},
"application/vnd.shade-save-file": {
"source": "iana"
},
"application/vnd.shana.informed.formdata": {
"source": "iana",
"extensions": ["ifm"]
},
"application/vnd.shana.informed.formtemplate": {
"source": "iana",
"extensions": ["itp"]
},
"application/vnd.shana.informed.interchange": {
"source": "iana",
"extensions": ["iif"]
},
"application/vnd.shana.informed.package": {
"source": "iana",
"extensions": ["ipk"]
},
"application/vnd.shootproof+json": {
"source": "iana",
"compressible": true
},
"application/vnd.shopkick+json": {
"source": "iana",
"compressible": true
},
"application/vnd.shp": {
"source": "iana"
},
"application/vnd.shx": {
"source": "iana"
},
"application/vnd.sigrok.session": {
"source": "iana"
},
"application/vnd.simtech-mindmapper": {
"source": "iana",
"extensions": ["twd","twds"]
},
"application/vnd.siren+json": {
"source": "iana",
"compressible": true
},
"application/vnd.smaf": {
"source": "iana",
"extensions": ["mmf"]
},
"application/vnd.smart.notebook": {
"source": "iana"
},
"application/vnd.smart.teacher": {
"source": "iana",
"extensions": ["teacher"]
},
"application/vnd.snesdev-page-table": {
"source": "iana"
},
"application/vnd.software602.filler.form+xml": {
"source": "iana",
"compressible": true,
"extensions": ["fo"]
},
"application/vnd.software602.filler.form-xml-zip": {
"source": "iana"
},
"application/vnd.solent.sdkm+xml": {
"source": "iana",
"compressible": true,
"extensions": ["sdkm","sdkd"]
},
"application/vnd.spotfire.dxp": {
"source": "iana",
"extensions": ["dxp"]
},
"application/vnd.spotfire.sfs": {
"source": "iana",
"extensions": ["sfs"]
},
"application/vnd.sqlite3": {
"source": "iana"
},
"application/vnd.sss-cod": {
"source": "iana"
},
"application/vnd.sss-dtf": {
"source": "iana"
},
"application/vnd.sss-ntf": {
"source": "iana"
},
"application/vnd.stardivision.calc": {
"source": "apache",
"extensions": ["sdc"]
},
"application/vnd.stardivision.draw": {
"source": "apache",
"extensions": ["sda"]
},
"application/vnd.stardivision.impress": {
"source": "apache",
"extensions": ["sdd"]
},
"application/vnd.stardivision.math": {
"source": "apache",
"extensions": ["smf"]
},
"application/vnd.stardivision.writer": {
"source": "apache",
"extensions": ["sdw","vor"]
},
"application/vnd.stardivision.writer-global": {
"source": "apache",
"extensions": ["sgl"]
},
"application/vnd.stepmania.package": {
"source": "iana",
"extensions": ["smzip"]
},
"application/vnd.stepmania.stepchart": {
"source": "iana",
"extensions": ["sm"]
},
"application/vnd.street-stream": {
"source": "iana"
},
"application/vnd.sun.wadl+xml": {
"source": "iana",
"compressible": true,
"extensions": ["wadl"]
},
"application/vnd.sun.xml.calc": {
"source": "apache",
"extensions": ["sxc"]
},
"application/vnd.sun.xml.calc.template": {
"source": "apache",
"extensions": ["stc"]
},
"application/vnd.sun.xml.draw": {
"source": "apache",
"extensions": ["sxd"]
},
"application/vnd.sun.xml.draw.template": {
"source": "apache",
"extensions": ["std"]
},
"application/vnd.sun.xml.impress": {
"source": "apache",
"extensions": ["sxi"]
},
"application/vnd.sun.xml.impress.template": {
"source": "apache",
"extensions": ["sti"]
},
"application/vnd.sun.xml.math": {
"source": "apache",
"extensions": ["sxm"]
},
"application/vnd.sun.xml.writer": {
"source": "apache",
"extensions": ["sxw"]
},
"application/vnd.sun.xml.writer.global": {
"source": "apache",
"extensions": ["sxg"]
},
"application/vnd.sun.xml.writer.template": {
"source": "apache",
"extensions": ["stw"]
},
"application/vnd.sus-calendar": {
"source": "iana",
"extensions": ["sus","susp"]
},
"application/vnd.svd": {
"source": "iana",
"extensions": ["svd"]
},
"application/vnd.swiftview-ics": {
"source": "iana"
},
"application/vnd.symbian.install": {
"source": "apache",
"extensions": ["sis","sisx"]
},
"application/vnd.syncml+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true,
"extensions": ["xsm"]
},
"application/vnd.syncml.dm+wbxml": {
"source": "iana",
"charset": "UTF-8",
"extensions": ["bdm"]
},
"application/vnd.syncml.dm+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true,
"extensions": ["xdm"]
},
"application/vnd.syncml.dm.notification": {
"source": "iana"
},
"application/vnd.syncml.dmddf+wbxml": {
"source": "iana"
},
"application/vnd.syncml.dmddf+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true,
"extensions": ["ddf"]
},
"application/vnd.syncml.dmtnds+wbxml": {
"source": "iana"
},
"application/vnd.syncml.dmtnds+xml": {
"source": "iana",
"charset": "UTF-8",
"compressible": true
},
"application/vnd.syncml.ds.notification": {
"source": "iana"
},
"application/vnd.tableschema+json": {
"source": "iana",
"compressible": true
},
"application/vnd.tao.intent-module-archive": {
"source": "iana",
"extensions": ["tao"]
},
"application/vnd.tcpdump.pcap": {
"source": "iana",
"extensions": ["pcap","cap","dmp"]
},
"application/vnd.think-cell.ppttc+json": {
"source": "iana",
"compressible": true
},
"application/vnd.tmd.mediaflex.api+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.tml": {
"source": "iana"
},
"application/vnd.tmobile-livetv": {
"source": "iana",
"extensions": ["tmo"]
},
"application/vnd.tri.onesource": {
"source": "iana"
},
"application/vnd.trid.tpt": {
"source": "iana",
"extensions": ["tpt"]
},
"application/vnd.triscape.mxs": {
"source": "iana",
"extensions": ["mxs"]
},
"application/vnd.trueapp": {
"source": "iana",
"extensions": ["tra"]
},
"application/vnd.truedoc": {
"source": "iana"
},
"application/vnd.ubisoft.webplayer": {
"source": "iana"
},
"application/vnd.ufdl": {
"source": "iana",
"extensions": ["ufd","ufdl"]
},
"application/vnd.uiq.theme": {
"source": "iana",
"extensions": ["utz"]
},
"application/vnd.umajin": {
"source": "iana",
"extensions": ["umj"]
},
"application/vnd.unity": {
"source": "iana",
"extensions": ["unityweb"]
},
"application/vnd.uoml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["uoml"]
},
"application/vnd.uplanet.alert": {
"source": "iana"
},
"application/vnd.uplanet.alert-wbxml": {
"source": "iana"
},
"application/vnd.uplanet.bearer-choice": {
"source": "iana"
},
"application/vnd.uplanet.bearer-choice-wbxml": {
"source": "iana"
},
"application/vnd.uplanet.cacheop": {
"source": "iana"
},
"application/vnd.uplanet.cacheop-wbxml": {
"source": "iana"
},
"application/vnd.uplanet.channel": {
"source": "iana"
},
"application/vnd.uplanet.channel-wbxml": {
"source": "iana"
},
"application/vnd.uplanet.list": {
"source": "iana"
},
"application/vnd.uplanet.list-wbxml": {
"source": "iana"
},
"application/vnd.uplanet.listcmd": {
"source": "iana"
},
"application/vnd.uplanet.listcmd-wbxml": {
"source": "iana"
},
"application/vnd.uplanet.signal": {
"source": "iana"
},
"application/vnd.uri-map": {
"source": "iana"
},
"application/vnd.valve.source.material": {
"source": "iana"
},
"application/vnd.vcx": {
"source": "iana",
"extensions": ["vcx"]
},
"application/vnd.vd-study": {
"source": "iana"
},
"application/vnd.vectorworks": {
"source": "iana"
},
"application/vnd.vel+json": {
"source": "iana",
"compressible": true
},
"application/vnd.verimatrix.vcas": {
"source": "iana"
},
"application/vnd.veryant.thin": {
"source": "iana"
},
"application/vnd.ves.encrypted": {
"source": "iana"
},
"application/vnd.vidsoft.vidconference": {
"source": "iana"
},
"application/vnd.visio": {
"source": "iana",
"extensions": ["vsd","vst","vss","vsw"]
},
"application/vnd.visionary": {
"source": "iana",
"extensions": ["vis"]
},
"application/vnd.vividence.scriptfile": {
"source": "iana"
},
"application/vnd.vsf": {
"source": "iana",
"extensions": ["vsf"]
},
"application/vnd.wap.sic": {
"source": "iana"
},
"application/vnd.wap.slc": {
"source": "iana"
},
"application/vnd.wap.wbxml": {
"source": "iana",
"charset": "UTF-8",
"extensions": ["wbxml"]
},
"application/vnd.wap.wmlc": {
"source": "iana",
"extensions": ["wmlc"]
},
"application/vnd.wap.wmlscriptc": {
"source": "iana",
"extensions": ["wmlsc"]
},
"application/vnd.webturbo": {
"source": "iana",
"extensions": ["wtb"]
},
"application/vnd.wfa.p2p": {
"source": "iana"
},
"application/vnd.wfa.wsc": {
"source": "iana"
},
"application/vnd.windows.devicepairing": {
"source": "iana"
},
"application/vnd.wmc": {
"source": "iana"
},
"application/vnd.wmf.bootstrap": {
"source": "iana"
},
"application/vnd.wolfram.mathematica": {
"source": "iana"
},
"application/vnd.wolfram.mathematica.package": {
"source": "iana"
},
"application/vnd.wolfram.player": {
"source": "iana",
"extensions": ["nbp"]
},
"application/vnd.wordperfect": {
"source": "iana",
"extensions": ["wpd"]
},
"application/vnd.wqd": {
"source": "iana",
"extensions": ["wqd"]
},
"application/vnd.wrq-hp3000-labelled": {
"source": "iana"
},
"application/vnd.wt.stf": {
"source": "iana",
"extensions": ["stf"]
},
"application/vnd.wv.csp+wbxml": {
"source": "iana"
},
"application/vnd.wv.csp+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.wv.ssp+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.xacml+json": {
"source": "iana",
"compressible": true
},
"application/vnd.xara": {
"source": "iana",
"extensions": ["xar"]
},
"application/vnd.xfdl": {
"source": "iana",
"extensions": ["xfdl"]
},
"application/vnd.xfdl.webform": {
"source": "iana"
},
"application/vnd.xmi+xml": {
"source": "iana",
"compressible": true
},
"application/vnd.xmpie.cpkg": {
"source": "iana"
},
"application/vnd.xmpie.dpkg": {
"source": "iana"
},
"application/vnd.xmpie.plan": {
"source": "iana"
},
"application/vnd.xmpie.ppkg": {
"source": "iana"
},
"application/vnd.xmpie.xlim": {
"source": "iana"
},
"application/vnd.yamaha.hv-dic": {
"source": "iana",
"extensions": ["hvd"]
},
"application/vnd.yamaha.hv-script": {
"source": "iana",
"extensions": ["hvs"]
},
"application/vnd.yamaha.hv-voice": {
"source": "iana",
"extensions": ["hvp"]
},
"application/vnd.yamaha.openscoreformat": {
"source": "iana",
"extensions": ["osf"]
},
"application/vnd.yamaha.openscoreformat.osfpvg+xml": {
"source": "iana",
"compressible": true,
"extensions": ["osfpvg"]
},
"application/vnd.yamaha.remote-setup": {
"source": "iana"
},
"application/vnd.yamaha.smaf-audio": {
"source": "iana",
"extensions": ["saf"]
},
"application/vnd.yamaha.smaf-phrase": {
"source": "iana",
"extensions": ["spf"]
},
"application/vnd.yamaha.through-ngn": {
"source": "iana"
},
"application/vnd.yamaha.tunnel-udpencap": {
"source": "iana"
},
"application/vnd.yaoweme": {
"source": "iana"
},
"application/vnd.yellowriver-custom-menu": {
"source": "iana",
"extensions": ["cmp"]
},
"application/vnd.youtube.yt": {
"source": "iana"
},
"application/vnd.zul": {
"source": "iana",
"extensions": ["zir","zirz"]
},
"application/vnd.zzazz.deck+xml": {
"source": "iana",
"compressible": true,
"extensions": ["zaz"]
},
"application/voicexml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["vxml"]
},
"application/voucher-cms+json": {
"source": "iana",
"compressible": true
},
"application/vq-rtcpxr": {
"source": "iana"
},
"application/wasm": {
"compressible": true,
"extensions": ["wasm"]
},
"application/watcherinfo+xml": {
"source": "iana",
"compressible": true
},
"application/webpush-options+json": {
"source": "iana",
"compressible": true
},
"application/whoispp-query": {
"source": "iana"
},
"application/whoispp-response": {
"source": "iana"
},
"application/widget": {
"source": "iana",
"extensions": ["wgt"]
},
"application/winhlp": {
"source": "apache",
"extensions": ["hlp"]
},
"application/wita": {
"source": "iana"
},
"application/wordperfect5.1": {
"source": "iana"
},
"application/wsdl+xml": {
"source": "iana",
"compressible": true,
"extensions": ["wsdl"]
},
"application/wspolicy+xml": {
"source": "iana",
"compressible": true,
"extensions": ["wspolicy"]
},
"application/x-7z-compressed": {
"source": "apache",
"compressible": false,
"extensions": ["7z"]
},
"application/x-abiword": {
"source": "apache",
"extensions": ["abw"]
},
"application/x-ace-compressed": {
"source": "apache",
"extensions": ["ace"]
},
"application/x-amf": {
"source": "apache"
},
"application/x-apple-diskimage": {
"source": "apache",
"extensions": ["dmg"]
},
"application/x-arj": {
"compressible": false,
"extensions": ["arj"]
},
"application/x-authorware-bin": {
"source": "apache",
"extensions": ["aab","x32","u32","vox"]
},
"application/x-authorware-map": {
"source": "apache",
"extensions": ["aam"]
},
"application/x-authorware-seg": {
"source": "apache",
"extensions": ["aas"]
},
"application/x-bcpio": {
"source": "apache",
"extensions": ["bcpio"]
},
"application/x-bdoc": {
"compressible": false,
"extensions": ["bdoc"]
},
"application/x-bittorrent": {
"source": "apache",
"extensions": ["torrent"]
},
"application/x-blorb": {
"source": "apache",
"extensions": ["blb","blorb"]
},
"application/x-bzip": {
"source": "apache",
"compressible": false,
"extensions": ["bz"]
},
"application/x-bzip2": {
"source": "apache",
"compressible": false,
"extensions": ["bz2","boz"]
},
"application/x-cbr": {
"source": "apache",
"extensions": ["cbr","cba","cbt","cbz","cb7"]
},
"application/x-cdlink": {
"source": "apache",
"extensions": ["vcd"]
},
"application/x-cfs-compressed": {
"source": "apache",
"extensions": ["cfs"]
},
"application/x-chat": {
"source": "apache",
"extensions": ["chat"]
},
"application/x-chess-pgn": {
"source": "apache",
"extensions": ["pgn"]
},
"application/x-chrome-extension": {
"extensions": ["crx"]
},
"application/x-cocoa": {
"source": "nginx",
"extensions": ["cco"]
},
"application/x-compress": {
"source": "apache"
},
"application/x-conference": {
"source": "apache",
"extensions": ["nsc"]
},
"application/x-cpio": {
"source": "apache",
"extensions": ["cpio"]
},
"application/x-csh": {
"source": "apache",
"extensions": ["csh"]
},
"application/x-deb": {
"compressible": false
},
"application/x-debian-package": {
"source": "apache",
"extensions": ["deb","udeb"]
},
"application/x-dgc-compressed": {
"source": "apache",
"extensions": ["dgc"]
},
"application/x-director": {
"source": "apache",
"extensions": ["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"]
},
"application/x-doom": {
"source": "apache",
"extensions": ["wad"]
},
"application/x-dtbncx+xml": {
"source": "apache",
"compressible": true,
"extensions": ["ncx"]
},
"application/x-dtbook+xml": {
"source": "apache",
"compressible": true,
"extensions": ["dtb"]
},
"application/x-dtbresource+xml": {
"source": "apache",
"compressible": true,
"extensions": ["res"]
},
"application/x-dvi": {
"source": "apache",
"compressible": false,
"extensions": ["dvi"]
},
"application/x-envoy": {
"source": "apache",
"extensions": ["evy"]
},
"application/x-eva": {
"source": "apache",
"extensions": ["eva"]
},
"application/x-font-bdf": {
"source": "apache",
"extensions": ["bdf"]
},
"application/x-font-dos": {
"source": "apache"
},
"application/x-font-framemaker": {
"source": "apache"
},
"application/x-font-ghostscript": {
"source": "apache",
"extensions": ["gsf"]
},
"application/x-font-libgrx": {
"source": "apache"
},
"application/x-font-linux-psf": {
"source": "apache",
"extensions": ["psf"]
},
"application/x-font-pcf": {
"source": "apache",
"extensions": ["pcf"]
},
"application/x-font-snf": {
"source": "apache",
"extensions": ["snf"]
},
"application/x-font-speedo": {
"source": "apache"
},
"application/x-font-sunos-news": {
"source": "apache"
},
"application/x-font-type1": {
"source": "apache",
"extensions": ["pfa","pfb","pfm","afm"]
},
"application/x-font-vfont": {
"source": "apache"
},
"application/x-freearc": {
"source": "apache",
"extensions": ["arc"]
},
"application/x-futuresplash": {
"source": "apache",
"extensions": ["spl"]
},
"application/x-gca-compressed": {
"source": "apache",
"extensions": ["gca"]
},
"application/x-glulx": {
"source": "apache",
"extensions": ["ulx"]
},
"application/x-gnumeric": {
"source": "apache",
"extensions": ["gnumeric"]
},
"application/x-gramps-xml": {
"source": "apache",
"extensions": ["gramps"]
},
"application/x-gtar": {
"source": "apache",
"extensions": ["gtar"]
},
"application/x-gzip": {
"source": "apache"
},
"application/x-hdf": {
"source": "apache",
"extensions": ["hdf"]
},
"application/x-httpd-php": {
"compressible": true,
"extensions": ["php"]
},
"application/x-install-instructions": {
"source": "apache",
"extensions": ["install"]
},
"application/x-iso9660-image": {
"source": "apache",
"extensions": ["iso"]
},
"application/x-java-archive-diff": {
"source": "nginx",
"extensions": ["jardiff"]
},
"application/x-java-jnlp-file": {
"source": "apache",
"compressible": false,
"extensions": ["jnlp"]
},
"application/x-javascript": {
"compressible": true
},
"application/x-keepass2": {
"extensions": ["kdbx"]
},
"application/x-latex": {
"source": "apache",
"compressible": false,
"extensions": ["latex"]
},
"application/x-lua-bytecode": {
"extensions": ["luac"]
},
"application/x-lzh-compressed": {
"source": "apache",
"extensions": ["lzh","lha"]
},
"application/x-makeself": {
"source": "nginx",
"extensions": ["run"]
},
"application/x-mie": {
"source": "apache",
"extensions": ["mie"]
},
"application/x-mobipocket-ebook": {
"source": "apache",
"extensions": ["prc","mobi"]
},
"application/x-mpegurl": {
"compressible": false
},
"application/x-ms-application": {
"source": "apache",
"extensions": ["application"]
},
"application/x-ms-shortcut": {
"source": "apache",
"extensions": ["lnk"]
},
"application/x-ms-wmd": {
"source": "apache",
"extensions": ["wmd"]
},
"application/x-ms-wmz": {
"source": "apache",
"extensions": ["wmz"]
},
"application/x-ms-xbap": {
"source": "apache",
"extensions": ["xbap"]
},
"application/x-msaccess": {
"source": "apache",
"extensions": ["mdb"]
},
"application/x-msbinder": {
"source": "apache",
"extensions": ["obd"]
},
"application/x-mscardfile": {
"source": "apache",
"extensions": ["crd"]
},
"application/x-msclip": {
"source": "apache",
"extensions": ["clp"]
},
"application/x-msdos-program": {
"extensions": ["exe"]
},
"application/x-msdownload": {
"source": "apache",
"extensions": ["exe","dll","com","bat","msi"]
},
"application/x-msmediaview": {
"source": "apache",
"extensions": ["mvb","m13","m14"]
},
"application/x-msmetafile": {
"source": "apache",
"extensions": ["wmf","wmz","emf","emz"]
},
"application/x-msmoney": {
"source": "apache",
"extensions": ["mny"]
},
"application/x-mspublisher": {
"source": "apache",
"extensions": ["pub"]
},
"application/x-msschedule": {
"source": "apache",
"extensions": ["scd"]
},
"application/x-msterminal": {
"source": "apache",
"extensions": ["trm"]
},
"application/x-mswrite": {
"source": "apache",
"extensions": ["wri"]
},
"application/x-netcdf": {
"source": "apache",
"extensions": ["nc","cdf"]
},
"application/x-ns-proxy-autoconfig": {
"compressible": true,
"extensions": ["pac"]
},
"application/x-nzb": {
"source": "apache",
"extensions": ["nzb"]
},
"application/x-perl": {
"source": "nginx",
"extensions": ["pl","pm"]
},
"application/x-pilot": {
"source": "nginx",
"extensions": ["prc","pdb"]
},
"application/x-pkcs12": {
"source": "apache",
"compressible": false,
"extensions": ["p12","pfx"]
},
"application/x-pkcs7-certificates": {
"source": "apache",
"extensions": ["p7b","spc"]
},
"application/x-pkcs7-certreqresp": {
"source": "apache",
"extensions": ["p7r"]
},
"application/x-pki-message": {
"source": "iana"
},
"application/x-rar-compressed": {
"source": "apache",
"compressible": false,
"extensions": ["rar"]
},
"application/x-redhat-package-manager": {
"source": "nginx",
"extensions": ["rpm"]
},
"application/x-research-info-systems": {
"source": "apache",
"extensions": ["ris"]
},
"application/x-sea": {
"source": "nginx",
"extensions": ["sea"]
},
"application/x-sh": {
"source": "apache",
"compressible": true,
"extensions": ["sh"]
},
"application/x-shar": {
"source": "apache",
"extensions": ["shar"]
},
"application/x-shockwave-flash": {
"source": "apache",
"compressible": false,
"extensions": ["swf"]
},
"application/x-silverlight-app": {
"source": "apache",
"extensions": ["xap"]
},
"application/x-sql": {
"source": "apache",
"extensions": ["sql"]
},
"application/x-stuffit": {
"source": "apache",
"compressible": false,
"extensions": ["sit"]
},
"application/x-stuffitx": {
"source": "apache",
"extensions": ["sitx"]
},
"application/x-subrip": {
"source": "apache",
"extensions": ["srt"]
},
"application/x-sv4cpio": {
"source": "apache",
"extensions": ["sv4cpio"]
},
"application/x-sv4crc": {
"source": "apache",
"extensions": ["sv4crc"]
},
"application/x-t3vm-image": {
"source": "apache",
"extensions": ["t3"]
},
"application/x-tads": {
"source": "apache",
"extensions": ["gam"]
},
"application/x-tar": {
"source": "apache",
"compressible": true,
"extensions": ["tar"]
},
"application/x-tcl": {
"source": "apache",
"extensions": ["tcl","tk"]
},
"application/x-tex": {
"source": "apache",
"extensions": ["tex"]
},
"application/x-tex-tfm": {
"source": "apache",
"extensions": ["tfm"]
},
"application/x-texinfo": {
"source": "apache",
"extensions": ["texinfo","texi"]
},
"application/x-tgif": {
"source": "apache",
"extensions": ["obj"]
},
"application/x-ustar": {
"source": "apache",
"extensions": ["ustar"]
},
"application/x-virtualbox-hdd": {
"compressible": true,
"extensions": ["hdd"]
},
"application/x-virtualbox-ova": {
"compressible": true,
"extensions": ["ova"]
},
"application/x-virtualbox-ovf": {
"compressible": true,
"extensions": ["ovf"]
},
"application/x-virtualbox-vbox": {
"compressible": true,
"extensions": ["vbox"]
},
"application/x-virtualbox-vbox-extpack": {
"compressible": false,
"extensions": ["vbox-extpack"]
},
"application/x-virtualbox-vdi": {
"compressible": true,
"extensions": ["vdi"]
},
"application/x-virtualbox-vhd": {
"compressible": true,
"extensions": ["vhd"]
},
"application/x-virtualbox-vmdk": {
"compressible": true,
"extensions": ["vmdk"]
},
"application/x-wais-source": {
"source": "apache",
"extensions": ["src"]
},
"application/x-web-app-manifest+json": {
"compressible": true,
"extensions": ["webapp"]
},
"application/x-www-form-urlencoded": {
"source": "iana",
"compressible": true
},
"application/x-x509-ca-cert": {
"source": "iana",
"extensions": ["der","crt","pem"]
},
"application/x-x509-ca-ra-cert": {
"source": "iana"
},
"application/x-x509-next-ca-cert": {
"source": "iana"
},
"application/x-xfig": {
"source": "apache",
"extensions": ["fig"]
},
"application/x-xliff+xml": {
"source": "apache",
"compressible": true,
"extensions": ["xlf"]
},
"application/x-xpinstall": {
"source": "apache",
"compressible": false,
"extensions": ["xpi"]
},
"application/x-xz": {
"source": "apache",
"extensions": ["xz"]
},
"application/x-zmachine": {
"source": "apache",
"extensions": ["z1","z2","z3","z4","z5","z6","z7","z8"]
},
"application/x400-bp": {
"source": "iana"
},
"application/xacml+xml": {
"source": "iana",
"compressible": true
},
"application/xaml+xml": {
"source": "apache",
"compressible": true,
"extensions": ["xaml"]
},
"application/xcap-att+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xav"]
},
"application/xcap-caps+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xca"]
},
"application/xcap-diff+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xdf"]
},
"application/xcap-el+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xel"]
},
"application/xcap-error+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xer"]
},
"application/xcap-ns+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xns"]
},
"application/xcon-conference-info+xml": {
"source": "iana",
"compressible": true
},
"application/xcon-conference-info-diff+xml": {
"source": "iana",
"compressible": true
},
"application/xenc+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xenc"]
},
"application/xhtml+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xhtml","xht"]
},
"application/xhtml-voice+xml": {
"source": "apache",
"compressible": true
},
"application/xliff+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xlf"]
},
"application/xml": {
"source": "iana",
"compressible": true,
"extensions": ["xml","xsl","xsd","rng"]
},
"application/xml-dtd": {
"source": "iana",
"compressible": true,
"extensions": ["dtd"]
},
"application/xml-external-parsed-entity": {
"source": "iana"
},
"application/xml-patch+xml": {
"source": "iana",
"compressible": true
},
"application/xmpp+xml": {
"source": "iana",
"compressible": true
},
"application/xop+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xop"]
},
"application/xproc+xml": {
"source": "apache",
"compressible": true,
"extensions": ["xpl"]
},
"application/xslt+xml": {
"source": "iana",
"compressible": true,
"extensions": ["xslt"]
},
"application/xspf+xml": {
"source": "apache",
"compressible": true,
"extensions": ["xspf"]
},
"application/xv+xml": {
"source": "iana",
"compressible": true,
"extensions": ["mxml","xhvml","xvml","xvm"]
},
"application/yang": {
"source": "iana",
"extensions": ["yang"]
},
"application/yang-data+json": {
"source": "iana",
"compressible": true
},
"application/yang-data+xml": {
"source": "iana",
"compressible": true
},
"application/yang-patch+json": {
"source": "iana",
"compressible": true
},
"application/yang-patch+xml": {
"source": "iana",
"compressible": true
},
"application/yin+xml": {
"source": "iana",
"compressible": true,
"extensions": ["yin"]
},
"application/zip": {
"source": "iana",
"compressible": false,
"extensions": ["zip"]
},
"application/zlib": {
"source": "iana"
},
"application/zstd": {
"source": "iana"
},
"audio/1d-interleaved-parityfec": {
"source": "iana"
},
"audio/32kadpcm": {
"source": "iana"
},
"audio/3gpp": {
"source": "iana",
"compressible": false,
"extensions": ["3gpp"]
},
"audio/3gpp2": {
"source": "iana"
},
"audio/aac": {
"source": "iana"
},
"audio/ac3": {
"source": "iana"
},
"audio/adpcm": {
"source": "apache",
"extensions": ["adp"]
},
"audio/amr": {
"source": "iana"
},
"audio/amr-wb": {
"source": "iana"
},
"audio/amr-wb+": {
"source": "iana"
},
"audio/aptx": {
"source": "iana"
},
"audio/asc": {
"source": "iana"
},
"audio/atrac-advanced-lossless": {
"source": "iana"
},
"audio/atrac-x": {
"source": "iana"
},
"audio/atrac3": {
"source": "iana"
},
"audio/basic": {
"source": "iana",
"compressible": false,
"extensions": ["au","snd"]
},
"audio/bv16": {
"source": "iana"
},
"audio/bv32": {
"source": "iana"
},
"audio/clearmode": {
"source": "iana"
},
"audio/cn": {
"source": "iana"
},
"audio/dat12": {
"source": "iana"
},
"audio/dls": {
"source": "iana"
},
"audio/dsr-es201108": {
"source": "iana"
},
"audio/dsr-es202050": {
"source": "iana"
},
"audio/dsr-es202211": {
"source": "iana"
},
"audio/dsr-es202212": {
"source": "iana"
},
"audio/dv": {
"source": "iana"
},
"audio/dvi4": {
"source": "iana"
},
"audio/eac3": {
"source": "iana"
},
"audio/encaprtp": {
"source": "iana"
},
"audio/evrc": {
"source": "iana"
},
"audio/evrc-qcp": {
"source": "iana"
},
"audio/evrc0": {
"source": "iana"
},
"audio/evrc1": {
"source": "iana"
},
"audio/evrcb": {
"source": "iana"
},
"audio/evrcb0": {
"source": "iana"
},
"audio/evrcb1": {
"source": "iana"
},
"audio/evrcnw": {
"source": "iana"
},
"audio/evrcnw0": {
"source": "iana"
},
"audio/evrcnw1": {
"source": "iana"
},
"audio/evrcwb": {
"source": "iana"
},
"audio/evrcwb0": {
"source": "iana"
},
"audio/evrcwb1": {
"source": "iana"
},
"audio/evs": {
"source": "iana"
},
"audio/flexfec": {
"source": "iana"
},
"audio/fwdred": {
"source": "iana"
},
"audio/g711-0": {
"source": "iana"
},
"audio/g719": {
"source": "iana"
},
"audio/g722": {
"source": "iana"
},
"audio/g7221": {
"source": "iana"
},
"audio/g723": {
"source": "iana"
},
"audio/g726-16": {
"source": "iana"
},
"audio/g726-24": {
"source": "iana"
},
"audio/g726-32": {
"source": "iana"
},
"audio/g726-40": {
"source": "iana"
},
"audio/g728": {
"source": "iana"
},
"audio/g729": {
"source": "iana"
},
"audio/g7291": {
"source": "iana"
},
"audio/g729d": {
"source": "iana"
},
"audio/g729e": {
"source": "iana"
},
"audio/gsm": {
"source": "iana"
},
"audio/gsm-efr": {
"source": "iana"
},
"audio/gsm-hr-08": {
"source": "iana"
},
"audio/ilbc": {
"source": "iana"
},
"audio/ip-mr_v2.5": {
"source": "iana"
},
"audio/isac": {
"source": "apache"
},
"audio/l16": {
"source": "iana"
},
"audio/l20": {
"source": "iana"
},
"audio/l24": {
"source": "iana",
"compressible": false
},
"audio/l8": {
"source": "iana"
},
"audio/lpc": {
"source": "iana"
},
"audio/melp": {
"source": "iana"
},
"audio/melp1200": {
"source": "iana"
},
"audio/melp2400": {
"source": "iana"
},
"audio/melp600": {
"source": "iana"
},
"audio/mhas": {
"source": "iana"
},
"audio/midi": {
"source": "apache",
"extensions": ["mid","midi","kar","rmi"]
},
"audio/mobile-xmf": {
"source": "iana",
"extensions": ["mxmf"]
},
"audio/mp3": {
"compressible": false,
"extensions": ["mp3"]
},
"audio/mp4": {
"source": "iana",
"compressible": false,
"extensions": ["m4a","mp4a"]
},
"audio/mp4a-latm": {
"source": "iana"
},
"audio/mpa": {
"source": "iana"
},
"audio/mpa-robust": {
"source": "iana"
},
"audio/mpeg": {
"source": "iana",
"compressible": false,
"extensions": ["mpga","mp2","mp2a","mp3","m2a","m3a"]
},
"audio/mpeg4-generic": {
"source": "iana"
},
"audio/musepack": {
"source": "apache"
},
"audio/ogg": {
"source": "iana",
"compressible": false,
"extensions": ["oga","ogg","spx"]
},
"audio/opus": {
"source": "iana"
},
"audio/parityfec": {
"source": "iana"
},
"audio/pcma": {
"source": "iana"
},
"audio/pcma-wb": {
"source": "iana"
},
"audio/pcmu": {
"source": "iana"
},
"audio/pcmu-wb": {
"source": "iana"
},
"audio/prs.sid": {
"source": "iana"
},
"audio/qcelp": {
"source": "iana"
},
"audio/raptorfec": {
"source": "iana"
},
"audio/red": {
"source": "iana"
},
"audio/rtp-enc-aescm128": {
"source": "iana"
},
"audio/rtp-midi": {
"source": "iana"
},
"audio/rtploopback": {
"source": "iana"
},
"audio/rtx": {
"source": "iana"
},
"audio/s3m": {
"source": "apache",
"extensions": ["s3m"]
},
"audio/silk": {
"source": "apache",
"extensions": ["sil"]
},
"audio/smv": {
"source": "iana"
},
"audio/smv-qcp": {
"source": "iana"
},
"audio/smv0": {
"source": "iana"
},
"audio/sp-midi": {
"source": "iana"
},
"audio/speex": {
"source": "iana"
},
"audio/t140c": {
"source": "iana"
},
"audio/t38": {
"source": "iana"
},
"audio/telephone-event": {
"source": "iana"
},
"audio/tetra_acelp": {
"source": "iana"
},
"audio/tetra_acelp_bb": {
"source": "iana"
},
"audio/tone": {
"source": "iana"
},
"audio/uemclip": {
"source": "iana"
},
"audio/ulpfec": {
"source": "iana"
},
"audio/usac": {
"source": "iana"
},
"audio/vdvi": {
"source": "iana"
},
"audio/vmr-wb": {
"source": "iana"
},
"audio/vnd.3gpp.iufp": {
"source": "iana"
},
"audio/vnd.4sb": {
"source": "iana"
},
"audio/vnd.audiokoz": {
"source": "iana"
},
"audio/vnd.celp": {
"source": "iana"
},
"audio/vnd.cisco.nse": {
"source": "iana"
},
"audio/vnd.cmles.radio-events": {
"source": "iana"
},
"audio/vnd.cns.anp1": {
"source": "iana"
},
"audio/vnd.cns.inf1": {
"source": "iana"
},
"audio/vnd.dece.audio": {
"source": "iana",
"extensions": ["uva","uvva"]
},
"audio/vnd.digital-winds": {
"source": "iana",
"extensions": ["eol"]
},
"audio/vnd.dlna.adts": {
"source": "iana"
},
"audio/vnd.dolby.heaac.1": {
"source": "iana"
},
"audio/vnd.dolby.heaac.2": {
"source": "iana"
},
"audio/vnd.dolby.mlp": {
"source": "iana"
},
"audio/vnd.dolby.mps": {
"source": "iana"
},
"audio/vnd.dolby.pl2": {
"source": "iana"
},
"audio/vnd.dolby.pl2x": {
"source": "iana"
},
"audio/vnd.dolby.pl2z": {
"source": "iana"
},
"audio/vnd.dolby.pulse.1": {
"source": "iana"
},
"audio/vnd.dra": {
"source": "iana",
"extensions": ["dra"]
},
"audio/vnd.dts": {
"source": "iana",
"extensions": ["dts"]
},
"audio/vnd.dts.hd": {
"source": "iana",
"extensions": ["dtshd"]
},
"audio/vnd.dts.uhd": {
"source": "iana"
},
"audio/vnd.dvb.file": {
"source": "iana"
},
"audio/vnd.everad.plj": {
"source": "iana"
},
"audio/vnd.hns.audio": {
"source": "iana"
},
"audio/vnd.lucent.voice": {
"source": "iana",
"extensions": ["lvp"]
},
"audio/vnd.ms-playready.media.pya": {
"source": "iana",
"extensions": ["pya"]
},
"audio/vnd.nokia.mobile-xmf": {
"source": "iana"
},
"audio/vnd.nortel.vbk": {
"source": "iana"
},
"audio/vnd.nuera.ecelp4800": {
"source": "iana",
"extensions": ["ecelp4800"]
},
"audio/vnd.nuera.ecelp7470": {
"source": "iana",
"extensions": ["ecelp7470"]
},
"audio/vnd.nuera.ecelp9600": {
"source": "iana",
"extensions": ["ecelp9600"]
},
"audio/vnd.octel.sbc": {
"source": "iana"
},
"audio/vnd.presonus.multitrack": {
"source": "iana"
},
"audio/vnd.qcelp": {
"source": "iana"
},
"audio/vnd.rhetorex.32kadpcm": {
"source": "iana"
},
"audio/vnd.rip": {
"source": "iana",
"extensions": ["rip"]
},
"audio/vnd.rn-realaudio": {
"compressible": false
},
"audio/vnd.sealedmedia.softseal.mpeg": {
"source": "iana"
},
"audio/vnd.vmx.cvsd": {
"source": "iana"
},
"audio/vnd.wave": {
"compressible": false
},
"audio/vorbis": {
"source": "iana",
"compressible": false
},
"audio/vorbis-config": {
"source": "iana"
},
"audio/wav": {
"compressible": false,
"extensions": ["wav"]
},
"audio/wave": {
"compressible": false,
"extensions": ["wav"]
},
"audio/webm": {
"source": "apache",
"compressible": false,
"extensions": ["weba"]
},
"audio/x-aac": {
"source": "apache",
"compressible": false,
"extensions": ["aac"]
},
"audio/x-aiff": {
"source": "apache",
"extensions": ["aif","aiff","aifc"]
},
"audio/x-caf": {
"source": "apache",
"compressible": false,
"extensions": ["caf"]
},
"audio/x-flac": {
"source": "apache",
"extensions": ["flac"]
},
"audio/x-m4a": {
"source": "nginx",
"extensions": ["m4a"]
},
"audio/x-matroska": {
"source": "apache",
"extensions": ["mka"]
},
"audio/x-mpegurl": {
"source": "apache",
"extensions": ["m3u"]
},
"audio/x-ms-wax": {
"source": "apache",
"extensions": ["wax"]
},
"audio/x-ms-wma": {
"source": "apache",
"extensions": ["wma"]
},
"audio/x-pn-realaudio": {
"source": "apache",
"extensions": ["ram","ra"]
},
"audio/x-pn-realaudio-plugin": {
"source": "apache",
"extensions": ["rmp"]
},
"audio/x-realaudio": {
"source": "nginx",
"extensions": ["ra"]
},
"audio/x-tta": {
"source": "apache"
},
"audio/x-wav": {
"source": "apache",
"extensions": ["wav"]
},
"audio/xm": {
"source": "apache",
"extensions": ["xm"]
},
"chemical/x-cdx": {
"source": "apache",
"extensions": ["cdx"]
},
"chemical/x-cif": {
"source": "apache",
"extensions": ["cif"]
},
"chemical/x-cmdf": {
"source": "apache",
"extensions": ["cmdf"]
},
"chemical/x-cml": {
"source": "apache",
"extensions": ["cml"]
},
"chemical/x-csml": {
"source": "apache",
"extensions": ["csml"]
},
"chemical/x-pdb": {
"source": "apache"
},
"chemical/x-xyz": {
"source": "apache",
"extensions": ["xyz"]
},
"font/collection": {
"source": "iana",
"extensions": ["ttc"]
},
"font/otf": {
"source": "iana",
"compressible": true,
"extensions": ["otf"]
},
"font/sfnt": {
"source": "iana"
},
"font/ttf": {
"source": "iana",
"compressible": true,
"extensions": ["ttf"]
},
"font/woff": {
"source": "iana",
"extensions": ["woff"]
},
"font/woff2": {
"source": "iana",
"extensions": ["woff2"]
},
"image/aces": {
"source": "iana",
"extensions": ["exr"]
},
"image/apng": {
"compressible": false,
"extensions": ["apng"]
},
"image/avci": {
"source": "iana"
},
"image/avcs": {
"source": "iana"
},
"image/bmp": {
"source": "iana",
"compressible": true,
"extensions": ["bmp"]
},
"image/cgm": {
"source": "iana",
"extensions": ["cgm"]
},
"image/dicom-rle": {
"source": "iana",
"extensions": ["drle"]
},
"image/emf": {
"source": "iana",
"extensions": ["emf"]
},
"image/fits": {
"source": "iana",
"extensions": ["fits"]
},
"image/g3fax": {
"source": "iana",
"extensions": ["g3"]
},
"image/gif": {
"source": "iana",
"compressible": false,
"extensions": ["gif"]
},
"image/heic": {
"source": "iana",
"extensions": ["heic"]
},
"image/heic-sequence": {
"source": "iana",
"extensions": ["heics"]
},
"image/heif": {
"source": "iana",
"extensions": ["heif"]
},
"image/heif-sequence": {
"source": "iana",
"extensions": ["heifs"]
},
"image/hej2k": {
"source": "iana",
"extensions": ["hej2"]
},
"image/hsj2": {
"source": "iana",
"extensions": ["hsj2"]
},
"image/ief": {
"source": "iana",
"extensions": ["ief"]
},
"image/jls": {
"source": "iana",
"extensions": ["jls"]
},
"image/jp2": {
"source": "iana",
"compressible": false,
"extensions": ["jp2","jpg2"]
},
"image/jpeg": {
"source": "iana",
"compressible": false,
"extensions": ["jpeg","jpg","jpe"]
},
"image/jph": {
"source": "iana",
"extensions": ["jph"]
},
"image/jphc": {
"source": "iana",
"extensions": ["jhc"]
},
"image/jpm": {
"source": "iana",
"compressible": false,
"extensions": ["jpm"]
},
"image/jpx": {
"source": "iana",
"compressible": false,
"extensions": ["jpx","jpf"]
},
"image/jxr": {
"source": "iana",
"extensions": ["jxr"]
},
"image/jxra": {
"source": "iana",
"extensions": ["jxra"]
},
"image/jxrs": {
"source": "iana",
"extensions": ["jxrs"]
},
"image/jxs": {
"source": "iana",
"extensions": ["jxs"]
},
"image/jxsc": {
"source": "iana",
"extensions": ["jxsc"]
},
"image/jxsi": {
"source": "iana",
"extensions": ["jxsi"]
},
"image/jxss": {
"source": "iana",
"extensions": ["jxss"]
},
"image/ktx": {
"source": "iana",
"extensions": ["ktx"]
},
"image/naplps": {
"source": "iana"
},
"image/pjpeg": {
"compressible": false
},
"image/png": {
"source": "iana",
"compressible": false,
"extensions": ["png"]
},
"image/prs.btif": {
"source": "iana",
"extensions": ["btif"]
},
"image/prs.pti": {
"source": "iana",
"extensions": ["pti"]
},
"image/pwg-raster": {
"source": "iana"
},
"image/sgi": {
"source": "apache",
"extensions": ["sgi"]
},
"image/svg+xml": {
"source": "iana",
"compressible": true,
"extensions": ["svg","svgz"]
},
"image/t38": {
"source": "iana",
"extensions": ["t38"]
},
"image/tiff": {
"source": "iana",
"compressible": false,
"extensions": ["tif","tiff"]
},
"image/tiff-fx": {
"source": "iana",
"extensions": ["tfx"]
},
"image/vnd.adobe.photoshop": {
"source": "iana",
"compressible": true,
"extensions": ["psd"]
},
"image/vnd.airzip.accelerator.azv": {
"source": "iana",
"extensions": ["azv"]
},
"image/vnd.cns.inf2": {
"source": "iana"
},
"image/vnd.dece.graphic": {
"source": "iana",
"extensions": ["uvi","uvvi","uvg","uvvg"]
},
"image/vnd.djvu": {
"source": "iana",
"extensions": ["djvu","djv"]
},
"image/vnd.dvb.subtitle": {
"source": "iana",
"extensions": ["sub"]
},
"image/vnd.dwg": {
"source": "iana",
"extensions": ["dwg"]
},
"image/vnd.dxf": {
"source": "iana",
"extensions": ["dxf"]
},
"image/vnd.fastbidsheet": {
"source": "iana",
"extensions": ["fbs"]
},
"image/vnd.fpx": {
"source": "iana",
"extensions": ["fpx"]
},
"image/vnd.fst": {
"source": "iana",
"extensions": ["fst"]
},
"image/vnd.fujixerox.edmics-mmr": {
"source": "iana",
"extensions": ["mmr"]
},
"image/vnd.fujixerox.edmics-rlc": {
"source": "iana",
"extensions": ["rlc"]
},
"image/vnd.globalgraphics.pgb": {
"source": "iana"
},
"image/vnd.microsoft.icon": {
"source": "iana",
"extensions": ["ico"]
},
"image/vnd.mix": {
"source": "iana"
},
"image/vnd.mozilla.apng": {
"source": "iana"
},
"image/vnd.ms-dds": {
"extensions": ["dds"]
},
"image/vnd.ms-modi": {
"source": "iana",
"extensions": ["mdi"]
},
"image/vnd.ms-photo": {
"source": "apache",
"extensions": ["wdp"]
},
"image/vnd.net-fpx": {
"source": "iana",
"extensions": ["npx"]
},
"image/vnd.radiance": {
"source": "iana"
},
"image/vnd.sealed.png": {
"source": "iana"
},
"image/vnd.sealedmedia.softseal.gif": {
"source": "iana"
},
"image/vnd.sealedmedia.softseal.jpg": {
"source": "iana"
},
"image/vnd.svf": {
"source": "iana"
},
"image/vnd.tencent.tap": {
"source": "iana",
"extensions": ["tap"]
},
"image/vnd.valve.source.texture": {
"source": "iana",
"extensions": ["vtf"]
},
"image/vnd.wap.wbmp": {
"source": "iana",
"extensions": ["wbmp"]
},
"image/vnd.xiff": {
"source": "iana",
"extensions": ["xif"]
},
"image/vnd.zbrush.pcx": {
"source": "iana",
"extensions": ["pcx"]
},
"image/webp": {
"source": "apache",
"extensions": ["webp"]
},
"image/wmf": {
"source": "iana",
"extensions": ["wmf"]
},
"image/x-3ds": {
"source": "apache",
"extensions": ["3ds"]
},
"image/x-cmu-raster": {
"source": "apache",
"extensions": ["ras"]
},
"image/x-cmx": {
"source": "apache",
"extensions": ["cmx"]
},
"image/x-freehand": {
"source": "apache",
"extensions": ["fh","fhc","fh4","fh5","fh7"]
},
"image/x-icon": {
"source": "apache",
"compressible": true,
"extensions": ["ico"]
},
"image/x-jng": {
"source": "nginx",
"extensions": ["jng"]
},
"image/x-mrsid-image": {
"source": "apache",
"extensions": ["sid"]
},
"image/x-ms-bmp": {
"source": "nginx",
"compressible": true,
"extensions": ["bmp"]
},
"image/x-pcx": {
"source": "apache",
"extensions": ["pcx"]
},
"image/x-pict": {
"source": "apache",
"extensions": ["pic","pct"]
},
"image/x-portable-anymap": {
"source": "apache",
"extensions": ["pnm"]
},
"image/x-portable-bitmap": {
"source": "apache",
"extensions": ["pbm"]
},
"image/x-portable-graymap": {
"source": "apache",
"extensions": ["pgm"]
},
"image/x-portable-pixmap": {
"source": "apache",
"extensions": ["ppm"]
},
"image/x-rgb": {
"source": "apache",
"extensions": ["rgb"]
},
"image/x-tga": {
"source": "apache",
"extensions": ["tga"]
},
"image/x-xbitmap": {
"source": "apache",
"extensions": ["xbm"]
},
"image/x-xcf": {
"compressible": false
},
"image/x-xpixmap": {
"source": "apache",
"extensions": ["xpm"]
},
"image/x-xwindowdump": {
"source": "apache",
"extensions": ["xwd"]
},
"message/cpim": {
"source": "iana"
},
"message/delivery-status": {
"source": "iana"
},
"message/disposition-notification": {
"source": "iana",
"extensions": [
"disposition-notification"
]
},
"message/external-body": {
"source": "iana"
},
"message/feedback-report": {
"source": "iana"
},
"message/global": {
"source": "iana",
"extensions": ["u8msg"]
},
"message/global-delivery-status": {
"source": "iana",
"extensions": ["u8dsn"]
},
"message/global-disposition-notification": {
"source": "iana",
"extensions": ["u8mdn"]
},
"message/global-headers": {
"source": "iana",
"extensions": ["u8hdr"]
},
"message/http": {
"source": "iana",
"compressible": false
},
"message/imdn+xml": {
"source": "iana",
"compressible": true
},
"message/news": {
"source": "iana"
},
"message/partial": {
"source": "iana",
"compressible": false
},
"message/rfc822": {
"source": "iana",
"compressible": true,
"extensions": ["eml","mime"]
},
"message/s-http": {
"source": "iana"
},
"message/sip": {
"source": "iana"
},
"message/sipfrag": {
"source": "iana"
},
"message/tracking-status": {
"source": "iana"
},
"message/vnd.si.simp": {
"source": "iana"
},
"message/vnd.wfa.wsc": {
"source": "iana",
"extensions": ["wsc"]
},
"model/3mf": {
"source": "iana",
"extensions": ["3mf"]
},
"model/gltf+json": {
"source": "iana",
"compressible": true,
"extensions": ["gltf"]
},
"model/gltf-binary": {
"source": "iana",
"compressible": true,
"extensions": ["glb"]
},
"model/iges": {
"source": "iana",
"compressible": false,
"extensions": ["igs","iges"]
},
"model/mesh": {
"source": "iana",
"compressible": false,
"extensions": ["msh","mesh","silo"]
},
"model/mtl": {
"source": "iana",
"extensions": ["mtl"]
},
"model/obj": {
"source": "iana",
"extensions": ["obj"]
},
"model/stl": {
"source": "iana",
"extensions": ["stl"]
},
"model/vnd.collada+xml": {
"source": "iana",
"compressible": true,
"extensions": ["dae"]
},
"model/vnd.dwf": {
"source": "iana",
"extensions": ["dwf"]
},
"model/vnd.flatland.3dml": {
"source": "iana"
},
"model/vnd.gdl": {
"source": "iana",
"extensions": ["gdl"]
},
"model/vnd.gs-gdl": {
"source": "apache"
},
"model/vnd.gs.gdl": {
"source": "iana"
},
"model/vnd.gtw": {
"source": "iana",
"extensions": ["gtw"]
},
"model/vnd.moml+xml": {
"source": "iana",
"compressible": true
},
"model/vnd.mts": {
"source": "iana",
"extensions": ["mts"]
},
"model/vnd.opengex": {
"source": "iana",
"extensions": ["ogex"]
},
"model/vnd.parasolid.transmit.binary": {
"source": "iana",
"extensions": ["x_b"]
},
"model/vnd.parasolid.transmit.text": {
"source": "iana",
"extensions": ["x_t"]
},
"model/vnd.rosette.annotated-data-model": {
"source": "iana"
},
"model/vnd.usdz+zip": {
"source": "iana",
"compressible": false,
"extensions": ["usdz"]
},
"model/vnd.valve.source.compiled-map": {
"source": "iana",
"extensions": ["bsp"]
},
"model/vnd.vtu": {
"source": "iana",
"extensions": ["vtu"]
},
"model/vrml": {
"source": "iana",
"compressible": false,
"extensions": ["wrl","vrml"]
},
"model/x3d+binary": {
"source": "apache",
"compressible": false,
"extensions": ["x3db","x3dbz"]
},
"model/x3d+fastinfoset": {
"source": "iana",
"extensions": ["x3db"]
},
"model/x3d+vrml": {
"source": "apache",
"compressible": false,
"extensions": ["x3dv","x3dvz"]
},
"model/x3d+xml": {
"source": "iana",
"compressible": true,
"extensions": ["x3d","x3dz"]
},
"model/x3d-vrml": {
"source": "iana",
"extensions": ["x3dv"]
},
"multipart/alternative": {
"source": "iana",
"compressible": false
},
"multipart/appledouble": {
"source": "iana"
},
"multipart/byteranges": {
"source": "iana"
},
"multipart/digest": {
"source": "iana"
},
"multipart/encrypted": {
"source": "iana",
"compressible": false
},
"multipart/form-data": {
"source": "iana",
"compressible": false
},
"multipart/header-set": {
"source": "iana"
},
"multipart/mixed": {
"source": "iana"
},
"multipart/multilingual": {
"source": "iana"
},
"multipart/parallel": {
"source": "iana"
},
"multipart/related": {
"source": "iana",
"compressible": false
},
"multipart/report": {
"source": "iana"
},
"multipart/signed": {
"source": "iana",
"compressible": false
},
"multipart/vnd.bint.med-plus": {
"source": "iana"
},
"multipart/voice-message": {
"source": "iana"
},
"multipart/x-mixed-replace": {
"source": "iana"
},
"text/1d-interleaved-parityfec": {
"source": "iana"
},
"text/cache-manifest": {
"source": "iana",
"compressible": true,
"extensions": ["appcache","manifest"]
},
"text/calendar": {
"source": "iana",
"extensions": ["ics","ifb"]
},
"text/calender": {
"compressible": true
},
"text/cmd": {
"compressible": true
},
"text/coffeescript": {
"extensions": ["coffee","litcoffee"]
},
"text/css": {
"source": "iana",
"charset": "UTF-8",
"compressible": true,
"extensions": ["css"]
},
"text/csv": {
"source": "iana",
"compressible": true,
"extensions": ["csv"]
},
"text/csv-schema": {
"source": "iana"
},
"text/directory": {
"source": "iana"
},
"text/dns": {
"source": "iana"
},
"text/ecmascript": {
"source": "iana"
},
"text/encaprtp": {
"source": "iana"
},
"text/enriched": {
"source": "iana"
},
"text/flexfec": {
"source": "iana"
},
"text/fwdred": {
"source": "iana"
},
"text/grammar-ref-list": {
"source": "iana"
},
"text/html": {
"source": "iana",
"compressible": true,
"extensions": ["html","htm","shtml"]
},
"text/jade": {
"extensions": ["jade"]
},
"text/javascript": {
"source": "iana",
"compressible": true
},
"text/jcr-cnd": {
"source": "iana"
},
"text/jsx": {
"compressible": true,
"extensions": ["jsx"]
},
"text/less": {
"compressible": true,
"extensions": ["less"]
},
"text/markdown": {
"source": "iana",
"compressible": true,
"extensions": ["markdown","md"]
},
"text/mathml": {
"source": "nginx",
"extensions": ["mml"]
},
"text/mdx": {
"compressible": true,
"extensions": ["mdx"]
},
"text/mizar": {
"source": "iana"
},
"text/n3": {
"source": "iana",
"charset": "UTF-8",
"compressible": true,
"extensions": ["n3"]
},
"text/parameters": {
"source": "iana",
"charset": "UTF-8"
},
"text/parityfec": {
"source": "iana"
},
"text/plain": {
"source": "iana",
"compressible": true,
"extensions": ["txt","text","conf","def","list","log","in","ini"]
},
"text/provenance-notation": {
"source": "iana",
"charset": "UTF-8"
},
"text/prs.fallenstein.rst": {
"source": "iana"
},
"text/prs.lines.tag": {
"source": "iana",
"extensions": ["dsc"]
},
"text/prs.prop.logic": {
"source": "iana"
},
"text/raptorfec": {
"source": "iana"
},
"text/red": {
"source": "iana"
},
"text/rfc822-headers": {
"source": "iana"
},
"text/richtext": {
"source": "iana",
"compressible": true,
"extensions": ["rtx"]
},
"text/rtf": {
"source": "iana",
"compressible": true,
"extensions": ["rtf"]
},
"text/rtp-enc-aescm128": {
"source": "iana"
},
"text/rtploopback": {
"source": "iana"
},
"text/rtx": {
"source": "iana"
},
"text/sgml": {
"source": "iana",
"extensions": ["sgml","sgm"]
},
"text/shex": {
"extensions": ["shex"]
},
"text/slim": {
"extensions": ["slim","slm"]
},
"text/strings": {
"source": "iana"
},
"text/stylus": {
"extensions": ["stylus","styl"]
},
"text/t140": {
"source": "iana"
},
"text/tab-separated-values": {
"source": "iana",
"compressible": true,
"extensions": ["tsv"]
},
"text/troff": {
"source": "iana",
"extensions": ["t","tr","roff","man","me","ms"]
},
"text/turtle": {
"source": "iana",
"charset": "UTF-8",
"extensions": ["ttl"]
},
"text/ulpfec": {
"source": "iana"
},
"text/uri-list": {
"source": "iana",
"compressible": true,
"extensions": ["uri","uris","urls"]
},
"text/vcard": {
"source": "iana",
"compressible": true,
"extensions": ["vcard"]
},
"text/vnd.a": {
"source": "iana"
},
"text/vnd.abc": {
"source": "iana"
},
"text/vnd.ascii-art": {
"source": "iana"
},
"text/vnd.curl": {
"source": "iana",
"extensions": ["curl"]
},
"text/vnd.curl.dcurl": {
"source": "apache",
"extensions": ["dcurl"]
},
"text/vnd.curl.mcurl": {
"source": "apache",
"extensions": ["mcurl"]
},
"text/vnd.curl.scurl": {
"source": "apache",
"extensions": ["scurl"]
},
"text/vnd.debian.copyright": {
"source": "iana",
"charset": "UTF-8"
},
"text/vnd.dmclientscript": {
"source": "iana"
},
"text/vnd.dvb.subtitle": {
"source": "iana",
"extensions": ["sub"]
},
"text/vnd.esmertec.theme-descriptor": {
"source": "iana",
"charset": "UTF-8"
},
"text/vnd.ficlab.flt": {
"source": "iana"
},
"text/vnd.fly": {
"source": "iana",
"extensions": ["fly"]
},
"text/vnd.fmi.flexstor": {
"source": "iana",
"extensions": ["flx"]
},
"text/vnd.gml": {
"source": "iana"
},
"text/vnd.graphviz": {
"source": "iana",
"extensions": ["gv"]
},
"text/vnd.hgl": {
"source": "iana"
},
"text/vnd.in3d.3dml": {
"source": "iana",
"extensions": ["3dml"]
},
"text/vnd.in3d.spot": {
"source": "iana",
"extensions": ["spot"]
},
"text/vnd.iptc.newsml": {
"source": "iana"
},
"text/vnd.iptc.nitf": {
"source": "iana"
},
"text/vnd.latex-z": {
"source": "iana"
},
"text/vnd.motorola.reflex": {
"source": "iana"
},
"text/vnd.ms-mediapackage": {
"source": "iana"
},
"text/vnd.net2phone.commcenter.command": {
"source": "iana"
},
"text/vnd.radisys.msml-basic-layout": {
"source": "iana"
},
"text/vnd.senx.warpscript": {
"source": "iana"
},
"text/vnd.si.uricatalogue": {
"source": "iana"
},
"text/vnd.sosi": {
"source": "iana"
},
"text/vnd.sun.j2me.app-descriptor": {
"source": "iana",
"charset": "UTF-8",
"extensions": ["jad"]
},
"text/vnd.trolltech.linguist": {
"source": "iana",
"charset": "UTF-8"
},
"text/vnd.wap.si": {
"source": "iana"
},
"text/vnd.wap.sl": {
"source": "iana"
},
"text/vnd.wap.wml": {
"source": "iana",
"extensions": ["wml"]
},
"text/vnd.wap.wmlscript": {
"source": "iana",
"extensions": ["wmls"]
},
"text/vtt": {
"source": "iana",
"charset": "UTF-8",
"compressible": true,
"extensions": ["vtt"]
},
"text/x-asm": {
"source": "apache",
"extensions": ["s","asm"]
},
"text/x-c": {
"source": "apache",
"extensions": ["c","cc","cxx","cpp","h","hh","dic"]
},
"text/x-component": {
"source": "nginx",
"extensions": ["htc"]
},
"text/x-fortran": {
"source": "apache",
"extensions": ["f","for","f77","f90"]
},
"text/x-gwt-rpc": {
"compressible": true
},
"text/x-handlebars-template": {
"extensions": ["hbs"]
},
"text/x-java-source": {
"source": "apache",
"extensions": ["java"]
},
"text/x-jquery-tmpl": {
"compressible": true
},
"text/x-lua": {
"extensions": ["lua"]
},
"text/x-markdown": {
"compressible": true,
"extensions": ["mkd"]
},
"text/x-nfo": {
"source": "apache",
"extensions": ["nfo"]
},
"text/x-opml": {
"source": "apache",
"extensions": ["opml"]
},
"text/x-org": {
"compressible": true,
"extensions": ["org"]
},
"text/x-pascal": {
"source": "apache",
"extensions": ["p","pas"]
},
"text/x-processing": {
"compressible": true,
"extensions": ["pde"]
},
"text/x-sass": {
"extensions": ["sass"]
},
"text/x-scss": {
"extensions": ["scss"]
},
"text/x-setext": {
"source": "apache",
"extensions": ["etx"]
},
"text/x-sfv": {
"source": "apache",
"extensions": ["sfv"]
},
"text/x-suse-ymp": {
"compressible": true,
"extensions": ["ymp"]
},
"text/x-uuencode": {
"source": "apache",
"extensions": ["uu"]
},
"text/x-vcalendar": {
"source": "apache",
"extensions": ["vcs"]
},
"text/x-vcard": {
"source": "apache",
"extensions": ["vcf"]
},
"text/xml": {
"source": "iana",
"compressible": true,
"extensions": ["xml"]
},
"text/xml-external-parsed-entity": {
"source": "iana"
},
"text/yaml": {
"extensions": ["yaml","yml"]
},
"video/1d-interleaved-parityfec": {
"source": "iana"
},
"video/3gpp": {
"source": "iana",
"extensions": ["3gp","3gpp"]
},
"video/3gpp-tt": {
"source": "iana"
},
"video/3gpp2": {
"source": "iana",
"extensions": ["3g2"]
},
"video/bmpeg": {
"source": "iana"
},
"video/bt656": {
"source": "iana"
},
"video/celb": {
"source": "iana"
},
"video/dv": {
"source": "iana"
},
"video/encaprtp": {
"source": "iana"
},
"video/flexfec": {
"source": "iana"
},
"video/h261": {
"source": "iana",
"extensions": ["h261"]
},
"video/h263": {
"source": "iana",
"extensions": ["h263"]
},
"video/h263-1998": {
"source": "iana"
},
"video/h263-2000": {
"source": "iana"
},
"video/h264": {
"source": "iana",
"extensions": ["h264"]
},
"video/h264-rcdo": {
"source": "iana"
},
"video/h264-svc": {
"source": "iana"
},
"video/h265": {
"source": "iana"
},
"video/iso.segment": {
"source": "iana"
},
"video/jpeg": {
"source": "iana",
"extensions": ["jpgv"]
},
"video/jpeg2000": {
"source": "iana"
},
"video/jpm": {
"source": "apache",
"extensions": ["jpm","jpgm"]
},
"video/mj2": {
"source": "iana",
"extensions": ["mj2","mjp2"]
},
"video/mp1s": {
"source": "iana"
},
"video/mp2p": {
"source": "iana"
},
"video/mp2t": {
"source": "iana",
"extensions": ["ts"]
},
"video/mp4": {
"source": "iana",
"compressible": false,
"extensions": ["mp4","mp4v","mpg4"]
},
"video/mp4v-es": {
"source": "iana"
},
"video/mpeg": {
"source": "iana",
"compressible": false,
"extensions": ["mpeg","mpg","mpe","m1v","m2v"]
},
"video/mpeg4-generic": {
"source": "iana"
},
"video/mpv": {
"source": "iana"
},
"video/nv": {
"source": "iana"
},
"video/ogg": {
"source": "iana",
"compressible": false,
"extensions": ["ogv"]
},
"video/parityfec": {
"source": "iana"
},
"video/pointer": {
"source": "iana"
},
"video/quicktime": {
"source": "iana",
"compressible": false,
"extensions": ["qt","mov"]
},
"video/raptorfec": {
"source": "iana"
},
"video/raw": {
"source": "iana"
},
"video/rtp-enc-aescm128": {
"source": "iana"
},
"video/rtploopback": {
"source": "iana"
},
"video/rtx": {
"source": "iana"
},
"video/smpte291": {
"source": "iana"
},
"video/smpte292m": {
"source": "iana"
},
"video/ulpfec": {
"source": "iana"
},
"video/vc1": {
"source": "iana"
},
"video/vc2": {
"source": "iana"
},
"video/vnd.cctv": {
"source": "iana"
},
"video/vnd.dece.hd": {
"source": "iana",
"extensions": ["uvh","uvvh"]
},
"video/vnd.dece.mobile": {
"source": "iana",
"extensions": ["uvm","uvvm"]
},
"video/vnd.dece.mp4": {
"source": "iana"
},
"video/vnd.dece.pd": {
"source": "iana",
"extensions": ["uvp","uvvp"]
},
"video/vnd.dece.sd": {
"source": "iana",
"extensions": ["uvs","uvvs"]
},
"video/vnd.dece.video": {
"source": "iana",
"extensions": ["uvv","uvvv"]
},
"video/vnd.directv.mpeg": {
"source": "iana"
},
"video/vnd.directv.mpeg-tts": {
"source": "iana"
},
"video/vnd.dlna.mpeg-tts": {
"source": "iana"
},
"video/vnd.dvb.file": {
"source": "iana",
"extensions": ["dvb"]
},
"video/vnd.fvt": {
"source": "iana",
"extensions": ["fvt"]
},
"video/vnd.hns.video": {
"source": "iana"
},
"video/vnd.iptvforum.1dparityfec-1010": {
"source": "iana"
},
"video/vnd.iptvforum.1dparityfec-2005": {
"source": "iana"
},
"video/vnd.iptvforum.2dparityfec-1010": {
"source": "iana"
},
"video/vnd.iptvforum.2dparityfec-2005": {
"source": "iana"
},
"video/vnd.iptvforum.ttsavc": {
"source": "iana"
},
"video/vnd.iptvforum.ttsmpeg2": {
"source": "iana"
},
"video/vnd.motorola.video": {
"source": "iana"
},
"video/vnd.motorola.videop": {
"source": "iana"
},
"video/vnd.mpegurl": {
"source": "iana",
"extensions": ["mxu","m4u"]
},
"video/vnd.ms-playready.media.pyv": {
"source": "iana",
"extensions": ["pyv"]
},
"video/vnd.nokia.interleaved-multimedia": {
"source": "iana"
},
"video/vnd.nokia.mp4vr": {
"source": "iana"
},
"video/vnd.nokia.videovoip": {
"source": "iana"
},
"video/vnd.objectvideo": {
"source": "iana"
},
"video/vnd.radgamettools.bink": {
"source": "iana"
},
"video/vnd.radgamettools.smacker": {
"source": "iana"
},
"video/vnd.sealed.mpeg1": {
"source": "iana"
},
"video/vnd.sealed.mpeg4": {
"source": "iana"
},
"video/vnd.sealed.swf": {
"source": "iana"
},
"video/vnd.sealedmedia.softseal.mov": {
"source": "iana"
},
"video/vnd.uvvu.mp4": {
"source": "iana",
"extensions": ["uvu","uvvu"]
},
"video/vnd.vivo": {
"source": "iana",
"extensions": ["viv"]
},
"video/vnd.youtube.yt": {
"source": "iana"
},
"video/vp8": {
"source": "iana"
},
"video/webm": {
"source": "apache",
"compressible": false,
"extensions": ["webm"]
},
"video/x-f4v": {
"source": "apache",
"extensions": ["f4v"]
},
"video/x-fli": {
"source": "apache",
"extensions": ["fli"]
},
"video/x-flv": {
"source": "apache",
"compressible": false,
"extensions": ["flv"]
},
"video/x-m4v": {
"source": "apache",
"extensions": ["m4v"]
},
"video/x-matroska": {
"source": "apache",
"compressible": false,
"extensions": ["mkv","mk3d","mks"]
},
"video/x-mng": {
"source": "apache",
"extensions": ["mng"]
},
"video/x-ms-asf": {
"source": "apache",
"extensions": ["asf","asx"]
},
"video/x-ms-vob": {
"source": "apache",
"extensions": ["vob"]
},
"video/x-ms-wm": {
"source": "apache",
"extensions": ["wm"]
},
"video/x-ms-wmv": {
"source": "apache",
"compressible": false,
"extensions": ["wmv"]
},
"video/x-ms-wmx": {
"source": "apache",
"extensions": ["wmx"]
},
"video/x-ms-wvx": {
"source": "apache",
"extensions": ["wvx"]
},
"video/x-msvideo": {
"source": "apache",
"extensions": ["avi"]
},
"video/x-sgi-movie": {
"source": "apache",
"extensions": ["movie"]
},
"video/x-smv": {
"source": "apache",
"extensions": ["smv"]
},
"x-conference/x-cooltalk": {
"source": "apache",
"extensions": ["ice"]
},
"x-shader/x-fragment": {
"compressible": true
},
"x-shader/x-vertex": {
"compressible": true
}
}
},{}],143:[function(require,module,exports){
/*!
* mime-db
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
/**
* Module exports.
*/
module.exports = require('./db.json')
},{"./db.json":142}],144:[function(require,module,exports){
/*!
* mime-types
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var db = require('mime-db')
var extname = require('path').extname
/**
* Module variables.
* @private
*/
var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/
var TEXT_TYPE_REGEXP = /^text\//i
/**
* Module exports.
* @public
*/
exports.charset = charset
exports.charsets = { lookup: charset }
exports.contentType = contentType
exports.extension = extension
exports.extensions = Object.create(null)
exports.lookup = lookup
exports.types = Object.create(null)
// Populate the extensions/types maps
populateMaps(exports.extensions, exports.types)
/**
* Get the default charset for a MIME type.
*
* @param {string} type
* @return {boolean|string}
*/
function charset (type) {
if (!type || typeof type !== 'string') {
return false
}
// TODO: use media-typer
var match = EXTRACT_TYPE_REGEXP.exec(type)
var mime = match && db[match[1].toLowerCase()]
if (mime && mime.charset) {
return mime.charset
}
// default text/* to utf-8
if (match && TEXT_TYPE_REGEXP.test(match[1])) {
return 'UTF-8'
}
return false
}
/**
* Create a full Content-Type header given a MIME type or extension.
*
* @param {string} str
* @return {boolean|string}
*/
function contentType (str) {
// TODO: should this even be in this module?
if (!str || typeof str !== 'string') {
return false
}
var mime = str.indexOf('/') === -1
? exports.lookup(str)
: str
if (!mime) {
return false
}
// TODO: use content-type or other module
if (mime.indexOf('charset') === -1) {
var charset = exports.charset(mime)
if (charset) mime += '; charset=' + charset.toLowerCase()
}
return mime
}
/**
* Get the default extension for a MIME type.
*
* @param {string} type
* @return {boolean|string}
*/
function extension (type) {
if (!type || typeof type !== 'string') {
return false
}
// TODO: use media-typer
var match = EXTRACT_TYPE_REGEXP.exec(type)
// get extensions
var exts = match && exports.extensions[match[1].toLowerCase()]
if (!exts || !exts.length) {
return false
}
return exts[0]
}
/**
* Lookup the MIME type for a file path/extension.
*
* @param {string} path
* @return {boolean|string}
*/
function lookup (path) {
if (!path || typeof path !== 'string') {
return false
}
// get the extension ("ext" or ".ext" or full path)
var extension = extname('x.' + path)
.toLowerCase()
.substr(1)
if (!extension) {
return false
}
return exports.types[extension] || false
}
/**
* Populate the extensions and types maps.
* @private
*/
function populateMaps (extensions, types) {
// source preference (least -> most)
var preference = ['nginx', 'apache', undefined, 'iana']
Object.keys(db).forEach(function forEachMimeType (type) {
var mime = db[type]
var exts = mime.extensions
if (!exts || !exts.length) {
return
}
// mime -> extensions
extensions[type] = exts
// extension -> mime
for (var i = 0; i < exts.length; i++) {
var extension = exts[i]
if (types[extension]) {
var from = preference.indexOf(db[types[extension]].source)
var to = preference.indexOf(mime.source)
if (types[extension] !== 'application/octet-stream' &&
(from > to || (from === to && types[extension].substr(0, 12) === 'application/'))) {
// skip the remapping
continue
}
}
// set the extension -> mime
types[extension] = type
}
})
}
},{"mime-db":143,"path":185}],145:[function(require,module,exports){
(function (Buffer){(function (){
// This is an intentionally recursive require. I don't like it either.
var Box = require('./index')
var Descriptor = require('./descriptor')
var uint64be = require('uint64be')
var TIME_OFFSET = 2082844800000
/*
TODO:
test these
add new box versions
*/
// These have 'version' and 'flags' fields in the headers
exports.fullBoxes = {}
var fullBoxes = [
'mvhd',
'tkhd',
'mdhd',
'vmhd',
'smhd',
'stsd',
'esds',
'stsz',
'stco',
'co64',
'stss',
'stts',
'ctts',
'stsc',
'dref',
'elst',
'hdlr',
'mehd',
'trex',
'mfhd',
'tfhd',
'tfdt',
'trun'
]
fullBoxes.forEach(function (type) {
exports.fullBoxes[type] = true
})
exports.ftyp = {}
exports.ftyp.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.ftyp.encodingLength(box))
var brands = box.compatibleBrands || []
buf.write(box.brand, 0, 4, 'ascii')
buf.writeUInt32BE(box.brandVersion, 4)
for (var i = 0; i < brands.length; i++) buf.write(brands[i], 8 + (i * 4), 4, 'ascii')
exports.ftyp.encode.bytes = 8 + brands.length * 4
return buf
}
exports.ftyp.decode = function (buf, offset) {
buf = buf.slice(offset)
var brand = buf.toString('ascii', 0, 4)
var version = buf.readUInt32BE(4)
var compatibleBrands = []
for (var i = 8; i < buf.length; i += 4) compatibleBrands.push(buf.toString('ascii', i, i + 4))
return {
brand: brand,
brandVersion: version,
compatibleBrands: compatibleBrands
}
}
exports.ftyp.encodingLength = function (box) {
return 8 + (box.compatibleBrands || []).length * 4
}
exports.mvhd = {}
exports.mvhd.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(96)
writeDate(box.ctime || new Date(), buf, 0)
writeDate(box.mtime || new Date(), buf, 4)
buf.writeUInt32BE(box.timeScale || 0, 8)
buf.writeUInt32BE(box.duration || 0, 12)
writeFixed32(box.preferredRate || 0, buf, 16)
writeFixed16(box.preferredVolume || 0, buf, 20)
writeReserved(buf, 22, 32)
writeMatrix(box.matrix, buf, 32)
buf.writeUInt32BE(box.previewTime || 0, 68)
buf.writeUInt32BE(box.previewDuration || 0, 72)
buf.writeUInt32BE(box.posterTime || 0, 76)
buf.writeUInt32BE(box.selectionTime || 0, 80)
buf.writeUInt32BE(box.selectionDuration || 0, 84)
buf.writeUInt32BE(box.currentTime || 0, 88)
buf.writeUInt32BE(box.nextTrackId || 0, 92)
exports.mvhd.encode.bytes = 96
return buf
}
exports.mvhd.decode = function (buf, offset) {
buf = buf.slice(offset)
return {
ctime: readDate(buf, 0),
mtime: readDate(buf, 4),
timeScale: buf.readUInt32BE(8),
duration: buf.readUInt32BE(12),
preferredRate: readFixed32(buf, 16),
preferredVolume: readFixed16(buf, 20),
matrix: readMatrix(buf.slice(32, 68)),
previewTime: buf.readUInt32BE(68),
previewDuration: buf.readUInt32BE(72),
posterTime: buf.readUInt32BE(76),
selectionTime: buf.readUInt32BE(80),
selectionDuration: buf.readUInt32BE(84),
currentTime: buf.readUInt32BE(88),
nextTrackId: buf.readUInt32BE(92)
}
}
exports.mvhd.encodingLength = function (box) {
return 96
}
exports.tkhd = {}
exports.tkhd.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(80)
writeDate(box.ctime || new Date(), buf, 0)
writeDate(box.mtime || new Date(), buf, 4)
buf.writeUInt32BE(box.trackId || 0, 8)
writeReserved(buf, 12, 16)
buf.writeUInt32BE(box.duration || 0, 16)
writeReserved(buf, 20, 28)
buf.writeUInt16BE(box.layer || 0, 28)
buf.writeUInt16BE(box.alternateGroup || 0, 30)
buf.writeUInt16BE(box.volume || 0, 32)
writeMatrix(box.matrix, buf, 36)
buf.writeUInt32BE(box.trackWidth || 0, 72)
buf.writeUInt32BE(box.trackHeight || 0, 76)
exports.tkhd.encode.bytes = 80
return buf
}
exports.tkhd.decode = function (buf, offset) {
buf = buf.slice(offset)
return {
ctime: readDate(buf, 0),
mtime: readDate(buf, 4),
trackId: buf.readUInt32BE(8),
duration: buf.readUInt32BE(16),
layer: buf.readUInt16BE(28),
alternateGroup: buf.readUInt16BE(30),
volume: buf.readUInt16BE(32),
matrix: readMatrix(buf.slice(36, 72)),
trackWidth: buf.readUInt32BE(72),
trackHeight: buf.readUInt32BE(76)
}
}
exports.tkhd.encodingLength = function (box) {
return 80
}
exports.mdhd = {}
exports.mdhd.encode = function (box, buf, offset) {
if (box.version === 1) {
buf = buf ? buf.slice(offset) : Buffer.alloc(32)
writeDate64(box.ctime || new Date(), buf, 0)
writeDate64(box.mtime || new Date(), buf, 8)
buf.writeUInt32BE(box.timeScale || 0, 16)
// Node only supports integer <= 48bit. Waiting for BigInt!
buf.writeUIntBE(box.duration || 0, 20, 6)
buf.writeUInt16BE(box.language || 0, 28)
buf.writeUInt16BE(box.quality || 0, 30)
exports.mdhd.encode.bytes = 32
return buf
}
buf = buf ? buf.slice(offset) : Buffer.alloc(20)
writeDate(box.ctime || new Date(), buf, 0)
writeDate(box.mtime || new Date(), buf, 4)
buf.writeUInt32BE(box.timeScale || 0, 8)
buf.writeUInt32BE(box.duration || 0, 12)
buf.writeUInt16BE(box.language || 0, 16)
buf.writeUInt16BE(box.quality || 0, 18)
exports.mdhd.encode.bytes = 20
return buf
}
exports.mdhd.decode = function (buf, offset, end) {
buf = buf.slice(offset)
var version1 = (end - offset) !== 20
// In version 1 creation time and modification time are unsigned long
if (version1) {
return {
ctime: readDate64(buf, 0),
mtime: readDate64(buf, 8),
timeScale: buf.readUInt32BE(16),
// Node only supports integer <= 48bit. Waiting for BigInt!
duration: buf.readUIntBE(20, 6),
language: buf.readUInt16BE(28),
quality: buf.readUInt16BE(30)
}
}
return {
ctime: readDate(buf, 0),
mtime: readDate(buf, 4),
timeScale: buf.readUInt32BE(8),
duration: buf.readUInt32BE(12),
language: buf.readUInt16BE(16),
quality: buf.readUInt16BE(18)
}
}
exports.mdhd.encodingLength = function (box) {
if (box.version === 1) return 32
return 20
}
exports.vmhd = {}
exports.vmhd.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(8)
buf.writeUInt16BE(box.graphicsMode || 0, 0)
var opcolor = box.opcolor || [0, 0, 0]
buf.writeUInt16BE(opcolor[0], 2)
buf.writeUInt16BE(opcolor[1], 4)
buf.writeUInt16BE(opcolor[2], 6)
exports.vmhd.encode.bytes = 8
return buf
}
exports.vmhd.decode = function (buf, offset) {
buf = buf.slice(offset)
return {
graphicsMode: buf.readUInt16BE(0),
opcolor: [buf.readUInt16BE(2), buf.readUInt16BE(4), buf.readUInt16BE(6)]
}
}
exports.vmhd.encodingLength = function (box) {
return 8
}
exports.smhd = {}
exports.smhd.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(4)
buf.writeUInt16BE(box.balance || 0, 0)
writeReserved(buf, 2, 4)
exports.smhd.encode.bytes = 4
return buf
}
exports.smhd.decode = function (buf, offset) {
buf = buf.slice(offset)
return {
balance: buf.readUInt16BE(0)
}
}
exports.smhd.encodingLength = function (box) {
return 4
}
exports.stsd = {}
exports.stsd.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.stsd.encodingLength(box))
var entries = box.entries || []
buf.writeUInt32BE(entries.length, 0)
var ptr = 4
for (var i = 0; i < entries.length; i++) {
var entry = entries[i]
Box.encode(entry, buf, ptr)
ptr += Box.encode.bytes
}
exports.stsd.encode.bytes = ptr
return buf
}
exports.stsd.decode = function (buf, offset, end) {
buf = buf.slice(offset)
var num = buf.readUInt32BE(0)
var entries = new Array(num)
var ptr = 4
for (var i = 0; i < num; i++) {
var entry = Box.decode(buf, ptr, end)
entries[i] = entry
ptr += entry.length
}
return {
entries: entries
}
}
exports.stsd.encodingLength = function (box) {
var totalSize = 4
if (!box.entries) return totalSize
for (var i = 0; i < box.entries.length; i++) {
totalSize += Box.encodingLength(box.entries[i])
}
return totalSize
}
exports.avc1 = exports.VisualSampleEntry = {}
exports.VisualSampleEntry.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.VisualSampleEntry.encodingLength(box))
writeReserved(buf, 0, 6)
buf.writeUInt16BE(box.dataReferenceIndex || 0, 6)
writeReserved(buf, 8, 24)
buf.writeUInt16BE(box.width || 0, 24)
buf.writeUInt16BE(box.height || 0, 26)
buf.writeUInt32BE(box.hResolution || 0x480000, 28)
buf.writeUInt32BE(box.vResolution || 0x480000, 32)
writeReserved(buf, 36, 40)
buf.writeUInt16BE(box.frameCount || 1, 40)
var compressorName = box.compressorName || ''
var nameLen = Math.min(compressorName.length, 31)
buf.writeUInt8(nameLen, 42)
buf.write(compressorName, 43, nameLen, 'utf8')
buf.writeUInt16BE(box.depth || 0x18, 74)
buf.writeInt16BE(-1, 76)
var ptr = 78
var children = box.children || []
children.forEach(function (child) {
Box.encode(child, buf, ptr)
ptr += Box.encode.bytes
})
exports.VisualSampleEntry.encode.bytes = ptr
}
exports.VisualSampleEntry.decode = function (buf, offset, end) {
buf = buf.slice(offset)
var length = end - offset
var nameLen = Math.min(buf.readUInt8(42), 31)
var box = {
dataReferenceIndex: buf.readUInt16BE(6),
width: buf.readUInt16BE(24),
height: buf.readUInt16BE(26),
hResolution: buf.readUInt32BE(28),
vResolution: buf.readUInt32BE(32),
frameCount: buf.readUInt16BE(40),
compressorName: buf.toString('utf8', 43, 43 + nameLen),
depth: buf.readUInt16BE(74),
children: []
}
var ptr = 78
while (length - ptr >= 8) {
var child = Box.decode(buf, ptr, length)
box.children.push(child)
box[child.type] = child
ptr += child.length
}
return box
}
exports.VisualSampleEntry.encodingLength = function (box) {
var len = 78
var children = box.children || []
children.forEach(function (child) {
len += Box.encodingLength(child)
})
return len
}
exports.avcC = {}
exports.avcC.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(box.buffer.length)
box.buffer.copy(buf)
exports.avcC.encode.bytes = box.buffer.length
}
exports.avcC.decode = function (buf, offset, end) {
buf = buf.slice(offset, end)
return {
mimeCodec: buf.toString('hex', 1, 4),
buffer: Buffer.from(buf)
}
}
exports.avcC.encodingLength = function (box) {
return box.buffer.length
}
exports.mp4a = exports.AudioSampleEntry = {}
exports.AudioSampleEntry.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.AudioSampleEntry.encodingLength(box))
writeReserved(buf, 0, 6)
buf.writeUInt16BE(box.dataReferenceIndex || 0, 6)
writeReserved(buf, 8, 16)
buf.writeUInt16BE(box.channelCount || 2, 16)
buf.writeUInt16BE(box.sampleSize || 16, 18)
writeReserved(buf, 20, 24)
buf.writeUInt32BE(box.sampleRate || 0, 24)
var ptr = 28
var children = box.children || []
children.forEach(function (child) {
Box.encode(child, buf, ptr)
ptr += Box.encode.bytes
})
exports.AudioSampleEntry.encode.bytes = ptr
}
exports.AudioSampleEntry.decode = function (buf, offset, end) {
buf = buf.slice(offset, end)
var length = end - offset
var box = {
dataReferenceIndex: buf.readUInt16BE(6),
channelCount: buf.readUInt16BE(16),
sampleSize: buf.readUInt16BE(18),
sampleRate: buf.readUInt32BE(24),
children: []
}
var ptr = 28
while (length - ptr >= 8) {
var child = Box.decode(buf, ptr, length)
box.children.push(child)
box[child.type] = child
ptr += child.length
}
return box
}
exports.AudioSampleEntry.encodingLength = function (box) {
var len = 28
var children = box.children || []
children.forEach(function (child) {
len += Box.encodingLength(child)
})
return len
}
exports.esds = {}
exports.esds.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(box.buffer.length)
box.buffer.copy(buf, 0)
exports.esds.encode.bytes = box.buffer.length
}
exports.esds.decode = function (buf, offset, end) {
buf = buf.slice(offset, end)
var desc = Descriptor.Descriptor.decode(buf, 0, buf.length)
var esd = (desc.tagName === 'ESDescriptor') ? desc : {}
var dcd = esd.DecoderConfigDescriptor || {}
var oti = dcd.oti || 0
var dsi = dcd.DecoderSpecificInfo
var audioConfig = dsi ? (dsi.buffer.readUInt8(0) & 0xf8) >> 3 : 0
var mimeCodec = null
if (oti) {
mimeCodec = oti.toString(16)
if (audioConfig) {
mimeCodec += '.' + audioConfig
}
}
return {
mimeCodec: mimeCodec,
buffer: Buffer.from(buf.slice(0))
}
}
exports.esds.encodingLength = function (box) {
return box.buffer.length
}
// TODO: integrate the two versions in a saner way
exports.stsz = {}
exports.stsz.encode = function (box, buf, offset) {
var entries = box.entries || []
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.stsz.encodingLength(box))
buf.writeUInt32BE(0, 0)
buf.writeUInt32BE(entries.length, 4)
for (var i = 0; i < entries.length; i++) {
buf.writeUInt32BE(entries[i], i * 4 + 8)
}
exports.stsz.encode.bytes = 8 + entries.length * 4
return buf
}
exports.stsz.decode = function (buf, offset) {
buf = buf.slice(offset)
var size = buf.readUInt32BE(0)
var num = buf.readUInt32BE(4)
var entries = new Array(num)
for (var i = 0; i < num; i++) {
if (size === 0) {
entries[i] = buf.readUInt32BE(i * 4 + 8)
} else {
entries[i] = size
}
}
return {
entries: entries
}
}
exports.stsz.encodingLength = function (box) {
return 8 + box.entries.length * 4
}
exports.stss =
exports.stco = {}
exports.stco.encode = function (box, buf, offset) {
var entries = box.entries || []
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.stco.encodingLength(box))
buf.writeUInt32BE(entries.length, 0)
for (var i = 0; i < entries.length; i++) {
buf.writeUInt32BE(entries[i], i * 4 + 4)
}
exports.stco.encode.bytes = 4 + entries.length * 4
return buf
}
exports.stco.decode = function (buf, offset) {
buf = buf.slice(offset)
var num = buf.readUInt32BE(0)
var entries = new Array(num)
for (var i = 0; i < num; i++) {
entries[i] = buf.readUInt32BE(i * 4 + 4)
}
return {
entries: entries
}
}
exports.stco.encodingLength = function (box) {
return 4 + box.entries.length * 4
}
exports.co64 = {}
exports.co64.encode = function (box, buf, offset) {
var entries = box.entries || []
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.co64.encodingLength(box))
buf.writeUInt32BE(entries.length, 0)
for (var i = 0; i < entries.length; i++) {
uint64be.encode(entries[i], buf, i * 8 + 4)
}
exports.co64.encode.bytes = 4 + entries.length * 8
return buf
}
exports.co64.decode = function (buf, offset) {
buf = buf.slice(offset)
var num = buf.readUInt32BE(0)
var entries = new Array(num)
for (var i = 0; i < num; i++) {
entries[i] = uint64be.decode(buf, i * 8 + 4)
}
return {
entries: entries
}
}
exports.co64.encodingLength = function (box) {
return 4 + box.entries.length * 8
}
exports.stts = {}
exports.stts.encode = function (box, buf, offset) {
var entries = box.entries || []
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.stts.encodingLength(box))
buf.writeUInt32BE(entries.length, 0)
for (var i = 0; i < entries.length; i++) {
var ptr = i * 8 + 4
buf.writeUInt32BE(entries[i].count || 0, ptr)
buf.writeUInt32BE(entries[i].duration || 0, ptr + 4)
}
exports.stts.encode.bytes = 4 + box.entries.length * 8
return buf
}
exports.stts.decode = function (buf, offset) {
buf = buf.slice(offset)
var num = buf.readUInt32BE(0)
var entries = new Array(num)
for (var i = 0; i < num; i++) {
var ptr = i * 8 + 4
entries[i] = {
count: buf.readUInt32BE(ptr),
duration: buf.readUInt32BE(ptr + 4)
}
}
return {
entries: entries
}
}
exports.stts.encodingLength = function (box) {
return 4 + box.entries.length * 8
}
exports.ctts = {}
exports.ctts.encode = function (box, buf, offset) {
var entries = box.entries || []
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.ctts.encodingLength(box))
buf.writeUInt32BE(entries.length, 0)
for (var i = 0; i < entries.length; i++) {
var ptr = i * 8 + 4
buf.writeUInt32BE(entries[i].count || 0, ptr)
buf.writeUInt32BE(entries[i].compositionOffset || 0, ptr + 4)
}
exports.ctts.encode.bytes = 4 + entries.length * 8
return buf
}
exports.ctts.decode = function (buf, offset) {
buf = buf.slice(offset)
var num = buf.readUInt32BE(0)
var entries = new Array(num)
for (var i = 0; i < num; i++) {
var ptr = i * 8 + 4
entries[i] = {
count: buf.readUInt32BE(ptr),
compositionOffset: buf.readInt32BE(ptr + 4)
}
}
return {
entries: entries
}
}
exports.ctts.encodingLength = function (box) {
return 4 + box.entries.length * 8
}
exports.stsc = {}
exports.stsc.encode = function (box, buf, offset) {
var entries = box.entries || []
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.stsc.encodingLength(box))
buf.writeUInt32BE(entries.length, 0)
for (var i = 0; i < entries.length; i++) {
var ptr = i * 12 + 4
buf.writeUInt32BE(entries[i].firstChunk || 0, ptr)
buf.writeUInt32BE(entries[i].samplesPerChunk || 0, ptr + 4)
buf.writeUInt32BE(entries[i].sampleDescriptionId || 0, ptr + 8)
}
exports.stsc.encode.bytes = 4 + entries.length * 12
return buf
}
exports.stsc.decode = function (buf, offset) {
buf = buf.slice(offset)
var num = buf.readUInt32BE(0)
var entries = new Array(num)
for (var i = 0; i < num; i++) {
var ptr = i * 12 + 4
entries[i] = {
firstChunk: buf.readUInt32BE(ptr),
samplesPerChunk: buf.readUInt32BE(ptr + 4),
sampleDescriptionId: buf.readUInt32BE(ptr + 8)
}
}
return {
entries: entries
}
}
exports.stsc.encodingLength = function (box) {
return 4 + box.entries.length * 12
}
exports.dref = {}
exports.dref.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.dref.encodingLength(box))
var entries = box.entries || []
buf.writeUInt32BE(entries.length, 0)
var ptr = 4
for (var i = 0; i < entries.length; i++) {
var entry = entries[i]
var size = (entry.buf ? entry.buf.length : 0) + 4 + 4
buf.writeUInt32BE(size, ptr)
ptr += 4
buf.write(entry.type, ptr, 4, 'ascii')
ptr += 4
if (entry.buf) {
entry.buf.copy(buf, ptr)
ptr += entry.buf.length
}
}
exports.dref.encode.bytes = ptr
return buf
}
exports.dref.decode = function (buf, offset) {
buf = buf.slice(offset)
var num = buf.readUInt32BE(0)
var entries = new Array(num)
var ptr = 4
for (var i = 0; i < num; i++) {
var size = buf.readUInt32BE(ptr)
var type = buf.toString('ascii', ptr + 4, ptr + 8)
var tmp = buf.slice(ptr + 8, ptr + size)
ptr += size
entries[i] = {
type: type,
buf: tmp
}
}
return {
entries: entries
}
}
exports.dref.encodingLength = function (box) {
var totalSize = 4
if (!box.entries) return totalSize
for (var i = 0; i < box.entries.length; i++) {
var buf = box.entries[i].buf
totalSize += (buf ? buf.length : 0) + 4 + 4
}
return totalSize
}
exports.elst = {}
exports.elst.encode = function (box, buf, offset) {
var entries = box.entries || []
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.elst.encodingLength(box))
buf.writeUInt32BE(entries.length, 0)
for (var i = 0; i < entries.length; i++) {
var ptr = i * 12 + 4
buf.writeUInt32BE(entries[i].trackDuration || 0, ptr)
buf.writeUInt32BE(entries[i].mediaTime || 0, ptr + 4)
writeFixed32(entries[i].mediaRate || 0, buf, ptr + 8)
}
exports.elst.encode.bytes = 4 + entries.length * 12
return buf
}
exports.elst.decode = function (buf, offset) {
buf = buf.slice(offset)
var num = buf.readUInt32BE(0)
var entries = new Array(num)
for (var i = 0; i < num; i++) {
var ptr = i * 12 + 4
entries[i] = {
trackDuration: buf.readUInt32BE(ptr),
mediaTime: buf.readInt32BE(ptr + 4),
mediaRate: readFixed32(buf, ptr + 8)
}
}
return {
entries: entries
}
}
exports.elst.encodingLength = function (box) {
return 4 + box.entries.length * 12
}
exports.hdlr = {}
exports.hdlr.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(exports.hdlr.encodingLength(box))
var len = 21 + (box.name || '').length
buf.fill(0, 0, len)
buf.write(box.handlerType || '', 4, 4, 'ascii')
writeString(box.name || '', buf, 20)
exports.hdlr.encode.bytes = len
return buf
}
exports.hdlr.decode = function (buf, offset, end) {
buf = buf.slice(offset)
return {
handlerType: buf.toString('ascii', 4, 8),
name: readString(buf, 20, end)
}
}
exports.hdlr.encodingLength = function (box) {
return 21 + (box.name || '').length
}
exports.mehd = {}
exports.mehd.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(4)
buf.writeUInt32BE(box.fragmentDuration || 0, 0)
exports.mehd.encode.bytes = 4
return buf
}
exports.mehd.decode = function (buf, offset) {
buf = buf.slice(offset)
return {
fragmentDuration: buf.readUInt32BE(0)
}
}
exports.mehd.encodingLength = function (box) {
return 4
}
exports.trex = {}
exports.trex.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(20)
buf.writeUInt32BE(box.trackId || 0, 0)
buf.writeUInt32BE(box.defaultSampleDescriptionIndex || 0, 4)
buf.writeUInt32BE(box.defaultSampleDuration || 0, 8)
buf.writeUInt32BE(box.defaultSampleSize || 0, 12)
buf.writeUInt32BE(box.defaultSampleFlags || 0, 16)
exports.trex.encode.bytes = 20
return buf
}
exports.trex.decode = function (buf, offset) {
buf = buf.slice(offset)
return {
trackId: buf.readUInt32BE(0),
defaultSampleDescriptionIndex: buf.readUInt32BE(4),
defaultSampleDuration: buf.readUInt32BE(8),
defaultSampleSize: buf.readUInt32BE(12),
defaultSampleFlags: buf.readUInt32BE(16)
}
}
exports.trex.encodingLength = function (box) {
return 20
}
exports.mfhd = {}
exports.mfhd.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(4)
buf.writeUInt32BE(box.sequenceNumber || 0, 0)
exports.mfhd.encode.bytes = 4
return buf
}
exports.mfhd.decode = function (buf, offset) {
return {
sequenceNumber: buf.readUInt32BE(0)
}
}
exports.mfhd.encodingLength = function (box) {
return 4
}
exports.tfhd = {}
exports.tfhd.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(4)
buf.writeUInt32BE(box.trackId, 0)
exports.tfhd.encode.bytes = 4
return buf
}
exports.tfhd.decode = function (buf, offset) {
// TODO: this
}
exports.tfhd.encodingLength = function (box) {
// TODO: this is wrong!
return 4
}
exports.tfdt = {}
exports.tfdt.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(4)
buf.writeUInt32BE(box.baseMediaDecodeTime || 0, 0)
exports.tfdt.encode.bytes = 4
return buf
}
exports.tfdt.decode = function (buf, offset) {
// TODO: this
}
exports.tfdt.encodingLength = function (box) {
return 4
}
exports.trun = {}
exports.trun.encode = function (box, buf, offset) {
buf = buf ? buf.slice(offset) : Buffer.alloc(8 + box.entries.length * 16)
// TODO: this is wrong
buf.writeUInt32BE(box.entries.length, 0)
buf.writeInt32BE(box.dataOffset, 4)
var ptr = 8
for (var i = 0; i < box.entries.length; i++) {
var entry = box.entries[i]
buf.writeUInt32BE(entry.sampleDuration, ptr)
ptr += 4
buf.writeUInt32BE(entry.sampleSize, ptr)
ptr += 4
buf.writeUInt32BE(entry.sampleFlags, ptr)
ptr += 4
if ((box.version || 0) === 0) {
buf.writeUInt32BE(entry.sampleCompositionTimeOffset, ptr)
} else {
buf.writeInt32BE(entry.sampleCompositionTimeOffset, ptr)
}
ptr += 4
}
exports.trun.encode.bytes = ptr
}
exports.trun.decode = function (buf, offset) {
// TODO: this
}
exports.trun.encodingLength = function (box) {
// TODO: this is wrong
return 8 + box.entries.length * 16
}
exports.mdat = {}
exports.mdat.encode = function (box, buf, offset) {
if (box.buffer) {
box.buffer.copy(buf, offset)
exports.mdat.encode.bytes = box.buffer.length
} else {
exports.mdat.encode.bytes = exports.mdat.encodingLength(box)
}
}
exports.mdat.decode = function (buf, start, end) {
return {
buffer: Buffer.from(buf.slice(start, end))
}
}
exports.mdat.encodingLength = function (box) {
return box.buffer ? box.buffer.length : box.contentLength
}
function writeReserved (buf, offset, end) {
for (var i = offset; i < end; i++) buf[i] = 0
}
function writeDate (date, buf, offset) {
buf.writeUInt32BE(Math.floor((date.getTime() + TIME_OFFSET) / 1000), offset)
}
function writeDate64 (date, buf, offset) {
// Node only supports integer <= 48bit. Waiting for BigInt!
buf.writeUIntBE(Math.floor((date.getTime() + TIME_OFFSET) / 1000), offset, 6)
}
// TODO: think something is wrong here
function writeFixed32 (num, buf, offset) {
buf.writeUInt16BE(Math.floor(num) % (256 * 256), offset)
buf.writeUInt16BE(Math.floor(num * 256 * 256) % (256 * 256), offset + 2)
}
function writeFixed16 (num, buf, offset) {
buf[offset] = Math.floor(num) % 256
buf[offset + 1] = Math.floor(num * 256) % 256
}
function writeMatrix (list, buf, offset) {
if (!list) list = [0, 0, 0, 0, 0, 0, 0, 0, 0]
for (var i = 0; i < list.length; i++) {
writeFixed32(list[i], buf, offset + i * 4)
}
}
function writeString (str, buf, offset) {
var strBuffer = Buffer.from(str, 'utf8')
strBuffer.copy(buf, offset)
buf[offset + strBuffer.length] = 0
}
function readMatrix (buf) {
var list = new Array(buf.length / 4)
for (var i = 0; i < list.length; i++) list[i] = readFixed32(buf, i * 4)
return list
}
function readDate64 (buf, offset) {
// Node only supports integer <= 48bit. Waiting for BigInt!
return new Date(buf.readUIntBE(offset, 6) * 1000 - TIME_OFFSET)
}
function readDate (buf, offset) {
return new Date(buf.readUInt32BE(offset) * 1000 - TIME_OFFSET)
}
function readFixed32 (buf, offset) {
return buf.readUInt16BE(offset) + buf.readUInt16BE(offset + 2) / (256 * 256)
}
function readFixed16 (buf, offset) {
return buf[offset] + buf[offset + 1] / 256
}
function readString (buf, offset, length) {
var i
for (i = 0; i < length; i++) {
if (buf[offset + i] === 0) {
break
}
}
return buf.toString('utf8', offset, offset + i)
}
}).call(this)}).call(this,require("buffer").Buffer)
},{"./descriptor":146,"./index":147,"buffer":60,"uint64be":297}],146:[function(require,module,exports){
(function (Buffer){(function (){
var tagToName = {
0x03: 'ESDescriptor',
0x04: 'DecoderConfigDescriptor',
0x05: 'DecoderSpecificInfo',
0x06: 'SLConfigDescriptor'
}
exports.Descriptor = {}
exports.Descriptor.decode = function (buf, start, end) {
var tag = buf.readUInt8(start)
var ptr = start + 1
var lenByte
var len = 0
do {
lenByte = buf.readUInt8(ptr++)
len = (len << 7) | (lenByte & 0x7f)
} while (lenByte & 0x80)
var obj
var tagName = tagToName[tag] // May be undefined; that's ok
if (exports[tagName]) {
obj = exports[tagName].decode(buf, ptr, end)
} else {
obj = {
buffer: Buffer.from(buf.slice(ptr, ptr + len))
}
}
obj.tag = tag
obj.tagName = tagName
obj.length = (ptr - start) + len
obj.contentsLen = len
return obj
}
exports.DescriptorArray = {}
exports.DescriptorArray.decode = function (buf, start, end) {
var ptr = start
var obj = {}
while (ptr + 2 <= end) {
var descriptor = exports.Descriptor.decode(buf, ptr, end)
ptr += descriptor.length
var tagName = tagToName[descriptor.tag] || ('Descriptor' + descriptor.tag)
obj[tagName] = descriptor
}
return obj
}
exports.ESDescriptor = {}
exports.ESDescriptor.decode = function (buf, start, end) {
var flags = buf.readUInt8(start + 2)
var ptr = start + 3
if (flags & 0x80) {
ptr += 2
}
if (flags & 0x40) {
var len = buf.readUInt8(ptr)
ptr += len + 1
}
if (flags & 0x20) {
ptr += 2
}
return exports.DescriptorArray.decode(buf, ptr, end)
}
exports.DecoderConfigDescriptor = {}
exports.DecoderConfigDescriptor.decode = function (buf, start, end) {
var oti = buf.readUInt8(start)
var obj = exports.DescriptorArray.decode(buf, start + 13, end)
obj.oti = oti
return obj
}
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60}],147:[function(require,module,exports){
(function (Buffer){(function (){
// var assert = require('assert')
var uint64be = require('uint64be')
var boxes = require('./boxes')
var UINT32_MAX = 4294967295
var Box = exports
/*
* Lists the proper order for boxes inside containers.
* Five-character names ending in 's' indicate arrays instead of single elements.
*/
var containers = exports.containers = {
'moov': ['mvhd', 'meta', 'traks', 'mvex'],
'trak': ['tkhd', 'tref', 'trgr', 'edts', 'meta', 'mdia', 'udta'],
'edts': ['elst'],
'mdia': ['mdhd', 'hdlr', 'elng', 'minf'],
'minf': ['vmhd', 'smhd', 'hmhd', 'sthd', 'nmhd', 'dinf', 'stbl'],
'dinf': ['dref'],
'stbl': ['stsd', 'stts', 'ctts', 'cslg', 'stsc', 'stsz', 'stz2', 'stco', 'co64', 'stss', 'stsh', 'padb', 'stdp', 'sdtp', 'sbgps', 'sgpds', 'subss', 'saizs', 'saios'],
'mvex': ['mehd', 'trexs', 'leva'],
'moof': ['mfhd', 'meta', 'trafs'],
'traf': ['tfhd', 'tfdt', 'trun', 'sbgps', 'sgpds', 'subss', 'saizs', 'saios', 'meta']
}
Box.encode = function (obj, buffer, offset) {
Box.encodingLength(obj) // sets every level appropriately
offset = offset || 0
buffer = buffer || Buffer.alloc(obj.length)
return Box._encode(obj, buffer, offset)
}
Box._encode = function (obj, buffer, offset) {
var type = obj.type
var len = obj.length
if (len > UINT32_MAX) {
len = 1
}
buffer.writeUInt32BE(len, offset)
buffer.write(obj.type, offset + 4, 4, 'ascii')
var ptr = offset + 8
if (len === 1) {
uint64be.encode(obj.length, buffer, ptr)
ptr += 8
}
if (boxes.fullBoxes[type]) {
buffer.writeUInt32BE(obj.flags || 0, ptr)
buffer.writeUInt8(obj.version || 0, ptr)
ptr += 4
}
if (containers[type]) {
var contents = containers[type]
contents.forEach(function (childType) {
if (childType.length === 5) {
var entry = obj[childType] || []
childType = childType.substr(0, 4)
entry.forEach(function (child) {
Box._encode(child, buffer, ptr)
ptr += Box.encode.bytes
})
} else if (obj[childType]) {
Box._encode(obj[childType], buffer, ptr)
ptr += Box.encode.bytes
}
})
if (obj.otherBoxes) {
obj.otherBoxes.forEach(function (child) {
Box._encode(child, buffer, ptr)
ptr += Box.encode.bytes
})
}
} else if (boxes[type]) {
var encode = boxes[type].encode
encode(obj, buffer, ptr)
ptr += encode.bytes
} else if (obj.buffer) {
var buf = obj.buffer
buf.copy(buffer, ptr)
ptr += obj.buffer.length
} else {
throw new Error('Either `type` must be set to a known type (not\'' + type + '\') or `buffer` must be set')
}
Box.encode.bytes = ptr - offset
// assert.equal(ptr - offset, obj.length, 'Error encoding \'' + type + '\': wrote ' + ptr - offset + ' bytes, expecting ' + obj.length)
return buffer
}
/*
* Returns an object with `type` and `size` fields,
* or if there isn't enough data, returns the total
* number of bytes needed to read the headers
*/
Box.readHeaders = function (buffer, start, end) {
start = start || 0
end = end || buffer.length
if (end - start < 8) {
return 8
}
var len = buffer.readUInt32BE(start)
var type = buffer.toString('ascii', start + 4, start + 8)
var ptr = start + 8
if (len === 1) {
if (end - start < 16) {
return 16
}
len = uint64be.decode(buffer, ptr)
ptr += 8
}
var version
var flags
if (boxes.fullBoxes[type]) {
version = buffer.readUInt8(ptr)
flags = buffer.readUInt32BE(ptr) & 0xffffff
ptr += 4
}
return {
length: len,
headersLen: ptr - start,
contentLen: len - (ptr - start),
type: type,
version: version,
flags: flags
}
}
Box.decode = function (buffer, start, end) {
start = start || 0
end = end || buffer.length
var headers = Box.readHeaders(buffer, start, end)
if (!headers || headers.length > end - start) {
throw new Error('Data too short')
}
return Box.decodeWithoutHeaders(headers, buffer, start + headers.headersLen, start + headers.length)
}
Box.decodeWithoutHeaders = function (headers, buffer, start, end) {
start = start || 0
end = end || buffer.length
var type = headers.type
var obj = {}
if (containers[type]) {
obj.otherBoxes = []
var contents = containers[type]
var ptr = start
while (end - ptr >= 8) {
var child = Box.decode(buffer, ptr, end)
ptr += child.length
if (contents.indexOf(child.type) >= 0) {
obj[child.type] = child
} else if (contents.indexOf(child.type + 's') >= 0) {
var childType = child.type + 's'
var entry = obj[childType] = obj[childType] || []
entry.push(child)
} else {
obj.otherBoxes.push(child)
}
}
} else if (boxes[type]) {
var decode = boxes[type].decode
obj = decode(buffer, start, end)
} else {
obj.buffer = Buffer.from(buffer.slice(start, end))
}
obj.length = headers.length
obj.contentLen = headers.contentLen
obj.type = headers.type
obj.version = headers.version
obj.flags = headers.flags
return obj
}
Box.encodingLength = function (obj) {
var type = obj.type
var len = 8
if (boxes.fullBoxes[type]) {
len += 4
}
if (containers[type]) {
var contents = containers[type]
contents.forEach(function (childType) {
if (childType.length === 5) {
var entry = obj[childType] || []
childType = childType.substr(0, 4)
entry.forEach(function (child) {
child.type = childType
len += Box.encodingLength(child)
})
} else if (obj[childType]) {
var child = obj[childType]
child.type = childType
len += Box.encodingLength(child)
}
})
if (obj.otherBoxes) {
obj.otherBoxes.forEach(function (child) {
len += Box.encodingLength(child)
})
}
} else if (boxes[type]) {
len += boxes[type].encodingLength(obj)
} else if (obj.buffer) {
len += obj.buffer.length
} else {
throw new Error('Either `type` must be set to a known type (not\'' + type + '\') or `buffer` must be set')
}
if (len > UINT32_MAX) {
len += 8
}
obj.length = len
return len
}
}).call(this)}).call(this,require("buffer").Buffer)
},{"./boxes":145,"buffer":60,"uint64be":297}],148:[function(require,module,exports){
(function (Buffer){(function (){
var stream = require('readable-stream')
var nextEvent = require('next-event')
var Box = require('mp4-box-encoding')
var EMPTY = Buffer.alloc(0)
class Decoder extends stream.Writable {
constructor (opts) {
super(opts)
this.destroyed = false
this._pending = 0
this._missing = 0
this._ignoreEmpty = false
this._buf = null
this._str = null
this._cb = null
this._ondrain = null
this._writeBuffer = null
this._writeCb = null
this._ondrain = null
this._kick()
}
destroy (err) {
if (this.destroyed) return
this.destroyed = true
if (err) this.emit('error', err)
this.emit('close')
}
_write (data, enc, next) {
if (this.destroyed) return
var drained = !this._str || !this._str._writableState.needDrain
while (data.length && !this.destroyed) {
if (!this._missing && !this._ignoreEmpty) {
this._writeBuffer = data
this._writeCb = next
return
}
var consumed = data.length < this._missing ? data.length : this._missing
if (this._buf) data.copy(this._buf, this._buf.length - this._missing)
else if (this._str) drained = this._str.write(consumed === data.length ? data : data.slice(0, consumed))
this._missing -= consumed
if (!this._missing) {
var buf = this._buf
var cb = this._cb
var stream = this._str
this._buf = this._cb = this._str = this._ondrain = null
drained = true
this._ignoreEmpty = false
if (stream) stream.end()
if (cb) cb(buf)
}
data = consumed === data.length ? EMPTY : data.slice(consumed)
}
if (this._pending && !this._missing) {
this._writeBuffer = data
this._writeCb = next
return
}
if (drained) next()
else this._ondrain(next)
}
_buffer (size, cb) {
this._missing = size
this._buf = Buffer.alloc(size)
this._cb = cb
}
_stream (size, cb) {
this._missing = size
this._str = new MediaData(this)
this._ondrain = nextEvent(this._str, 'drain')
this._pending++
this._str.on('end', () => {
this._pending--
this._kick()
})
this._cb = cb
return this._str
}
_readBox () {
const bufferHeaders = (len, buf) => {
this._buffer(len, additionalBuf => {
if (buf) {
buf = Buffer.concat([buf, additionalBuf])
} else {
buf = additionalBuf
}
var headers = Box.readHeaders(buf)
if (typeof headers === 'number') {
bufferHeaders(headers - buf.length, buf)
} else {
this._pending++
this._headers = headers
this.emit('box', headers)
}
})
}
bufferHeaders(8)
}
stream () {
if (!this._headers) throw new Error('this function can only be called once after \'box\' is emitted')
var headers = this._headers
this._headers = null
return this._stream(headers.contentLen, null)
}
decode (cb) {
if (!this._headers) throw new Error('this function can only be called once after \'box\' is emitted')
var headers = this._headers
this._headers = null
this._buffer(headers.contentLen, buf => {
var box = Box.decodeWithoutHeaders(headers, buf)
cb(box)
this._pending--
this._kick()
})
}
ignore () {
if (!this._headers) throw new Error('this function can only be called once after \'box\' is emitted')
var headers = this._headers
this._headers = null
this._missing = headers.contentLen
if (this._missing === 0) {
this._ignoreEmpty = true
}
this._cb = () => {
this._pending--
this._kick()
}
}
_kick () {
if (this._pending) return
if (!this._buf && !this._str) this._readBox()
if (this._writeBuffer) {
var next = this._writeCb
var buffer = this._writeBuffer
this._writeBuffer = null
this._writeCb = null
this._write(buffer, null, next)
}
}
}
class MediaData extends stream.PassThrough {
constructor (parent) {
super()
this._parent = parent
this.destroyed = false
}
destroy (err) {
if (this.destroyed) return
this.destroyed = true
this._parent.destroy(err)
if (err) this.emit('error', err)
this.emit('close')
}
}
module.exports = Decoder
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60,"mp4-box-encoding":147,"next-event":182,"readable-stream":165}],149:[function(require,module,exports){
(function (process,Buffer){(function (){
var stream = require('readable-stream')
var Box = require('mp4-box-encoding')
function noop () {}
class Encoder extends stream.Readable {
constructor (opts) {
super(opts)
this.destroyed = false
this._finalized = false
this._reading = false
this._stream = null
this._drain = null
this._want = false
this._onreadable = () => {
if (!this._want) return
this._want = false
this._read()
}
this._onend = () => {
this._stream = null
}
}
mdat (size, cb) {
this.mediaData(size, cb)
}
mediaData (size, cb) {
var stream = new MediaData(this)
this.box({ type: 'mdat', contentLength: size, encodeBufferLen: 8, stream: stream }, cb)
return stream
}
box (box, cb) {
if (!cb) cb = noop
if (this.destroyed) return cb(new Error('Encoder is destroyed'))
var buf
if (box.encodeBufferLen) {
buf = Buffer.alloc(box.encodeBufferLen)
}
if (box.stream) {
box.buffer = null
buf = Box.encode(box, buf)
this.push(buf)
this._stream = box.stream
this._stream.on('readable', this._onreadable)
this._stream.on('end', this._onend)
this._stream.on('end', cb)
this._forward()
} else {
buf = Box.encode(box, buf)
var drained = this.push(buf)
if (drained) return process.nextTick(cb)
this._drain = cb
}
}
destroy (err) {
if (this.destroyed) return
this.destroyed = true
if (this._stream && this._stream.destroy) this._stream.destroy()
this._stream = null
if (this._drain) {
var cb = this._drain
this._drain = null
cb(err)
}
if (err) this.emit('error', err)
this.emit('close')
}
finalize () {
this._finalized = true
if (!this._stream && !this._drain) {
this.push(null)
}
}
_forward () {
if (!this._stream) return
while (!this.destroyed) {
var buf = this._stream.read()
if (!buf) {
this._want = !!this._stream
return
}
if (!this.push(buf)) return
}
}
_read () {
if (this._reading || this.destroyed) return
this._reading = true
if (this._stream) this._forward()
if (this._drain) {
var drain = this._drain
this._drain = null
drain()
}
this._reading = false
if (this._finalized) {
this.push(null)
}
}
}
class MediaData extends stream.PassThrough {
constructor (parent) {
super()
this._parent = parent
this.destroyed = false
}
destroy (err) {
if (this.destroyed) return
this.destroyed = true
this._parent.destroy(err)
if (err) this.emit('error', err)
this.emit('close')
}
}
module.exports = Encoder
}).call(this)}).call(this,require('_process'),require("buffer").Buffer)
},{"_process":187,"buffer":60,"mp4-box-encoding":147,"readable-stream":165}],150:[function(require,module,exports){
const Decoder = require('./decode')
const Encoder = require('./encode')
exports.decode = opts => new Decoder(opts)
exports.encode = opts => new Encoder(opts)
},{"./decode":148,"./encode":149}],151:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],152:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":154,"./_stream_writable":156,"_process":187,"dup":17,"inherits":119}],153:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":155,"dup":18,"inherits":119}],154:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":151,"./_stream_duplex":152,"./internal/streams/async_iterator":157,"./internal/streams/buffer_list":158,"./internal/streams/destroy":159,"./internal/streams/from":161,"./internal/streams/state":163,"./internal/streams/stream":164,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],155:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":151,"./_stream_duplex":152,"dup":20,"inherits":119}],156:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":151,"./_stream_duplex":152,"./internal/streams/destroy":159,"./internal/streams/state":163,"./internal/streams/stream":164,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],157:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":160,"_process":187,"dup":22}],158:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],159:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],160:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":151,"dup":25}],161:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],162:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":151,"./end-of-stream":160,"dup":27}],163:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":151,"dup":28}],164:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],165:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":152,"./lib/_stream_passthrough.js":153,"./lib/_stream_readable.js":154,"./lib/_stream_transform.js":155,"./lib/_stream_writable.js":156,"./lib/internal/streams/end-of-stream.js":160,"./lib/internal/streams/pipeline.js":162,"dup":30}],166:[function(require,module,exports){
/*! multistream. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
var stream = require('readable-stream')
function toStreams2Obj (s) {
return toStreams2(s, { objectMode: true, highWaterMark: 16 })
}
function toStreams2Buf (s) {
return toStreams2(s)
}
function toStreams2 (s, opts) {
if (!s || typeof s === 'function' || s._readableState) return s
var wrap = new stream.Readable(opts).wrap(s)
if (s.destroy) {
wrap.destroy = s.destroy.bind(s)
}
return wrap
}
class MultiStream extends stream.Readable {
constructor (streams, opts) {
super(opts)
this.destroyed = false
this._drained = false
this._forwarding = false
this._current = null
this._toStreams2 = (opts && opts.objectMode) ? toStreams2Obj : toStreams2Buf
if (typeof streams === 'function') {
this._queue = streams
} else {
this._queue = streams.map(this._toStreams2)
this._queue.forEach(stream => {
if (typeof stream !== 'function') this._attachErrorListener(stream)
})
}
this._next()
}
_read () {
this._drained = true
this._forward()
}
_forward () {
if (this._forwarding || !this._drained || !this._current) return
this._forwarding = true
var chunk
while (this._drained && (chunk = this._current.read()) !== null) {
this._drained = this.push(chunk)
}
this._forwarding = false
}
destroy (err) {
if (this.destroyed) return
this.destroyed = true
if (this._current && this._current.destroy) this._current.destroy()
if (typeof this._queue !== 'function') {
this._queue.forEach(stream => {
if (stream.destroy) stream.destroy()
})
}
if (err) this.emit('error', err)
this.emit('close')
}
_next () {
this._current = null
if (typeof this._queue === 'function') {
this._queue((err, stream) => {
if (err) return this.destroy(err)
stream = this._toStreams2(stream)
this._attachErrorListener(stream)
this._gotNextStream(stream)
})
} else {
var stream = this._queue.shift()
if (typeof stream === 'function') {
stream = this._toStreams2(stream())
this._attachErrorListener(stream)
}
this._gotNextStream(stream)
}
}
_gotNextStream (stream) {
if (!stream) {
this.push(null)
this.destroy()
return
}
this._current = stream
this._forward()
const onReadable = () => {
this._forward()
}
const onClose = () => {
if (!stream._readableState.ended) {
this.destroy()
}
}
const onEnd = () => {
this._current = null
stream.removeListener('readable', onReadable)
stream.removeListener('end', onEnd)
stream.removeListener('close', onClose)
this._next()
}
stream.on('readable', onReadable)
stream.once('end', onEnd)
stream.once('close', onClose)
}
_attachErrorListener (stream) {
if (!stream) return
const onError = (err) => {
stream.removeListener('error', onError)
this.destroy(err)
}
stream.once('error', onError)
}
}
MultiStream.obj = streams => (
new MultiStream(streams, { objectMode: true, highWaterMark: 16 })
)
module.exports = MultiStream
},{"readable-stream":181}],167:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],168:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":170,"./_stream_writable":172,"_process":187,"dup":17,"inherits":119}],169:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":171,"dup":18,"inherits":119}],170:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":167,"./_stream_duplex":168,"./internal/streams/async_iterator":173,"./internal/streams/buffer_list":174,"./internal/streams/destroy":175,"./internal/streams/from":177,"./internal/streams/state":179,"./internal/streams/stream":180,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],171:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":167,"./_stream_duplex":168,"dup":20,"inherits":119}],172:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":167,"./_stream_duplex":168,"./internal/streams/destroy":175,"./internal/streams/state":179,"./internal/streams/stream":180,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],173:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":176,"_process":187,"dup":22}],174:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],175:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],176:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":167,"dup":25}],177:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],178:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":167,"./end-of-stream":176,"dup":27}],179:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":167,"dup":28}],180:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],181:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":168,"./lib/_stream_passthrough.js":169,"./lib/_stream_readable.js":170,"./lib/_stream_transform.js":171,"./lib/_stream_writable.js":172,"./lib/internal/streams/end-of-stream.js":176,"./lib/internal/streams/pipeline.js":178,"dup":30}],182:[function(require,module,exports){
module.exports = nextEvent
function nextEvent (emitter, name) {
var next = null
emitter.on(name, function (data) {
if (!next) return
var fn = next
next = null
fn(data)
})
return function (once) {
next = once
}
}
},{}],183:[function(require,module,exports){
var wrappy = require('wrappy')
module.exports = wrappy(once)
module.exports.strict = wrappy(onceStrict)
once.proto = once(function () {
Object.defineProperty(Function.prototype, 'once', {
value: function () {
return once(this)
},
configurable: true
})
Object.defineProperty(Function.prototype, 'onceStrict', {
value: function () {
return onceStrict(this)
},
configurable: true
})
})
function once (fn) {
var f = function () {
if (f.called) return f.value
f.called = true
return f.value = fn.apply(this, arguments)
}
f.called = false
return f
}
function onceStrict (fn) {
var f = function () {
if (f.called)
throw new Error(f.onceError)
f.called = true
return f.value = fn.apply(this, arguments)
}
var name = fn.name || 'Function wrapped with `once`'
f.onceError = name + " shouldn't be called more than once"
f.called = false
return f
}
},{"wrappy":335}],184:[function(require,module,exports){
(function (process,Buffer){(function (){
/*! parse-torrent. MIT License. WebTorrent LLC <https://webtorrent.io/opensource> */
/* global Blob */
const bencode = require('bencode')
const blobToBuffer = require('blob-to-buffer')
const fs = require('fs') // browser exclude
const get = require('simple-get')
const magnet = require('magnet-uri')
const path = require('path')
const sha1 = require('simple-sha1')
module.exports = parseTorrent
module.exports.remote = parseTorrentRemote
module.exports.toMagnetURI = magnet.encode
module.exports.toTorrentFile = encodeTorrentFile
/**
* Parse a torrent identifier (magnet uri, .torrent file, info hash)
* @param {string|Buffer|Object} torrentId
* @return {Object}
*/
function parseTorrent (torrentId) {
if (typeof torrentId === 'string' && /^(stream-)?magnet:/.test(torrentId)) {
// if magnet uri (string)
const torrentObj = magnet(torrentId)
// infoHash won't be defined if a non-bittorrent magnet is passed
if (!torrentObj.infoHash) {
throw new Error('Invalid torrent identifier')
}
return torrentObj
} else if (typeof torrentId === 'string' && (/^[a-f0-9]{40}$/i.test(torrentId) || /^[a-z2-7]{32}$/i.test(torrentId))) {
// if info hash (hex/base-32 string)
return magnet(`magnet:?xt=urn:btih:${torrentId}`)
} else if (Buffer.isBuffer(torrentId) && torrentId.length === 20) {
// if info hash (buffer)
return magnet(`magnet:?xt=urn:btih:${torrentId.toString('hex')}`)
} else if (Buffer.isBuffer(torrentId)) {
// if .torrent file (buffer)
return decodeTorrentFile(torrentId) // might throw
} else if (torrentId && torrentId.infoHash) {
// if parsed torrent (from `parse-torrent` or `magnet-uri`)
torrentId.infoHash = torrentId.infoHash.toLowerCase()
if (!torrentId.announce) torrentId.announce = []
if (typeof torrentId.announce === 'string') {
torrentId.announce = [torrentId.announce]
}
if (!torrentId.urlList) torrentId.urlList = []
return torrentId
} else {
throw new Error('Invalid torrent identifier')
}
}
function parseTorrentRemote (torrentId, opts, cb) {
if (typeof opts === 'function') return parseTorrentRemote(torrentId, {}, opts)
if (typeof cb !== 'function') throw new Error('second argument must be a Function')
let parsedTorrent
try {
parsedTorrent = parseTorrent(torrentId)
} catch (err) {
// If torrent fails to parse, it could be a Blob, http/https URL or
// filesystem path, so don't consider it an error yet.
}
if (parsedTorrent && parsedTorrent.infoHash) {
process.nextTick(() => {
cb(null, parsedTorrent)
})
} else if (isBlob(torrentId)) {
blobToBuffer(torrentId, (err, torrentBuf) => {
if (err) return cb(new Error(`Error converting Blob: ${err.message}`))
parseOrThrow(torrentBuf)
})
} else if (typeof get === 'function' && /^https?:/.test(torrentId)) {
// http, or https url to torrent file
opts = Object.assign({
url: torrentId,
timeout: 30 * 1000,
headers: { 'user-agent': 'WebTorrent (https://webtorrent.io)' }
}, opts)
get.concat(opts, (err, res, torrentBuf) => {
if (err) return cb(new Error(`Error downloading torrent: ${err.message}`))
parseOrThrow(torrentBuf)
})
} else if (typeof fs.readFile === 'function' && typeof torrentId === 'string') {
// assume it's a filesystem path
fs.readFile(torrentId, (err, torrentBuf) => {
if (err) return cb(new Error('Invalid torrent identifier'))
parseOrThrow(torrentBuf)
})
} else {
process.nextTick(() => {
cb(new Error('Invalid torrent identifier'))
})
}
function parseOrThrow (torrentBuf) {
try {
parsedTorrent = parseTorrent(torrentBuf)
} catch (err) {
return cb(err)
}
if (parsedTorrent && parsedTorrent.infoHash) cb(null, parsedTorrent)
else cb(new Error('Invalid torrent identifier'))
}
}
/**
* Parse a torrent. Throws an exception if the torrent is missing required fields.
* @param {Buffer|Object} torrent
* @return {Object} parsed torrent
*/
function decodeTorrentFile (torrent) {
if (Buffer.isBuffer(torrent)) {
torrent = bencode.decode(torrent)
}
// sanity check
ensure(torrent.info, 'info')
ensure(torrent.info['name.utf-8'] || torrent.info.name, 'info.name')
ensure(torrent.info['piece length'], 'info[\'piece length\']')
ensure(torrent.info.pieces, 'info.pieces')
if (torrent.info.files) {
torrent.info.files.forEach(file => {
ensure(typeof file.length === 'number', 'info.files[0].length')
ensure(file['path.utf-8'] || file.path, 'info.files[0].path')
})
} else {
ensure(typeof torrent.info.length === 'number', 'info.length')
}
const result = {
info: torrent.info,
infoBuffer: bencode.encode(torrent.info),
name: (torrent.info['name.utf-8'] || torrent.info.name).toString(),
announce: []
}
result.infoHash = sha1.sync(result.infoBuffer)
result.infoHashBuffer = Buffer.from(result.infoHash, 'hex')
if (torrent.info.private !== undefined) result.private = !!torrent.info.private
if (torrent['creation date']) result.created = new Date(torrent['creation date'] * 1000)
if (torrent['created by']) result.createdBy = torrent['created by'].toString()
if (Buffer.isBuffer(torrent.comment)) result.comment = torrent.comment.toString()
// announce and announce-list will be missing if metadata fetched via ut_metadata
if (Array.isArray(torrent['announce-list']) && torrent['announce-list'].length > 0) {
torrent['announce-list'].forEach(urls => {
urls.forEach(url => {
result.announce.push(url.toString())
})
})
} else if (torrent.announce) {
result.announce.push(torrent.announce.toString())
}
// handle url-list (BEP19 / web seeding)
if (Buffer.isBuffer(torrent['url-list'])) {
// some clients set url-list to empty string
torrent['url-list'] = torrent['url-list'].length > 0
? [torrent['url-list']]
: []
}
result.urlList = (torrent['url-list'] || []).map(url => url.toString())
// remove duplicates by converting to Set and back
result.announce = Array.from(new Set(result.announce))
result.urlList = Array.from(new Set(result.urlList))
const files = torrent.info.files || [torrent.info]
result.files = files.map((file, i) => {
const parts = [].concat(result.name, file['path.utf-8'] || file.path || []).map(p => p.toString())
return {
path: path.join.apply(null, [path.sep].concat(parts)).slice(1),
name: parts[parts.length - 1],
length: file.length,
offset: files.slice(0, i).reduce(sumLength, 0)
}
})
result.length = files.reduce(sumLength, 0)
const lastFile = result.files[result.files.length - 1]
result.pieceLength = torrent.info['piece length']
result.lastPieceLength = ((lastFile.offset + lastFile.length) % result.pieceLength) || result.pieceLength
result.pieces = splitPieces(torrent.info.pieces)
return result
}
/**
* Convert a parsed torrent object back into a .torrent file buffer.
* @param {Object} parsed parsed torrent
* @return {Buffer}
*/
function encodeTorrentFile (parsed) {
const torrent = {
info: parsed.info
}
torrent['announce-list'] = (parsed.announce || []).map(url => {
if (!torrent.announce) torrent.announce = url
url = Buffer.from(url, 'utf8')
return [url]
})
torrent['url-list'] = parsed.urlList || []
if (parsed.private !== undefined) {
torrent.private = Number(parsed.private)
}
if (parsed.created) {
torrent['creation date'] = (parsed.created.getTime() / 1000) | 0
}
if (parsed.createdBy) {
torrent['created by'] = parsed.createdBy
}
if (parsed.comment) {
torrent.comment = parsed.comment
}
return bencode.encode(torrent)
}
/**
* Check if `obj` is a W3C `Blob` or `File` object
* @param {*} obj
* @return {boolean}
*/
function isBlob (obj) {
return typeof Blob !== 'undefined' && obj instanceof Blob
}
function sumLength (sum, file) {
return sum + file.length
}
function splitPieces (buf) {
const pieces = []
for (let i = 0; i < buf.length; i += 20) {
pieces.push(buf.slice(i, i + 20).toString('hex'))
}
return pieces
}
function ensure (bool, fieldName) {
if (!bool) throw new Error(`Torrent is missing required field: ${fieldName}`)
}
// Workaround Browserify v13 bug
// https://github.com/substack/node-browserify/issues/1483
;(() => { Buffer.alloc(0) })()
}).call(this)}).call(this,require('_process'),require("buffer").Buffer)
},{"_process":187,"bencode":7,"blob-to-buffer":38,"buffer":60,"fs":56,"magnet-uri":124,"path":185,"simple-get":222,"simple-sha1":242}],185:[function(require,module,exports){
(function (process){(function (){
// 'path' module extracted from Node.js v8.11.1 (only the posix part)
// transplited with Babel
// 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';
function assertPath(path) {
if (typeof path !== 'string') {
throw new TypeError('Path must be a string. Received ' + JSON.stringify(path));
}
}
// Resolves . and .. elements in a path with directory names
function normalizeStringPosix(path, allowAboveRoot) {
var res = '';
var lastSegmentLength = 0;
var lastSlash = -1;
var dots = 0;
var code;
for (var i = 0; i <= path.length; ++i) {
if (i < path.length)
code = path.charCodeAt(i);
else if (code === 47 /*/*/)
break;
else
code = 47 /*/*/;
if (code === 47 /*/*/) {
if (lastSlash === i - 1 || dots === 1) {
// NOOP
} else if (lastSlash !== i - 1 && dots === 2) {
if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 /*.*/ || res.charCodeAt(res.length - 2) !== 46 /*.*/) {
if (res.length > 2) {
var lastSlashIndex = res.lastIndexOf('/');
if (lastSlashIndex !== res.length - 1) {
if (lastSlashIndex === -1) {
res = '';
lastSegmentLength = 0;
} else {
res = res.slice(0, lastSlashIndex);
lastSegmentLength = res.length - 1 - res.lastIndexOf('/');
}
lastSlash = i;
dots = 0;
continue;
}
} else if (res.length === 2 || res.length === 1) {
res = '';
lastSegmentLength = 0;
lastSlash = i;
dots = 0;
continue;
}
}
if (allowAboveRoot) {
if (res.length > 0)
res += '/..';
else
res = '..';
lastSegmentLength = 2;
}
} else {
if (res.length > 0)
res += '/' + path.slice(lastSlash + 1, i);
else
res = path.slice(lastSlash + 1, i);
lastSegmentLength = i - lastSlash - 1;
}
lastSlash = i;
dots = 0;
} else if (code === 46 /*.*/ && dots !== -1) {
++dots;
} else {
dots = -1;
}
}
return res;
}
function _format(sep, pathObject) {
var dir = pathObject.dir || pathObject.root;
var base = pathObject.base || (pathObject.name || '') + (pathObject.ext || '');
if (!dir) {
return base;
}
if (dir === pathObject.root) {
return dir + base;
}
return dir + sep + base;
}
var posix = {
// path.resolve([from ...], to)
resolve: function resolve() {
var resolvedPath = '';
var resolvedAbsolute = false;
var cwd;
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
var path;
if (i >= 0)
path = arguments[i];
else {
if (cwd === undefined)
cwd = process.cwd();
path = cwd;
}
assertPath(path);
// Skip empty entries
if (path.length === 0) {
continue;
}
resolvedPath = path + '/' + resolvedPath;
resolvedAbsolute = path.charCodeAt(0) === 47 /*/*/;
}
// At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path
resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute);
if (resolvedAbsolute) {
if (resolvedPath.length > 0)
return '/' + resolvedPath;
else
return '/';
} else if (resolvedPath.length > 0) {
return resolvedPath;
} else {
return '.';
}
},
normalize: function normalize(path) {
assertPath(path);
if (path.length === 0) return '.';
var isAbsolute = path.charCodeAt(0) === 47 /*/*/;
var trailingSeparator = path.charCodeAt(path.length - 1) === 47 /*/*/;
// Normalize the path
path = normalizeStringPosix(path, !isAbsolute);
if (path.length === 0 && !isAbsolute) path = '.';
if (path.length > 0 && trailingSeparator) path += '/';
if (isAbsolute) return '/' + path;
return path;
},
isAbsolute: function isAbsolute(path) {
assertPath(path);
return path.length > 0 && path.charCodeAt(0) === 47 /*/*/;
},
join: function join() {
if (arguments.length === 0)
return '.';
var joined;
for (var i = 0; i < arguments.length; ++i) {
var arg = arguments[i];
assertPath(arg);
if (arg.length > 0) {
if (joined === undefined)
joined = arg;
else
joined += '/' + arg;
}
}
if (joined === undefined)
return '.';
return posix.normalize(joined);
},
relative: function relative(from, to) {
assertPath(from);
assertPath(to);
if (from === to) return '';
from = posix.resolve(from);
to = posix.resolve(to);
if (from === to) return '';
// Trim any leading backslashes
var fromStart = 1;
for (; fromStart < from.length; ++fromStart) {
if (from.charCodeAt(fromStart) !== 47 /*/*/)
break;
}
var fromEnd = from.length;
var fromLen = fromEnd - fromStart;
// Trim any leading backslashes
var toStart = 1;
for (; toStart < to.length; ++toStart) {
if (to.charCodeAt(toStart) !== 47 /*/*/)
break;
}
var toEnd = to.length;
var toLen = toEnd - toStart;
// Compare paths to find the longest common path from root
var length = fromLen < toLen ? fromLen : toLen;
var lastCommonSep = -1;
var i = 0;
for (; i <= length; ++i) {
if (i === length) {
if (toLen > length) {
if (to.charCodeAt(toStart + i) === 47 /*/*/) {
// We get here if `from` is the exact base path for `to`.
// For example: from='/foo/bar'; to='/foo/bar/baz'
return to.slice(toStart + i + 1);
} else if (i === 0) {
// We get here if `from` is the root
// For example: from='/'; to='/foo'
return to.slice(toStart + i);
}
} else if (fromLen > length) {
if (from.charCodeAt(fromStart + i) === 47 /*/*/) {
// We get here if `to` is the exact base path for `from`.
// For example: from='/foo/bar/baz'; to='/foo/bar'
lastCommonSep = i;
} else if (i === 0) {
// We get here if `to` is the root.
// For example: from='/foo'; to='/'
lastCommonSep = 0;
}
}
break;
}
var fromCode = from.charCodeAt(fromStart + i);
var toCode = to.charCodeAt(toStart + i);
if (fromCode !== toCode)
break;
else if (fromCode === 47 /*/*/)
lastCommonSep = i;
}
var out = '';
// Generate the relative path based on the path difference between `to`
// and `from`
for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
if (i === fromEnd || from.charCodeAt(i) === 47 /*/*/) {
if (out.length === 0)
out += '..';
else
out += '/..';
}
}
// Lastly, append the rest of the destination (`to`) path that comes after
// the common path parts
if (out.length > 0)
return out + to.slice(toStart + lastCommonSep);
else {
toStart += lastCommonSep;
if (to.charCodeAt(toStart) === 47 /*/*/)
++toStart;
return to.slice(toStart);
}
},
_makeLong: function _makeLong(path) {
return path;
},
dirname: function dirname(path) {
assertPath(path);
if (path.length === 0) return '.';
var code = path.charCodeAt(0);
var hasRoot = code === 47 /*/*/;
var end = -1;
var matchedSlash = true;
for (var i = path.length - 1; i >= 1; --i) {
code = path.charCodeAt(i);
if (code === 47 /*/*/) {
if (!matchedSlash) {
end = i;
break;
}
} else {
// We saw the first non-path separator
matchedSlash = false;
}
}
if (end === -1) return hasRoot ? '/' : '.';
if (hasRoot && end === 1) return '//';
return path.slice(0, end);
},
basename: function basename(path, ext) {
if (ext !== undefined && typeof ext !== 'string') throw new TypeError('"ext" argument must be a string');
assertPath(path);
var start = 0;
var end = -1;
var matchedSlash = true;
var i;
if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
if (ext.length === path.length && ext === path) return '';
var extIdx = ext.length - 1;
var firstNonSlashEnd = -1;
for (i = path.length - 1; i >= 0; --i) {
var code = path.charCodeAt(i);
if (code === 47 /*/*/) {
// If we reached a path separator that was not part of a set of path
// separators at the end of the string, stop now
if (!matchedSlash) {
start = i + 1;
break;
}
} else {
if (firstNonSlashEnd === -1) {
// We saw the first non-path separator, remember this index in case
// we need it if the extension ends up not matching
matchedSlash = false;
firstNonSlashEnd = i + 1;
}
if (extIdx >= 0) {
// Try to match the explicit extension
if (code === ext.charCodeAt(extIdx)) {
if (--extIdx === -1) {
// We matched the extension, so mark this as the end of our path
// component
end = i;
}
} else {
// Extension does not match, so our result is the entire path
// component
extIdx = -1;
end = firstNonSlashEnd;
}
}
}
}
if (start === end) end = firstNonSlashEnd;else if (end === -1) end = path.length;
return path.slice(start, end);
} else {
for (i = path.length - 1; i >= 0; --i) {
if (path.charCodeAt(i) === 47 /*/*/) {
// If we reached a path separator that was not part of a set of path
// separators at the end of the string, stop now
if (!matchedSlash) {
start = i + 1;
break;
}
} else if (end === -1) {
// We saw the first non-path separator, mark this as the end of our
// path component
matchedSlash = false;
end = i + 1;
}
}
if (end === -1) return '';
return path.slice(start, end);
}
},
extname: function extname(path) {
assertPath(path);
var startDot = -1;
var startPart = 0;
var end = -1;
var matchedSlash = true;
// Track the state of characters (if any) we see before our first dot and
// after any path separator we find
var preDotState = 0;
for (var i = path.length - 1; i >= 0; --i) {
var code = path.charCodeAt(i);
if (code === 47 /*/*/) {
// If we reached a path separator that was not part of a set of path
// separators at the end of the string, stop now
if (!matchedSlash) {
startPart = i + 1;
break;
}
continue;
}
if (end === -1) {
// We saw the first non-path separator, mark this as the end of our
// extension
matchedSlash = false;
end = i + 1;
}
if (code === 46 /*.*/) {
// If this is our first dot, mark it as the start of our extension
if (startDot === -1)
startDot = i;
else if (preDotState !== 1)
preDotState = 1;
} else if (startDot !== -1) {
// We saw a non-dot and non-path separator before our dot, so we should
// have a good chance at having a non-empty extension
preDotState = -1;
}
}
if (startDot === -1 || end === -1 ||
// We saw a non-dot character immediately before the dot
preDotState === 0 ||
// The (right-most) trimmed path component is exactly '..'
preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
return '';
}
return path.slice(startDot, end);
},
format: function format(pathObject) {
if (pathObject === null || typeof pathObject !== 'object') {
throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof pathObject);
}
return _format('/', pathObject);
},
parse: function parse(path) {
assertPath(path);
var ret = { root: '', dir: '', base: '', ext: '', name: '' };
if (path.length === 0) return ret;
var code = path.charCodeAt(0);
var isAbsolute = code === 47 /*/*/;
var start;
if (isAbsolute) {
ret.root = '/';
start = 1;
} else {
start = 0;
}
var startDot = -1;
var startPart = 0;
var end = -1;
var matchedSlash = true;
var i = path.length - 1;
// Track the state of characters (if any) we see before our first dot and
// after any path separator we find
var preDotState = 0;
// Get non-dir info
for (; i >= start; --i) {
code = path.charCodeAt(i);
if (code === 47 /*/*/) {
// If we reached a path separator that was not part of a set of path
// separators at the end of the string, stop now
if (!matchedSlash) {
startPart = i + 1;
break;
}
continue;
}
if (end === -1) {
// We saw the first non-path separator, mark this as the end of our
// extension
matchedSlash = false;
end = i + 1;
}
if (code === 46 /*.*/) {
// If this is our first dot, mark it as the start of our extension
if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1;
} else if (startDot !== -1) {
// We saw a non-dot and non-path separator before our dot, so we should
// have a good chance at having a non-empty extension
preDotState = -1;
}
}
if (startDot === -1 || end === -1 ||
// We saw a non-dot character immediately before the dot
preDotState === 0 ||
// The (right-most) trimmed path component is exactly '..'
preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
if (end !== -1) {
if (startPart === 0 && isAbsolute) ret.base = ret.name = path.slice(1, end);else ret.base = ret.name = path.slice(startPart, end);
}
} else {
if (startPart === 0 && isAbsolute) {
ret.name = path.slice(1, startDot);
ret.base = path.slice(1, end);
} else {
ret.name = path.slice(startPart, startDot);
ret.base = path.slice(startPart, end);
}
ret.ext = path.slice(startDot, end);
}
if (startPart > 0) ret.dir = path.slice(0, startPart - 1);else if (isAbsolute) ret.dir = '/';
return ret;
},
sep: '/',
delimiter: ':',
win32: null,
posix: null
};
posix.posix = posix;
module.exports = posix;
}).call(this)}).call(this,require('_process'))
},{"_process":187}],186:[function(require,module,exports){
module.exports = length
function length (bytes) {
return Math.max(16384, 1 << Math.log2(bytes < 1024 ? 1 : bytes / 1024) + 0.5 | 0)
}
},{}],187:[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; };
},{}],188:[function(require,module,exports){
(function (process){(function (){
var once = require('once')
var eos = require('end-of-stream')
var fs = require('fs') // we only need fs to get the ReadStream and WriteStream prototypes
var noop = function () {}
var ancient = /^v?\.0/.test(process.version)
var isFn = function (fn) {
return typeof fn === 'function'
}
var isFS = function (stream) {
if (!ancient) return false // newer node version do not need to care about fs is a special way
if (!fs) return false // browser
return (stream instanceof (fs.ReadStream || noop) || stream instanceof (fs.WriteStream || noop)) && isFn(stream.close)
}
var isRequest = function (stream) {
return stream.setHeader && isFn(stream.abort)
}
var destroyer = function (stream, reading, writing, callback) {
callback = once(callback)
var closed = false
stream.on('close', function () {
closed = true
})
eos(stream, {readable: reading, writable: writing}, function (err) {
if (err) return callback(err)
closed = true
callback()
})
var destroyed = false
return function (err) {
if (closed) return
if (destroyed) return
destroyed = true
if (isFS(stream)) return stream.close(noop) // use close for fs streams to avoid fd leaks
if (isRequest(stream)) return stream.abort() // request.destroy just do .end - .abort is what we want
if (isFn(stream.destroy)) return stream.destroy()
callback(err || new Error('stream was destroyed'))
}
}
var call = function (fn) {
fn()
}
var pipe = function (from, to) {
return from.pipe(to)
}
var pump = function () {
var streams = Array.prototype.slice.call(arguments)
var callback = isFn(streams[streams.length - 1] || noop) && streams.pop() || noop
if (Array.isArray(streams[0])) streams = streams[0]
if (streams.length < 2) throw new Error('pump requires two streams per minimum')
var error
var destroys = streams.map(function (stream, i) {
var reading = i < streams.length - 1
var writing = i > 0
return destroyer(stream, reading, writing, function (err) {
if (!error) error = err
if (err) destroys.forEach(call)
if (reading) return
destroys.forEach(call)
callback(error)
})
})
return streams.reduce(pipe)
}
module.exports = pump
}).call(this)}).call(this,require('_process'))
},{"_process":187,"end-of-stream":96,"fs":55,"once":183}],189:[function(require,module,exports){
(function (global){(function (){
/*! 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)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],190:[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]';
};
},{}],191:[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;
};
},{}],192:[function(require,module,exports){
'use strict';
exports.decode = exports.parse = require('./decode');
exports.encode = exports.stringify = require('./encode');
},{"./decode":190,"./encode":191}],193:[function(require,module,exports){
/*! queue-microtask. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
let promise
module.exports = typeof queueMicrotask === 'function'
? queueMicrotask.bind(globalThis)
// reuse resolved promise, and allocate it lazily
: cb => (promise || (promise = Promise.resolve()))
.then(cb)
.catch(err => setTimeout(() => { throw err }, 0))
},{}],194:[function(require,module,exports){
var iterate = function (list) {
var offset = 0
return function () {
if (offset === list.length) return null
var len = list.length - offset
var i = (Math.random() * len) | 0
var el = list[offset + i]
var tmp = list[offset]
list[offset] = el
list[offset + i] = tmp
offset++
return el
}
}
module.exports = iterate
},{}],195:[function(require,module,exports){
(function (process,global){(function (){
'use strict'
// limit of Crypto.getRandomValues()
// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
var MAX_BYTES = 65536
// Node supports requesting up to this number of bytes
// https://github.com/nodejs/node/blob/master/lib/internal/crypto/random.js#L48
var MAX_UINT32 = 4294967295
function oldBrowser () {
throw new Error('Secure random number generation is not supported by this browser.\nUse Chrome, Firefox or Internet Explorer 11')
}
var Buffer = require('safe-buffer').Buffer
var crypto = global.crypto || global.msCrypto
if (crypto && crypto.getRandomValues) {
module.exports = randomBytes
} else {
module.exports = oldBrowser
}
function randomBytes (size, cb) {
// phantomjs needs to throw
if (size > MAX_UINT32) throw new RangeError('requested too many random bytes')
var bytes = Buffer.allocUnsafe(size)
if (size > 0) { // getRandomValues fails on IE if size == 0
if (size > MAX_BYTES) { // this is the max bytes crypto.getRandomValues
// can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues
for (var generated = 0; generated < size; generated += MAX_BYTES) {
// buffer.slice automatically checks if the end is past the end of
// the buffer so we don't have to here
crypto.getRandomValues(bytes.slice(generated, generated + MAX_BYTES))
}
} else {
crypto.getRandomValues(bytes)
}
}
if (typeof cb === 'function') {
return process.nextTick(function () {
cb(null, bytes)
})
}
return bytes
}
}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"_process":187,"safe-buffer":220}],196:[function(require,module,exports){
/*
Instance of writable stream.
call .get(length) or .discard(length) to get a stream (relative to the last end)
emits 'stalled' once everything is written
*/
const { Writable, PassThrough } = require('readable-stream')
class RangeSliceStream extends Writable {
constructor (offset, opts = {}) {
super(opts)
this.destroyed = false
this._queue = []
this._position = offset || 0
this._cb = null
this._buffer = null
this._out = null
}
_write (chunk, encoding, cb) {
let drained = true
while (true) {
if (this.destroyed) {
return
}
// Wait for more queue entries
if (this._queue.length === 0) {
this._buffer = chunk
this._cb = cb
return
}
this._buffer = null
var currRange = this._queue[0]
// Relative to the start of chunk, what data do we need?
const writeStart = Math.max(currRange.start - this._position, 0)
const writeEnd = currRange.end - this._position
// Check if we need to throw it all away
if (writeStart >= chunk.length) {
this._position += chunk.length
return cb(null)
}
// Check if we need to use it all
let toWrite
if (writeEnd > chunk.length) {
this._position += chunk.length
if (writeStart === 0) {
toWrite = chunk
} else {
toWrite = chunk.slice(writeStart)
}
drained = currRange.stream.write(toWrite) && drained
break
}
this._position += writeEnd
toWrite = (writeStart === 0 && writeEnd === chunk.length)
? chunk
: chunk.slice(writeStart, writeEnd)
drained = currRange.stream.write(toWrite) && drained
if (currRange.last) {
currRange.stream.end()
}
chunk = chunk.slice(writeEnd)
this._queue.shift()
}
if (drained) {
cb(null)
} else {
currRange.stream.once('drain', cb.bind(null, null))
}
}
slice (ranges) {
if (this.destroyed) return null
if (!Array.isArray(ranges)) ranges = [ranges]
const str = new PassThrough()
ranges.forEach((range, i) => {
this._queue.push({
start: range.start,
end: range.end,
stream: str,
last: i === ranges.length - 1
})
})
if (this._buffer) {
this._write(this._buffer, null, this._cb)
}
return str
}
destroy (err) {
if (this.destroyed) return
this.destroyed = true
if (err) this.emit('error', err)
}
}
module.exports = RangeSliceStream
},{"readable-stream":211}],197:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],198:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":200,"./_stream_writable":202,"_process":187,"dup":17,"inherits":119}],199:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":201,"dup":18,"inherits":119}],200:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":197,"./_stream_duplex":198,"./internal/streams/async_iterator":203,"./internal/streams/buffer_list":204,"./internal/streams/destroy":205,"./internal/streams/from":207,"./internal/streams/state":209,"./internal/streams/stream":210,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],201:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":197,"./_stream_duplex":198,"dup":20,"inherits":119}],202:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":197,"./_stream_duplex":198,"./internal/streams/destroy":205,"./internal/streams/state":209,"./internal/streams/stream":210,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],203:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":206,"_process":187,"dup":22}],204:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],205:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],206:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":197,"dup":25}],207:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],208:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":197,"./end-of-stream":206,"dup":27}],209:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":197,"dup":28}],210:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],211:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":198,"./lib/_stream_passthrough.js":199,"./lib/_stream_readable.js":200,"./lib/_stream_transform.js":201,"./lib/_stream_writable.js":202,"./lib/internal/streams/end-of-stream.js":206,"./lib/internal/streams/pipeline.js":208,"dup":30}],212:[function(require,module,exports){
/*! render-media. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
exports.render = render
exports.append = append
exports.mime = require('./lib/mime.json')
var debug = require('debug')('render-media')
var isAscii = require('is-ascii')
var MediaElementWrapper = require('mediasource')
var path = require('path')
var streamToBlobURL = require('stream-to-blob-url')
var VideoStream = require('videostream')
// Note: Everything listed in VIDEOSTREAM_EXTS should also appear in either
// MEDIASOURCE_VIDEO_EXTS or MEDIASOURCE_AUDIO_EXTS.
var VIDEOSTREAM_EXTS = [
'.m4a',
'.m4b',
'.m4p',
'.m4v',
'.mp4'
]
var MEDIASOURCE_VIDEO_EXTS = [
'.m4v',
'.mkv',
'.mp4',
'.webm'
]
var MEDIASOURCE_AUDIO_EXTS = [
'.m4a',
'.m4b',
'.m4p',
'.mp3'
]
var MEDIASOURCE_EXTS = [].concat(
MEDIASOURCE_VIDEO_EXTS,
MEDIASOURCE_AUDIO_EXTS
)
var VIDEO_EXTS = [
'.mov',
'.ogv'
]
var AUDIO_EXTS = [
'.aac',
'.oga',
'.ogg',
'.wav',
'.flac'
]
var IMAGE_EXTS = [
'.bmp',
'.gif',
'.jpeg',
'.jpg',
'.png',
'.svg'
]
var IFRAME_EXTS = [
'.css',
'.html',
'.js',
'.md',
'.pdf',
'.srt',
'.txt'
]
// Maximum file length for which the Blob URL strategy will be attempted
// See: https://github.com/feross/render-media/issues/18
var MAX_BLOB_LENGTH = 200 * 1000 * 1000 // 200 MB
var MediaSource = typeof window !== 'undefined' && window.MediaSource
function render (file, elem, opts, cb) {
if (typeof opts === 'function') {
cb = opts
opts = {}
}
if (!opts) opts = {}
if (!cb) cb = function () {}
validateFile(file)
parseOpts(opts)
if (typeof elem === 'string') elem = document.querySelector(elem)
renderMedia(file, function (tagName) {
if (elem.nodeName !== tagName.toUpperCase()) {
var extname = path.extname(file.name).toLowerCase()
throw new Error(
'Cannot render "' + extname + '" inside a "' +
elem.nodeName.toLowerCase() + '" element, expected "' + tagName + '"'
)
}
if (tagName === 'video' || tagName === 'audio') setMediaOpts(elem, opts)
return elem
}, opts, cb)
}
function append (file, rootElem, opts, cb) {
if (typeof opts === 'function') {
cb = opts
opts = {}
}
if (!opts) opts = {}
if (!cb) cb = function () {}
validateFile(file)
parseOpts(opts)
if (typeof rootElem === 'string') rootElem = document.querySelector(rootElem)
if (rootElem && (rootElem.nodeName === 'VIDEO' || rootElem.nodeName === 'AUDIO')) {
throw new Error(
'Invalid video/audio node argument. Argument must be root element that ' +
'video/audio tag will be appended to.'
)
}
renderMedia(file, getElem, opts, done)
function getElem (tagName) {
if (tagName === 'video' || tagName === 'audio') return createMedia(tagName)
else return createElem(tagName)
}
function createMedia (tagName) {
var elem = createElem(tagName)
setMediaOpts(elem, opts)
rootElem.appendChild(elem)
return elem
}
function createElem (tagName) {
var elem = document.createElement(tagName)
rootElem.appendChild(elem)
return elem
}
function done (err, elem) {
if (err && elem) elem.remove()
cb(err, elem)
}
}
function renderMedia (file, getElem, opts, cb) {
var extname = path.extname(file.name).toLowerCase()
var currentTime = 0
var elem
if (MEDIASOURCE_EXTS.indexOf(extname) >= 0) {
renderMediaSource()
} else if (VIDEO_EXTS.indexOf(extname) >= 0) {
renderMediaElement('video')
} else if (AUDIO_EXTS.indexOf(extname) >= 0) {
renderMediaElement('audio')
} else if (IMAGE_EXTS.indexOf(extname) >= 0) {
renderImage()
} else if (IFRAME_EXTS.indexOf(extname) >= 0) {
renderIframe()
} else {
tryRenderIframe()
}
function renderMediaSource () {
var tagName = MEDIASOURCE_VIDEO_EXTS.indexOf(extname) >= 0 ? 'video' : 'audio'
if (MediaSource) {
if (VIDEOSTREAM_EXTS.indexOf(extname) >= 0) {
useVideostream()
} else {
useMediaSource()
}
} else {
useBlobURL()
}
function useVideostream () {
debug('Use `videostream` package for ' + file.name)
prepareElem()
elem.addEventListener('error', fallbackToMediaSource)
elem.addEventListener('loadstart', onLoadStart)
elem.addEventListener('canplay', onCanPlay)
new VideoStream(file, elem) /* eslint-disable-line no-new */
}
function useMediaSource () {
debug('Use MediaSource API for ' + file.name)
prepareElem()
elem.addEventListener('error', fallbackToBlobURL)
elem.addEventListener('loadstart', onLoadStart)
elem.addEventListener('canplay', onCanPlay)
var wrapper = new MediaElementWrapper(elem)
var writable = wrapper.createWriteStream(getCodec(file.name))
file.createReadStream().pipe(writable)
if (currentTime) elem.currentTime = currentTime
}
function useBlobURL () {
debug('Use Blob URL for ' + file.name)
prepareElem()
elem.addEventListener('error', fatalError)
elem.addEventListener('loadstart', onLoadStart)
elem.addEventListener('canplay', onCanPlay)
getBlobURL(file, function (err, url) {
if (err) return fatalError(err)
elem.src = url
if (currentTime) elem.currentTime = currentTime
})
}
function fallbackToMediaSource (err) {
debug('videostream error: fallback to MediaSource API: %o', err.message || err)
elem.removeEventListener('error', fallbackToMediaSource)
elem.removeEventListener('canplay', onCanPlay)
useMediaSource()
}
function fallbackToBlobURL (err) {
debug('MediaSource API error: fallback to Blob URL: %o', err.message || err)
if (!checkBlobLength()) return
elem.removeEventListener('error', fallbackToBlobURL)
elem.removeEventListener('canplay', onCanPlay)
useBlobURL()
}
function prepareElem () {
if (!elem) {
elem = getElem(tagName)
elem.addEventListener('progress', function () {
currentTime = elem.currentTime
})
}
}
}
function checkBlobLength () {
if (typeof file.length === 'number' && file.length > opts.maxBlobLength) {
debug(
'File length too large for Blob URL approach: %d (max: %d)',
file.length, opts.maxBlobLength
)
fatalError(new Error(
'File length too large for Blob URL approach: ' + file.length +
' (max: ' + opts.maxBlobLength + ')'
))
return false
}
return true
}
function renderMediaElement (type) {
if (!checkBlobLength()) return
elem = getElem(type)
getBlobURL(file, function (err, url) {
if (err) return fatalError(err)
elem.addEventListener('error', fatalError)
elem.addEventListener('loadstart', onLoadStart)
elem.addEventListener('canplay', onCanPlay)
elem.src = url
})
}
function onLoadStart () {
elem.removeEventListener('loadstart', onLoadStart)
if (opts.autoplay) elem.play()
}
function onCanPlay () {
elem.removeEventListener('canplay', onCanPlay)
cb(null, elem)
}
function renderImage () {
elem = getElem('img')
getBlobURL(file, function (err, url) {
if (err) return fatalError(err)
elem.src = url
elem.alt = file.name
cb(null, elem)
})
}
function renderIframe () {
getBlobURL(file, function (err, url) {
if (err) return fatalError(err)
if (extname !== '.pdf') {
// Render iframe
elem = getElem('iframe')
elem.sandbox = 'allow-forms allow-scripts'
elem.src = url
} else {
// Render .pdf
elem = getElem('object')
// Firefox-only: `typemustmatch` keeps the embedded file from running unless
// its content type matches the specified `type` attribute
elem.setAttribute('typemustmatch', true)
elem.setAttribute('type', 'application/pdf')
elem.setAttribute('data', url)
}
cb(null, elem)
})
}
function tryRenderIframe () {
debug('Unknown file extension "%s" - will attempt to render into iframe', extname)
var str = ''
file.createReadStream({ start: 0, end: 1000 })
.setEncoding('utf8')
.on('data', function (chunk) {
str += chunk
})
.on('end', done)
.on('error', cb)
function done () {
if (isAscii(str)) {
debug('File extension "%s" appears ascii, so will render.', extname)
renderIframe()
} else {
debug('File extension "%s" appears non-ascii, will not render.', extname)
cb(new Error('Unsupported file type "' + extname + '": Cannot append to DOM'))
}
}
}
function fatalError (err) {
err.message = 'Error rendering file "' + file.name + '": ' + err.message
debug(err.message)
cb(err)
}
}
function getBlobURL (file, cb) {
var extname = path.extname(file.name).toLowerCase()
streamToBlobURL(file.createReadStream(), exports.mime[extname])
.then(
blobUrl => cb(null, blobUrl),
err => cb(err)
)
}
function validateFile (file) {
if (file == null) {
throw new Error('file cannot be null or undefined')
}
if (typeof file.name !== 'string') {
throw new Error('missing or invalid file.name property')
}
if (typeof file.createReadStream !== 'function') {
throw new Error('missing or invalid file.createReadStream property')
}
}
function getCodec (name) {
var extname = path.extname(name).toLowerCase()
return {
'.m4a': 'audio/mp4; codecs="mp4a.40.5"',
'.m4b': 'audio/mp4; codecs="mp4a.40.5"',
'.m4p': 'audio/mp4; codecs="mp4a.40.5"',
'.m4v': 'video/mp4; codecs="avc1.640029, mp4a.40.5"',
'.mkv': 'video/webm; codecs="avc1.640029, mp4a.40.5"',
'.mp3': 'audio/mpeg',
'.mp4': 'video/mp4; codecs="avc1.640029, mp4a.40.5"',
'.webm': 'video/webm; codecs="vorbis, vp8"'
}[extname]
}
function parseOpts (opts) {
if (opts.autoplay == null) opts.autoplay = false
if (opts.muted == null) opts.muted = false
if (opts.controls == null) opts.controls = true
if (opts.maxBlobLength == null) opts.maxBlobLength = MAX_BLOB_LENGTH
}
function setMediaOpts (elem, opts) {
elem.autoplay = !!opts.autoplay
elem.muted = !!opts.muted
elem.controls = !!opts.controls
}
},{"./lib/mime.json":213,"debug":214,"is-ascii":120,"mediasource":125,"path":185,"stream-to-blob-url":283,"videostream":308}],213:[function(require,module,exports){
module.exports={
".3gp": "video/3gpp",
".aac": "audio/aac",
".aif": "audio/x-aiff",
".aiff": "audio/x-aiff",
".atom": "application/atom+xml",
".avi": "video/x-msvideo",
".bmp": "image/bmp",
".bz2": "application/x-bzip2",
".conf": "text/plain",
".css": "text/css",
".csv": "text/plain",
".diff": "text/x-diff",
".doc": "application/msword",
".flv": "video/x-flv",
".gif": "image/gif",
".gz": "application/x-gzip",
".htm": "text/html",
".html": "text/html",
".ico": "image/vnd.microsoft.icon",
".ics": "text/calendar",
".iso": "application/octet-stream",
".jar": "application/java-archive",
".jpeg": "image/jpeg",
".jpg": "image/jpeg",
".js": "application/javascript",
".json": "application/json",
".less": "text/css",
".log": "text/plain",
".m3u": "audio/x-mpegurl",
".m4a": "audio/x-m4a",
".m4b": "audio/mp4",
".m4p": "audio/mp4",
".m4v": "video/x-m4v",
".manifest": "text/cache-manifest",
".markdown": "text/x-markdown",
".mathml": "application/mathml+xml",
".md": "text/x-markdown",
".mid": "audio/midi",
".midi": "audio/midi",
".mov": "video/quicktime",
".mp3": "audio/mpeg",
".mp4": "video/mp4",
".mp4v": "video/mp4",
".mpeg": "video/mpeg",
".mpg": "video/mpeg",
".odp": "application/vnd.oasis.opendocument.presentation",
".ods": "application/vnd.oasis.opendocument.spreadsheet",
".odt": "application/vnd.oasis.opendocument.text",
".oga": "audio/ogg",
".ogg": "application/ogg",
".pdf": "application/pdf",
".png": "image/png",
".pps": "application/vnd.ms-powerpoint",
".ppt": "application/vnd.ms-powerpoint",
".ps": "application/postscript",
".psd": "image/vnd.adobe.photoshop",
".qt": "video/quicktime",
".rar": "application/x-rar-compressed",
".rdf": "application/rdf+xml",
".rss": "application/rss+xml",
".rtf": "application/rtf",
".svg": "image/svg+xml",
".svgz": "image/svg+xml",
".swf": "application/x-shockwave-flash",
".tar": "application/x-tar",
".tbz": "application/x-bzip-compressed-tar",
".text": "text/plain",
".tif": "image/tiff",
".tiff": "image/tiff",
".torrent": "application/x-bittorrent",
".ttf": "application/x-font-ttf",
".txt": "text/plain",
".wav": "audio/wav",
".webm": "video/webm",
".wma": "audio/x-ms-wma",
".wmv": "video/x-ms-wmv",
".xls": "application/vnd.ms-excel",
".xml": "application/xml",
".yaml": "text/yaml",
".yml": "text/yaml",
".zip": "application/zip"
}
},{}],214:[function(require,module,exports){
arguments[4][13][0].apply(exports,arguments)
},{"./common":215,"_process":187,"dup":13}],215:[function(require,module,exports){
arguments[4][14][0].apply(exports,arguments)
},{"dup":14,"ms":216}],216:[function(require,module,exports){
arguments[4][15][0].apply(exports,arguments)
},{"dup":15}],217:[function(require,module,exports){
(function (process){(function (){
/*! run-parallel-limit. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
module.exports = runParallelLimit
function runParallelLimit (tasks, limit, cb) {
if (typeof limit !== 'number') throw new Error('second argument must be a Number')
var results, len, pending, keys, isErrored
var isSync = true
if (Array.isArray(tasks)) {
results = []
pending = len = tasks.length
} else {
keys = Object.keys(tasks)
results = {}
pending = len = keys.length
}
function done (err) {
function end () {
if (cb) cb(err, results)
cb = null
}
if (isSync) process.nextTick(end)
else end()
}
function each (i, err, result) {
results[i] = result
if (err) isErrored = true
if (--pending === 0 || err) {
done(err)
} else if (!isErrored && next < len) {
var key
if (keys) {
key = keys[next]
next += 1
tasks[key](function (err, result) { each(key, err, result) })
} else {
key = next
next += 1
tasks[key](function (err, result) { each(key, err, result) })
}
}
}
var next = limit
if (!pending) {
// empty
done(null)
} else if (keys) {
// object
keys.some(function (key, i) {
tasks[key](function (err, result) { each(key, err, result) })
if (i === limit - 1) return true // early return
})
} else {
// array
tasks.some(function (task, i) {
task(function (err, result) { each(i, err, result) })
if (i === limit - 1) return true // early return
})
}
isSync = false
}
}).call(this)}).call(this,require('_process'))
},{"_process":187}],218:[function(require,module,exports){
(function (process){(function (){
/*! run-parallel. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
module.exports = runParallel
function runParallel (tasks, cb) {
var results, pending, keys
var isSync = true
if (Array.isArray(tasks)) {
results = []
pending = tasks.length
} else {
keys = Object.keys(tasks)
results = {}
pending = keys.length
}
function done (err) {
function end () {
if (cb) cb(err, results)
cb = null
}
if (isSync) process.nextTick(end)
else end()
}
function each (i, err, result) {
results[i] = result
if (--pending === 0 || err) {
done(err)
}
}
if (!pending) {
// empty
done(null)
} else if (keys) {
// object
keys.forEach(function (key) {
tasks[key](function (err, result) { each(key, err, result) })
})
} else {
// array
tasks.forEach(function (task, i) {
task(function (err, result) { each(i, err, result) })
})
}
isSync = false
}
}).call(this)}).call(this,require('_process'))
},{"_process":187}],219:[function(require,module,exports){
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["Rusha"] = factory();
else
root["Rusha"] = factory();
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 3);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/* eslint-env commonjs, browser */
var RushaCore = __webpack_require__(5);
var _require = __webpack_require__(1),
toHex = _require.toHex,
ceilHeapSize = _require.ceilHeapSize;
var conv = __webpack_require__(6);
// Calculate the length of buffer that the sha1 routine uses
// including the padding.
var padlen = function (len) {
for (len += 9; len % 64 > 0; len += 1) {}
return len;
};
var padZeroes = function (bin, len) {
var h8 = new Uint8Array(bin.buffer);
var om = len % 4,
align = len - om;
switch (om) {
case 0:
h8[align + 3] = 0;
case 1:
h8[align + 2] = 0;
case 2:
h8[align + 1] = 0;
case 3:
h8[align + 0] = 0;
}
for (var i = (len >> 2) + 1; i < bin.length; i++) {
bin[i] = 0;
}
};
var padData = function (bin, chunkLen, msgLen) {
bin[chunkLen >> 2] |= 0x80 << 24 - (chunkLen % 4 << 3);
// To support msgLen >= 2 GiB, use a float division when computing the
// high 32-bits of the big-endian message length in bits.
bin[((chunkLen >> 2) + 2 & ~0x0f) + 14] = msgLen / (1 << 29) | 0;
bin[((chunkLen >> 2) + 2 & ~0x0f) + 15] = msgLen << 3;
};
var getRawDigest = function (heap, padMaxChunkLen) {
var io = new Int32Array(heap, padMaxChunkLen + 320, 5);
var out = new Int32Array(5);
var arr = new DataView(out.buffer);
arr.setInt32(0, io[0], false);
arr.setInt32(4, io[1], false);
arr.setInt32(8, io[2], false);
arr.setInt32(12, io[3], false);
arr.setInt32(16, io[4], false);
return out;
};
var Rusha = function () {
function Rusha(chunkSize) {
_classCallCheck(this, Rusha);
chunkSize = chunkSize || 64 * 1024;
if (chunkSize % 64 > 0) {
throw new Error('Chunk size must be a multiple of 128 bit');
}
this._offset = 0;
this._maxChunkLen = chunkSize;
this._padMaxChunkLen = padlen(chunkSize);
// The size of the heap is the sum of:
// 1. The padded input message size
// 2. The extended space the algorithm needs (320 byte)
// 3. The 160 bit state the algoritm uses
this._heap = new ArrayBuffer(ceilHeapSize(this._padMaxChunkLen + 320 + 20));
this._h32 = new Int32Array(this._heap);
this._h8 = new Int8Array(this._heap);
this._core = new RushaCore({ Int32Array: Int32Array }, {}, this._heap);
}
Rusha.prototype._initState = function _initState(heap, padMsgLen) {
this._offset = 0;
var io = new Int32Array(heap, padMsgLen + 320, 5);
io[0] = 1732584193;
io[1] = -271733879;
io[2] = -1732584194;
io[3] = 271733878;
io[4] = -1009589776;
};
Rusha.prototype._padChunk = function _padChunk(chunkLen, msgLen) {
var padChunkLen = padlen(chunkLen);
var view = new Int32Array(this._heap, 0, padChunkLen >> 2);
padZeroes(view, chunkLen);
padData(view, chunkLen, msgLen);
return padChunkLen;
};
Rusha.prototype._write = function _write(data, chunkOffset, chunkLen, off) {
conv(data, this._h8, this._h32, chunkOffset, chunkLen, off || 0);
};
Rusha.prototype._coreCall = function _coreCall(data, chunkOffset, chunkLen, msgLen, finalize) {
var padChunkLen = chunkLen;
this._write(data, chunkOffset, chunkLen);
if (finalize) {
padChunkLen = this._padChunk(chunkLen, msgLen);
}
this._core.hash(padChunkLen, this._padMaxChunkLen);
};
Rusha.prototype.rawDigest = function rawDigest(str) {
var msgLen = str.byteLength || str.length || str.size || 0;
this._initState(this._heap, this._padMaxChunkLen);
var chunkOffset = 0,
chunkLen = this._maxChunkLen;
for (chunkOffset = 0; msgLen > chunkOffset + chunkLen; chunkOffset += chunkLen) {
this._coreCall(str, chunkOffset, chunkLen, msgLen, false);
}
this._coreCall(str, chunkOffset, msgLen - chunkOffset, msgLen, true);
return getRawDigest(this._heap, this._padMaxChunkLen);
};
Rusha.prototype.digest = function digest(str) {
return toHex(this.rawDigest(str).buffer);
};
Rusha.prototype.digestFromString = function digestFromString(str) {
return this.digest(str);
};
Rusha.prototype.digestFromBuffer = function digestFromBuffer(str) {
return this.digest(str);
};
Rusha.prototype.digestFromArrayBuffer = function digestFromArrayBuffer(str) {
return this.digest(str);
};
Rusha.prototype.resetState = function resetState() {
this._initState(this._heap, this._padMaxChunkLen);
return this;
};
Rusha.prototype.append = function append(chunk) {
var chunkOffset = 0;
var chunkLen = chunk.byteLength || chunk.length || chunk.size || 0;
var turnOffset = this._offset % this._maxChunkLen;
var inputLen = void 0;
this._offset += chunkLen;
while (chunkOffset < chunkLen) {
inputLen = Math.min(chunkLen - chunkOffset, this._maxChunkLen - turnOffset);
this._write(chunk, chunkOffset, inputLen, turnOffset);
turnOffset += inputLen;
chunkOffset += inputLen;
if (turnOffset === this._maxChunkLen) {
this._core.hash(this._maxChunkLen, this._padMaxChunkLen);
turnOffset = 0;
}
}
return this;
};
Rusha.prototype.getState = function getState() {
var turnOffset = this._offset % this._maxChunkLen;
var heap = void 0;
if (!turnOffset) {
var io = new Int32Array(this._heap, this._padMaxChunkLen + 320, 5);
heap = io.buffer.slice(io.byteOffset, io.byteOffset + io.byteLength);
} else {
heap = this._heap.slice(0);
}
return {
offset: this._offset,
heap: heap
};
};
Rusha.prototype.setState = function setState(state) {
this._offset = state.offset;
if (state.heap.byteLength === 20) {
var io = new Int32Array(this._heap, this._padMaxChunkLen + 320, 5);
io.set(new Int32Array(state.heap));
} else {
this._h32.set(new Int32Array(state.heap));
}
return this;
};
Rusha.prototype.rawEnd = function rawEnd() {
var msgLen = this._offset;
var chunkLen = msgLen % this._maxChunkLen;
var padChunkLen = this._padChunk(chunkLen, msgLen);
this._core.hash(padChunkLen, this._padMaxChunkLen);
var result = getRawDigest(this._heap, this._padMaxChunkLen);
this._initState(this._heap, this._padMaxChunkLen);
return result;
};
Rusha.prototype.end = function end() {
return toHex(this.rawEnd().buffer);
};
return Rusha;
}();
module.exports = Rusha;
module.exports._core = RushaCore;
/***/ }),
/* 1 */
/***/ (function(module, exports) {
/* eslint-env commonjs, browser */
//
// toHex
//
var precomputedHex = new Array(256);
for (var i = 0; i < 256; i++) {
precomputedHex[i] = (i < 0x10 ? '0' : '') + i.toString(16);
}
module.exports.toHex = function (arrayBuffer) {
var binarray = new Uint8Array(arrayBuffer);
var res = new Array(arrayBuffer.byteLength);
for (var _i = 0; _i < res.length; _i++) {
res[_i] = precomputedHex[binarray[_i]];
}
return res.join('');
};
//
// ceilHeapSize
//
module.exports.ceilHeapSize = function (v) {
// The asm.js spec says:
// The heap object's byteLength must be either
// 2^n for n in [12, 24) or 2^24 * n for n ≥ 1.
// Also, byteLengths smaller than 2^16 are deprecated.
var p = 0;
// If v is smaller than 2^16, the smallest possible solution
// is 2^16.
if (v <= 65536) return 65536;
// If v < 2^24, we round up to 2^n,
// otherwise we round up to 2^24 * n.
if (v < 16777216) {
for (p = 1; p < v; p = p << 1) {}
} else {
for (p = 16777216; p < v; p += 16777216) {}
}
return p;
};
//
// isDedicatedWorkerScope
//
module.exports.isDedicatedWorkerScope = function (self) {
var isRunningInWorker = 'WorkerGlobalScope' in self && self instanceof self.WorkerGlobalScope;
var isRunningInSharedWorker = 'SharedWorkerGlobalScope' in self && self instanceof self.SharedWorkerGlobalScope;
var isRunningInServiceWorker = 'ServiceWorkerGlobalScope' in self && self instanceof self.ServiceWorkerGlobalScope;
// Detects whether we run inside a dedicated worker or not.
//
// We can't just check for `DedicatedWorkerGlobalScope`, since IE11
// has a bug where it only supports `WorkerGlobalScope`.
//
// Therefore, we consider us as running inside a dedicated worker
// when we are running inside a worker, but not in a shared or service worker.
//
// When new types of workers are introduced, we will need to adjust this code.
return isRunningInWorker && !isRunningInSharedWorker && !isRunningInServiceWorker;
};
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
/* eslint-env commonjs, worker */
module.exports = function () {
var Rusha = __webpack_require__(0);
var hashData = function (hasher, data, cb) {
try {
return cb(null, hasher.digest(data));
} catch (e) {
return cb(e);
}
};
var hashFile = function (hasher, readTotal, blockSize, file, cb) {
var reader = new self.FileReader();
reader.onloadend = function onloadend() {
if (reader.error) {
return cb(reader.error);
}
var buffer = reader.result;
readTotal += reader.result.byteLength;
try {
hasher.append(buffer);
} catch (e) {
cb(e);
return;
}
if (readTotal < file.size) {
hashFile(hasher, readTotal, blockSize, file, cb);
} else {
cb(null, hasher.end());
}
};
reader.readAsArrayBuffer(file.slice(readTotal, readTotal + blockSize));
};
var workerBehaviourEnabled = true;
self.onmessage = function (event) {
if (!workerBehaviourEnabled) {
return;
}
var data = event.data.data,
file = event.data.file,
id = event.data.id;
if (typeof id === 'undefined') return;
if (!file && !data) return;
var blockSize = event.data.blockSize || 4 * 1024 * 1024;
var hasher = new Rusha(blockSize);
hasher.resetState();
var done = function (err, hash) {
if (!err) {
self.postMessage({ id: id, hash: hash });
} else {
self.postMessage({ id: id, error: err.name });
}
};
if (data) hashData(hasher, data, done);
if (file) hashFile(hasher, 0, blockSize, file, done);
};
return function () {
workerBehaviourEnabled = false;
};
};
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
/* eslint-env commonjs, browser */
var work = __webpack_require__(4);
var Rusha = __webpack_require__(0);
var createHash = __webpack_require__(7);
var runWorker = __webpack_require__(2);
var _require = __webpack_require__(1),
isDedicatedWorkerScope = _require.isDedicatedWorkerScope;
var isRunningInDedicatedWorker = typeof self !== 'undefined' && isDedicatedWorkerScope(self);
Rusha.disableWorkerBehaviour = isRunningInDedicatedWorker ? runWorker() : function () {};
Rusha.createWorker = function () {
var worker = work(/*require.resolve*/(2));
var terminate = worker.terminate;
worker.terminate = function () {
URL.revokeObjectURL(worker.objectURL);
terminate.call(worker);
};
return worker;
};
Rusha.createHash = createHash;
module.exports = Rusha;
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
function webpackBootstrapFunc (modules) {
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // identity function for calling harmony imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/";
/******/ // on error function for async loading
/******/ __webpack_require__.oe = function(err) { console.error(err); throw err; };
var f = __webpack_require__(__webpack_require__.s = ENTRY_MODULE)
return f.default || f // try to call default if defined to also support babel esmodule exports
}
var moduleNameReqExp = '[\\.|\\-|\\+|\\w|\/|@]+'
var dependencyRegExp = '\\((\/\\*.*?\\*\/)?\s?.*?(' + moduleNameReqExp + ').*?\\)' // additional chars when output.pathinfo is true
// http://stackoverflow.com/a/2593661/130442
function quoteRegExp (str) {
return (str + '').replace(/[.?*+^$[\]\\(){}|-]/g, '\\$&')
}
function getModuleDependencies (sources, module, queueName) {
var retval = {}
retval[queueName] = []
var fnString = module.toString()
var wrapperSignature = fnString.match(/^function\s?\(\w+,\s*\w+,\s*(\w+)\)/)
if (!wrapperSignature) return retval
var webpackRequireName = wrapperSignature[1]
// main bundle deps
var re = new RegExp('(\\\\n|\\W)' + quoteRegExp(webpackRequireName) + dependencyRegExp, 'g')
var match
while ((match = re.exec(fnString))) {
if (match[3] === 'dll-reference') continue
retval[queueName].push(match[3])
}
// dll deps
re = new RegExp('\\(' + quoteRegExp(webpackRequireName) + '\\("(dll-reference\\s(' + moduleNameReqExp + '))"\\)\\)' + dependencyRegExp, 'g')
while ((match = re.exec(fnString))) {
if (!sources[match[2]]) {
retval[queueName].push(match[1])
sources[match[2]] = __webpack_require__(match[1]).m
}
retval[match[2]] = retval[match[2]] || []
retval[match[2]].push(match[4])
}
return retval
}
function hasValuesInQueues (queues) {
var keys = Object.keys(queues)
return keys.reduce(function (hasValues, key) {
return hasValues || queues[key].length > 0
}, false)
}
function getRequiredModules (sources, moduleId) {
var modulesQueue = {
main: [moduleId]
}
var requiredModules = {
main: []
}
var seenModules = {
main: {}
}
while (hasValuesInQueues(modulesQueue)) {
var queues = Object.keys(modulesQueue)
for (var i = 0; i < queues.length; i++) {
var queueName = queues[i]
var queue = modulesQueue[queueName]
var moduleToCheck = queue.pop()
seenModules[queueName] = seenModules[queueName] || {}
if (seenModules[queueName][moduleToCheck] || !sources[queueName][moduleToCheck]) continue
seenModules[queueName][moduleToCheck] = true
requiredModules[queueName] = requiredModules[queueName] || []
requiredModules[queueName].push(moduleToCheck)
var newModules = getModuleDependencies(sources, sources[queueName][moduleToCheck], queueName)
var newModulesKeys = Object.keys(newModules)
for (var j = 0; j < newModulesKeys.length; j++) {
modulesQueue[newModulesKeys[j]] = modulesQueue[newModulesKeys[j]] || []
modulesQueue[newModulesKeys[j]] = modulesQueue[newModulesKeys[j]].concat(newModules[newModulesKeys[j]])
}
}
}
return requiredModules
}
module.exports = function (moduleId, options) {
options = options || {}
var sources = {
main: __webpack_require__.m
}
var requiredModules = options.all ? { main: Object.keys(sources) } : getRequiredModules(sources, moduleId)
var src = ''
Object.keys(requiredModules).filter(function (m) { return m !== 'main' }).forEach(function (module) {
var entryModule = 0
while (requiredModules[module][entryModule]) {
entryModule++
}
requiredModules[module].push(entryModule)
sources[module][entryModule] = '(function(module, exports, __webpack_require__) { module.exports = __webpack_require__; })'
src = src + 'var ' + module + ' = (' + webpackBootstrapFunc.toString().replace('ENTRY_MODULE', JSON.stringify(entryModule)) + ')({' + requiredModules[module].map(function (id) { return '' + JSON.stringify(id) + ': ' + sources[module][id].toString() }).join(',') + '});\n'
})
src = src + '(' + webpackBootstrapFunc.toString().replace('ENTRY_MODULE', JSON.stringify(moduleId)) + ')({' + requiredModules.main.map(function (id) { return '' + JSON.stringify(id) + ': ' + sources.main[id].toString() }).join(',') + '})(self);'
var blob = new window.Blob([src], { type: 'text/javascript' })
if (options.bare) { return blob }
var URL = window.URL || window.webkitURL || window.mozURL || window.msURL
var workerUrl = URL.createObjectURL(blob)
var worker = new window.Worker(workerUrl)
worker.objectURL = workerUrl
return worker
}
/***/ }),
/* 5 */
/***/ (function(module, exports) {
// The low-level RushCore module provides the heart of Rusha,
// a high-speed sha1 implementation working on an Int32Array heap.
// At first glance, the implementation seems complicated, however
// with the SHA1 spec at hand, it is obvious this almost a textbook
// implementation that has a few functions hand-inlined and a few loops
// hand-unrolled.
module.exports = function RushaCore(stdlib$846, foreign$847, heap$848) {
'use asm';
var H$849 = new stdlib$846.Int32Array(heap$848);
function hash$850(k$851, x$852) {
// k in bytes
k$851 = k$851 | 0;
x$852 = x$852 | 0;
var i$853 = 0, j$854 = 0, y0$855 = 0, z0$856 = 0, y1$857 = 0, z1$858 = 0, y2$859 = 0, z2$860 = 0, y3$861 = 0, z3$862 = 0, y4$863 = 0, z4$864 = 0, t0$865 = 0, t1$866 = 0;
y0$855 = H$849[x$852 + 320 >> 2] | 0;
y1$857 = H$849[x$852 + 324 >> 2] | 0;
y2$859 = H$849[x$852 + 328 >> 2] | 0;
y3$861 = H$849[x$852 + 332 >> 2] | 0;
y4$863 = H$849[x$852 + 336 >> 2] | 0;
for (i$853 = 0; (i$853 | 0) < (k$851 | 0); i$853 = i$853 + 64 | 0) {
z0$856 = y0$855;
z1$858 = y1$857;
z2$860 = y2$859;
z3$862 = y3$861;
z4$864 = y4$863;
for (j$854 = 0; (j$854 | 0) < 64; j$854 = j$854 + 4 | 0) {
t1$866 = H$849[i$853 + j$854 >> 2] | 0;
t0$865 = ((y0$855 << 5 | y0$855 >>> 27) + (y1$857 & y2$859 | ~y1$857 & y3$861) | 0) + ((t1$866 + y4$863 | 0) + 1518500249 | 0) | 0;
y4$863 = y3$861;
y3$861 = y2$859;
y2$859 = y1$857 << 30 | y1$857 >>> 2;
y1$857 = y0$855;
y0$855 = t0$865;
H$849[k$851 + j$854 >> 2] = t1$866;
}
for (j$854 = k$851 + 64 | 0; (j$854 | 0) < (k$851 + 80 | 0); j$854 = j$854 + 4 | 0) {
t1$866 = (H$849[j$854 - 12 >> 2] ^ H$849[j$854 - 32 >> 2] ^ H$849[j$854 - 56 >> 2] ^ H$849[j$854 - 64 >> 2]) << 1 | (H$849[j$854 - 12 >> 2] ^ H$849[j$854 - 32 >> 2] ^ H$849[j$854 - 56 >> 2] ^ H$849[j$854 - 64 >> 2]) >>> 31;
t0$865 = ((y0$855 << 5 | y0$855 >>> 27) + (y1$857 & y2$859 | ~y1$857 & y3$861) | 0) + ((t1$866 + y4$863 | 0) + 1518500249 | 0) | 0;
y4$863 = y3$861;
y3$861 = y2$859;
y2$859 = y1$857 << 30 | y1$857 >>> 2;
y1$857 = y0$855;
y0$855 = t0$865;
H$849[j$854 >> 2] = t1$866;
}
for (j$854 = k$851 + 80 | 0; (j$854 | 0) < (k$851 + 160 | 0); j$854 = j$854 + 4 | 0) {
t1$866 = (H$849[j$854 - 12 >> 2] ^ H$849[j$854 - 32 >> 2] ^ H$849[j$854 - 56 >> 2] ^ H$849[j$854 - 64 >> 2]) << 1 | (H$849[j$854 - 12 >> 2] ^ H$849[j$854 - 32 >> 2] ^ H$849[j$854 - 56 >> 2] ^ H$849[j$854 - 64 >> 2]) >>> 31;
t0$865 = ((y0$855 << 5 | y0$855 >>> 27) + (y1$857 ^ y2$859 ^ y3$861) | 0) + ((t1$866 + y4$863 | 0) + 1859775393 | 0) | 0;
y4$863 = y3$861;
y3$861 = y2$859;
y2$859 = y1$857 << 30 | y1$857 >>> 2;
y1$857 = y0$855;
y0$855 = t0$865;
H$849[j$854 >> 2] = t1$866;
}
for (j$854 = k$851 + 160 | 0; (j$854 | 0) < (k$851 + 240 | 0); j$854 = j$854 + 4 | 0) {
t1$866 = (H$849[j$854 - 12 >> 2] ^ H$849[j$854 - 32 >> 2] ^ H$849[j$854 - 56 >> 2] ^ H$849[j$854 - 64 >> 2]) << 1 | (H$849[j$854 - 12 >> 2] ^ H$849[j$854 - 32 >> 2] ^ H$849[j$854 - 56 >> 2] ^ H$849[j$854 - 64 >> 2]) >>> 31;
t0$865 = ((y0$855 << 5 | y0$855 >>> 27) + (y1$857 & y2$859 | y1$857 & y3$861 | y2$859 & y3$861) | 0) + ((t1$866 + y4$863 | 0) - 1894007588 | 0) | 0;
y4$863 = y3$861;
y3$861 = y2$859;
y2$859 = y1$857 << 30 | y1$857 >>> 2;
y1$857 = y0$855;
y0$855 = t0$865;
H$849[j$854 >> 2] = t1$866;
}
for (j$854 = k$851 + 240 | 0; (j$854 | 0) < (k$851 + 320 | 0); j$854 = j$854 + 4 | 0) {
t1$866 = (H$849[j$854 - 12 >> 2] ^ H$849[j$854 - 32 >> 2] ^ H$849[j$854 - 56 >> 2] ^ H$849[j$854 - 64 >> 2]) << 1 | (H$849[j$854 - 12 >> 2] ^ H$849[j$854 - 32 >> 2] ^ H$849[j$854 - 56 >> 2] ^ H$849[j$854 - 64 >> 2]) >>> 31;
t0$865 = ((y0$855 << 5 | y0$855 >>> 27) + (y1$857 ^ y2$859 ^ y3$861) | 0) + ((t1$866 + y4$863 | 0) - 899497514 | 0) | 0;
y4$863 = y3$861;
y3$861 = y2$859;
y2$859 = y1$857 << 30 | y1$857 >>> 2;
y1$857 = y0$855;
y0$855 = t0$865;
H$849[j$854 >> 2] = t1$866;
}
y0$855 = y0$855 + z0$856 | 0;
y1$857 = y1$857 + z1$858 | 0;
y2$859 = y2$859 + z2$860 | 0;
y3$861 = y3$861 + z3$862 | 0;
y4$863 = y4$863 + z4$864 | 0;
}
H$849[x$852 + 320 >> 2] = y0$855;
H$849[x$852 + 324 >> 2] = y1$857;
H$849[x$852 + 328 >> 2] = y2$859;
H$849[x$852 + 332 >> 2] = y3$861;
H$849[x$852 + 336 >> 2] = y4$863;
}
return { hash: hash$850 };
};
/***/ }),
/* 6 */
/***/ (function(module, exports) {
var _this = this;
/* eslint-env commonjs, browser */
var reader = void 0;
if (typeof self !== 'undefined' && typeof self.FileReaderSync !== 'undefined') {
reader = new self.FileReaderSync();
}
// Convert a binary string and write it to the heap.
// A binary string is expected to only contain char codes < 256.
var convStr = function (str, H8, H32, start, len, off) {
var i = void 0,
om = off % 4,
lm = (len + om) % 4,
j = len - lm;
switch (om) {
case 0:
H8[off] = str.charCodeAt(start + 3);
case 1:
H8[off + 1 - (om << 1) | 0] = str.charCodeAt(start + 2);
case 2:
H8[off + 2 - (om << 1) | 0] = str.charCodeAt(start + 1);
case 3:
H8[off + 3 - (om << 1) | 0] = str.charCodeAt(start);
}
if (len < lm + (4 - om)) {
return;
}
for (i = 4 - om; i < j; i = i + 4 | 0) {
H32[off + i >> 2] = str.charCodeAt(start + i) << 24 | str.charCodeAt(start + i + 1) << 16 | str.charCodeAt(start + i + 2) << 8 | str.charCodeAt(start + i + 3);
}
switch (lm) {
case 3:
H8[off + j + 1 | 0] = str.charCodeAt(start + j + 2);
case 2:
H8[off + j + 2 | 0] = str.charCodeAt(start + j + 1);
case 1:
H8[off + j + 3 | 0] = str.charCodeAt(start + j);
}
};
// Convert a buffer or array and write it to the heap.
// The buffer or array is expected to only contain elements < 256.
var convBuf = function (buf, H8, H32, start, len, off) {
var i = void 0,
om = off % 4,
lm = (len + om) % 4,
j = len - lm;
switch (om) {
case 0:
H8[off] = buf[start + 3];
case 1:
H8[off + 1 - (om << 1) | 0] = buf[start + 2];
case 2:
H8[off + 2 - (om << 1) | 0] = buf[start + 1];
case 3:
H8[off + 3 - (om << 1) | 0] = buf[start];
}
if (len < lm + (4 - om)) {
return;
}
for (i = 4 - om; i < j; i = i + 4 | 0) {
H32[off + i >> 2 | 0] = buf[start + i] << 24 | buf[start + i + 1] << 16 | buf[start + i + 2] << 8 | buf[start + i + 3];
}
switch (lm) {
case 3:
H8[off + j + 1 | 0] = buf[start + j + 2];
case 2:
H8[off + j + 2 | 0] = buf[start + j + 1];
case 1:
H8[off + j + 3 | 0] = buf[start + j];
}
};
var convBlob = function (blob, H8, H32, start, len, off) {
var i = void 0,
om = off % 4,
lm = (len + om) % 4,
j = len - lm;
var buf = new Uint8Array(reader.readAsArrayBuffer(blob.slice(start, start + len)));
switch (om) {
case 0:
H8[off] = buf[3];
case 1:
H8[off + 1 - (om << 1) | 0] = buf[2];
case 2:
H8[off + 2 - (om << 1) | 0] = buf[1];
case 3:
H8[off + 3 - (om << 1) | 0] = buf[0];
}
if (len < lm + (4 - om)) {
return;
}
for (i = 4 - om; i < j; i = i + 4 | 0) {
H32[off + i >> 2 | 0] = buf[i] << 24 | buf[i + 1] << 16 | buf[i + 2] << 8 | buf[i + 3];
}
switch (lm) {
case 3:
H8[off + j + 1 | 0] = buf[j + 2];
case 2:
H8[off + j + 2 | 0] = buf[j + 1];
case 1:
H8[off + j + 3 | 0] = buf[j];
}
};
module.exports = function (data, H8, H32, start, len, off) {
if (typeof data === 'string') {
return convStr(data, H8, H32, start, len, off);
}
if (data instanceof Array) {
return convBuf(data, H8, H32, start, len, off);
}
// Safely doing a Buffer check using "this" to avoid Buffer polyfill to be included in the dist
if (_this && _this.Buffer && _this.Buffer.isBuffer(data)) {
return convBuf(data, H8, H32, start, len, off);
}
if (data instanceof ArrayBuffer) {
return convBuf(new Uint8Array(data), H8, H32, start, len, off);
}
if (data.buffer instanceof ArrayBuffer) {
return convBuf(new Uint8Array(data.buffer, data.byteOffset, data.byteLength), H8, H32, start, len, off);
}
if (data instanceof Blob) {
return convBlob(data, H8, H32, start, len, off);
}
throw new Error('Unsupported data type.');
};
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/* eslint-env commonjs, browser */
var Rusha = __webpack_require__(0);
var _require = __webpack_require__(1),
toHex = _require.toHex;
var Hash = function () {
function Hash() {
_classCallCheck(this, Hash);
this._rusha = new Rusha();
this._rusha.resetState();
}
Hash.prototype.update = function update(data) {
this._rusha.append(data);
return this;
};
Hash.prototype.digest = function digest(encoding) {
var digest = this._rusha.rawEnd().buffer;
if (!encoding) {
return digest;
}
if (encoding === 'hex') {
return toHex(digest);
}
throw new Error('unsupported digest encoding');
};
return Hash;
}();
module.exports = function () {
return new Hash();
};
/***/ })
/******/ ]);
});
},{}],220:[function(require,module,exports){
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/* 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)
}
SafeBuffer.prototype = Object.create(Buffer.prototype)
// 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":60}],221:[function(require,module,exports){
(function (Buffer){(function (){
/*! simple-concat. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
module.exports = function (stream, cb) {
var chunks = []
stream.on('data', function (chunk) {
chunks.push(chunk)
})
stream.once('end', function () {
if (cb) cb(null, Buffer.concat(chunks))
cb = null
})
stream.once('error', function (err) {
if (cb) cb(err)
cb = null
})
}
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60}],222:[function(require,module,exports){
(function (Buffer){(function (){
/*! simple-get. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
module.exports = simpleGet
const concat = require('simple-concat')
const decompressResponse = require('decompress-response') // excluded from browser build
const http = require('http')
const https = require('https')
const once = require('once')
const querystring = require('querystring')
const url = require('url')
const isStream = o => o !== null && typeof o === 'object' && typeof o.pipe === 'function'
function simpleGet (opts, cb) {
opts = Object.assign({ maxRedirects: 10 }, typeof opts === 'string' ? { url: opts } : opts)
cb = once(cb)
if (opts.url) {
const { hostname, port, protocol, auth, path } = url.parse(opts.url) // eslint-disable-line node/no-deprecated-api
delete opts.url
if (!hostname && !port && !protocol && !auth) opts.path = path // Relative redirect
else Object.assign(opts, { hostname, port, protocol, auth, path }) // Absolute redirect
}
const headers = { 'accept-encoding': 'gzip, deflate' }
if (opts.headers) Object.keys(opts.headers).forEach(k => (headers[k.toLowerCase()] = opts.headers[k]))
opts.headers = headers
let body
if (opts.body) {
body = opts.json && !isStream(opts.body) ? JSON.stringify(opts.body) : opts.body
} else if (opts.form) {
body = typeof opts.form === 'string' ? opts.form : querystring.stringify(opts.form)
opts.headers['content-type'] = 'application/x-www-form-urlencoded'
}
if (body) {
if (!opts.method) opts.method = 'POST'
if (!isStream(body)) opts.headers['content-length'] = Buffer.byteLength(body)
if (opts.json && !opts.form) opts.headers['content-type'] = 'application/json'
}
delete opts.body; delete opts.form
if (opts.json) opts.headers.accept = 'application/json'
if (opts.method) opts.method = opts.method.toUpperCase()
const protocol = opts.protocol === 'https:' ? https : http // Support http/https urls
const req = protocol.request(opts, res => {
if (opts.followRedirects !== false && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
opts.url = res.headers.location // Follow 3xx redirects
delete opts.headers.host // Discard `host` header on redirect (see #32)
res.resume() // Discard response
if (opts.method === 'POST' && [301, 302].includes(res.statusCode)) {
opts.method = 'GET' // On 301/302 redirect, change POST to GET (see #35)
delete opts.headers['content-length']; delete opts.headers['content-type']
}
if (opts.maxRedirects-- === 0) return cb(new Error('too many redirects'))
else return simpleGet(opts, cb)
}
const tryUnzip = typeof decompressResponse === 'function' && opts.method !== 'HEAD'
cb(null, tryUnzip ? decompressResponse(res) : res)
})
req.on('timeout', () => {
req.abort()
cb(new Error('Request timed out'))
})
req.on('error', cb)
if (isStream(body)) body.on('error', cb).pipe(req)
else req.end(body)
return req
}
simpleGet.concat = (opts, cb) => {
return simpleGet(opts, (err, res) => {
if (err) return cb(err)
concat(res, (err, data) => {
if (err) return cb(err)
if (opts.json) {
try {
data = JSON.parse(data.toString())
} catch (err) {
return cb(err, res, data)
}
}
cb(null, res, data)
})
})
}
;['get', 'post', 'put', 'patch', 'head', 'delete'].forEach(method => {
simpleGet[method] = (opts, cb) => {
if (typeof opts === 'string') opts = { url: opts }
return simpleGet(Object.assign({ method: method.toUpperCase() }, opts), cb)
}
})
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60,"decompress-response":55,"http":264,"https":116,"once":183,"querystring":192,"simple-concat":221,"url":299}],223:[function(require,module,exports){
/*! simple-peer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
const debug = require('debug')('simple-peer')
const getBrowserRTC = require('get-browser-rtc')
const randombytes = require('randombytes')
const stream = require('readable-stream')
const queueMicrotask = require('queue-microtask') // TODO: remove when Node 10 is not supported
const errCode = require('err-code')
const { Buffer } = require('buffer')
const MAX_BUFFERED_AMOUNT = 64 * 1024
const ICECOMPLETE_TIMEOUT = 5 * 1000
const CHANNEL_CLOSING_TIMEOUT = 5 * 1000
// HACK: Filter trickle lines when trickle is disabled #354
function filterTrickle (sdp) {
return sdp.replace(/a=ice-options:trickle\s\n/g, '')
}
function warn (message) {
console.warn(message)
}
/**
* WebRTC peer connection. Same API as node core `net.Socket`, plus a few extra methods.
* Duplex stream.
* @param {Object} opts
*/
class Peer extends stream.Duplex {
constructor (opts) {
opts = Object.assign({
allowHalfOpen: false
}, opts)
super(opts)
this._id = randombytes(4).toString('hex').slice(0, 7)
this._debug('new peer %o', opts)
this.channelName = opts.initiator
? opts.channelName || randombytes(20).toString('hex')
: null
this.initiator = opts.initiator || false
this.channelConfig = opts.channelConfig || Peer.channelConfig
this.channelNegotiated = this.channelConfig.negotiated
this.config = Object.assign({}, Peer.config, opts.config)
this.offerOptions = opts.offerOptions || {}
this.answerOptions = opts.answerOptions || {}
this.sdpTransform = opts.sdpTransform || (sdp => sdp)
this.streams = opts.streams || (opts.stream ? [opts.stream] : []) // support old "stream" option
this.trickle = opts.trickle !== undefined ? opts.trickle : true
this.allowHalfTrickle = opts.allowHalfTrickle !== undefined ? opts.allowHalfTrickle : false
this.iceCompleteTimeout = opts.iceCompleteTimeout || ICECOMPLETE_TIMEOUT
this.destroyed = false
this.destroying = false
this._connected = false
this.remoteAddress = undefined
this.remoteFamily = undefined
this.remotePort = undefined
this.localAddress = undefined
this.localFamily = undefined
this.localPort = undefined
this._wrtc = (opts.wrtc && typeof opts.wrtc === 'object')
? opts.wrtc
: getBrowserRTC()
if (!this._wrtc) {
if (typeof window === 'undefined') {
throw errCode(new Error('No WebRTC support: Specify `opts.wrtc` option in this environment'), 'ERR_WEBRTC_SUPPORT')
} else {
throw errCode(new Error('No WebRTC support: Not a supported browser'), 'ERR_WEBRTC_SUPPORT')
}
}
this._pcReady = false
this._channelReady = false
this._iceComplete = false // ice candidate trickle done (got null candidate)
this._iceCompleteTimer = null // send an offer/answer anyway after some timeout
this._channel = null
this._pendingCandidates = []
this._isNegotiating = false // is this peer waiting for negotiation to complete?
this._firstNegotiation = true
this._batchedNegotiation = false // batch synchronous negotiations
this._queuedNegotiation = false // is there a queued negotiation request?
this._sendersAwaitingStable = []
this._senderMap = new Map()
this._closingInterval = null
this._remoteTracks = []
this._remoteStreams = []
this._chunk = null
this._cb = null
this._interval = null
try {
this._pc = new (this._wrtc.RTCPeerConnection)(this.config)
} catch (err) {
queueMicrotask(() => this.destroy(errCode(err, 'ERR_PC_CONSTRUCTOR')))
return
}
// We prefer feature detection whenever possible, but sometimes that's not
// possible for certain implementations.
this._isReactNativeWebrtc = typeof this._pc._peerConnectionId === 'number'
this._pc.oniceconnectionstatechange = () => {
this._onIceStateChange()
}
this._pc.onicegatheringstatechange = () => {
this._onIceStateChange()
}
this._pc.onconnectionstatechange = () => {
this._onConnectionStateChange()
}
this._pc.onsignalingstatechange = () => {
this._onSignalingStateChange()
}
this._pc.onicecandidate = event => {
this._onIceCandidate(event)
}
// Other spec events, unused by this implementation:
// - onconnectionstatechange
// - onicecandidateerror
// - onfingerprintfailure
// - onnegotiationneeded
if (this.initiator || this.channelNegotiated) {
this._setupData({
channel: this._pc.createDataChannel(this.channelName, this.channelConfig)
})
} else {
this._pc.ondatachannel = event => {
this._setupData(event)
}
}
if (this.streams) {
this.streams.forEach(stream => {
this.addStream(stream)
})
}
this._pc.ontrack = event => {
this._onTrack(event)
}
this._debug('initial negotiation')
this._needsNegotiation()
this._onFinishBound = () => {
this._onFinish()
}
this.once('finish', this._onFinishBound)
}
get bufferSize () {
return (this._channel && this._channel.bufferedAmount) || 0
}
// HACK: it's possible channel.readyState is "closing" before peer.destroy() fires
// https://bugs.chromium.org/p/chromium/issues/detail?id=882743
get connected () {
return (this._connected && this._channel.readyState === 'open')
}
address () {
return { port: this.localPort, family: this.localFamily, address: this.localAddress }
}
signal (data) {
if (this.destroyed) throw errCode(new Error('cannot signal after peer is destroyed'), 'ERR_SIGNALING')
if (typeof data === 'string') {
try {
data = JSON.parse(data)
} catch (err) {
data = {}
}
}
this._debug('signal()')
if (data.renegotiate && this.initiator) {
this._debug('got request to renegotiate')
this._needsNegotiation()
}
if (data.transceiverRequest && this.initiator) {
this._debug('got request for transceiver')
this.addTransceiver(data.transceiverRequest.kind, data.transceiverRequest.init)
}
if (data.candidate) {
if (this._pc.remoteDescription && this._pc.remoteDescription.type) {
this._addIceCandidate(data.candidate)
} else {
this._pendingCandidates.push(data.candidate)
}
}
if (data.sdp) {
this._pc.setRemoteDescription(new (this._wrtc.RTCSessionDescription)(data))
.then(() => {
if (this.destroyed) return
this._pendingCandidates.forEach(candidate => {
this._addIceCandidate(candidate)
})
this._pendingCandidates = []
if (this._pc.remoteDescription.type === 'offer') this._createAnswer()
})
.catch(err => {
this.destroy(errCode(err, 'ERR_SET_REMOTE_DESCRIPTION'))
})
}
if (!data.sdp && !data.candidate && !data.renegotiate && !data.transceiverRequest) {
this.destroy(errCode(new Error('signal() called with invalid signal data'), 'ERR_SIGNALING'))
}
}
_addIceCandidate (candidate) {
const iceCandidateObj = new this._wrtc.RTCIceCandidate(candidate)
this._pc.addIceCandidate(iceCandidateObj)
.catch(err => {
if (!iceCandidateObj.address || iceCandidateObj.address.endsWith('.local')) {
warn('Ignoring unsupported ICE candidate.')
} else {
this.destroy(errCode(err, 'ERR_ADD_ICE_CANDIDATE'))
}
})
}
/**
* Send text/binary data to the remote peer.
* @param {ArrayBufferView|ArrayBuffer|Buffer|string|Blob} chunk
*/
send (chunk) {
this._channel.send(chunk)
}
/**
* Add a Transceiver to the connection.
* @param {String} kind
* @param {Object} init
*/
addTransceiver (kind, init) {
this._debug('addTransceiver()')
if (this.initiator) {
try {
this._pc.addTransceiver(kind, init)
this._needsNegotiation()
} catch (err) {
this.destroy(errCode(err, 'ERR_ADD_TRANSCEIVER'))
}
} else {
this.emit('signal', { // request initiator to renegotiate
type: 'transceiverRequest',
transceiverRequest: { kind, init }
})
}
}
/**
* Add a MediaStream to the connection.
* @param {MediaStream} stream
*/
addStream (stream) {
this._debug('addStream()')
stream.getTracks().forEach(track => {
this.addTrack(track, stream)
})
}
/**
* Add a MediaStreamTrack to the connection.
* @param {MediaStreamTrack} track
* @param {MediaStream} stream
*/
addTrack (track, stream) {
this._debug('addTrack()')
const submap = this._senderMap.get(track) || new Map() // nested Maps map [track, stream] to sender
let sender = submap.get(stream)
if (!sender) {
sender = this._pc.addTrack(track, stream)
submap.set(stream, sender)
this._senderMap.set(track, submap)
this._needsNegotiation()
} else if (sender.removed) {
throw errCode(new Error('Track has been removed. You should enable/disable tracks that you want to re-add.'), 'ERR_SENDER_REMOVED')
} else {
throw errCode(new Error('Track has already been added to that stream.'), 'ERR_SENDER_ALREADY_ADDED')
}
}
/**
* Replace a MediaStreamTrack by another in the connection.
* @param {MediaStreamTrack} oldTrack
* @param {MediaStreamTrack} newTrack
* @param {MediaStream} stream
*/
replaceTrack (oldTrack, newTrack, stream) {
this._debug('replaceTrack()')
const submap = this._senderMap.get(oldTrack)
const sender = submap ? submap.get(stream) : null
if (!sender) {
throw errCode(new Error('Cannot replace track that was never added.'), 'ERR_TRACK_NOT_ADDED')
}
if (newTrack) this._senderMap.set(newTrack, submap)
if (sender.replaceTrack != null) {
sender.replaceTrack(newTrack)
} else {
this.destroy(errCode(new Error('replaceTrack is not supported in this browser'), 'ERR_UNSUPPORTED_REPLACETRACK'))
}
}
/**
* Remove a MediaStreamTrack from the connection.
* @param {MediaStreamTrack} track
* @param {MediaStream} stream
*/
removeTrack (track, stream) {
this._debug('removeSender()')
const submap = this._senderMap.get(track)
const sender = submap ? submap.get(stream) : null
if (!sender) {
throw errCode(new Error('Cannot remove track that was never added.'), 'ERR_TRACK_NOT_ADDED')
}
try {
sender.removed = true
this._pc.removeTrack(sender)
} catch (err) {
if (err.name === 'NS_ERROR_UNEXPECTED') {
this._sendersAwaitingStable.push(sender) // HACK: Firefox must wait until (signalingState === stable) https://bugzilla.mozilla.org/show_bug.cgi?id=1133874
} else {
this.destroy(errCode(err, 'ERR_REMOVE_TRACK'))
}
}
this._needsNegotiation()
}
/**
* Remove a MediaStream from the connection.
* @param {MediaStream} stream
*/
removeStream (stream) {
this._debug('removeSenders()')
stream.getTracks().forEach(track => {
this.removeTrack(track, stream)
})
}
_needsNegotiation () {
this._debug('_needsNegotiation')
if (this._batchedNegotiation) return // batch synchronous renegotiations
this._batchedNegotiation = true
queueMicrotask(() => {
this._batchedNegotiation = false
if (this.initiator || !this._firstNegotiation) {
this._debug('starting batched negotiation')
this.negotiate()
} else {
this._debug('non-initiator initial negotiation request discarded')
}
this._firstNegotiation = false
})
}
negotiate () {
if (this.initiator) {
if (this._isNegotiating) {
this._queuedNegotiation = true
this._debug('already negotiating, queueing')
} else {
this._debug('start negotiation')
setTimeout(() => { // HACK: Chrome crashes if we immediately call createOffer
this._createOffer()
}, 0)
}
} else {
if (this._isNegotiating) {
this._queuedNegotiation = true
this._debug('already negotiating, queueing')
} else {
this._debug('requesting negotiation from initiator')
this.emit('signal', { // request initiator to renegotiate
type: 'renegotiate',
renegotiate: true
})
}
}
this._isNegotiating = true
}
// TODO: Delete this method once readable-stream is updated to contain a default
// implementation of destroy() that automatically calls _destroy()
// See: https://github.com/nodejs/readable-stream/issues/283
destroy (err) {
this._destroy(err, () => {})
}
_destroy (err, cb) {
if (this.destroyed || this.destroying) return
this.destroying = true
this._debug('destroying (error: %s)', err && (err.message || err))
queueMicrotask(() => { // allow events concurrent with the call to _destroy() to fire (see #692)
this.destroyed = true
this.destroying = false
this._debug('destroy (error: %s)', err && (err.message || err))
this.readable = this.writable = false
if (!this._readableState.ended) this.push(null)
if (!this._writableState.finished) this.end()
this._connected = false
this._pcReady = false
this._channelReady = false
this._remoteTracks = null
this._remoteStreams = null
this._senderMap = null
clearInterval(this._closingInterval)
this._closingInterval = null
clearInterval(this._interval)
this._interval = null
this._chunk = null
this._cb = null
if (this._onFinishBound) this.removeListener('finish', this._onFinishBound)
this._onFinishBound = null
if (this._channel) {
try {
this._channel.close()
} catch (err) {}
// allow events concurrent with destruction to be handled
this._channel.onmessage = null
this._channel.onopen = null
this._channel.onclose = null
this._channel.onerror = null
}
if (this._pc) {
try {
this._pc.close()
} catch (err) {}
// allow events concurrent with destruction to be handled
this._pc.oniceconnectionstatechange = null
this._pc.onicegatheringstatechange = null
this._pc.onsignalingstatechange = null
this._pc.onicecandidate = null
this._pc.ontrack = null
this._pc.ondatachannel = null
}
this._pc = null
this._channel = null
if (err) this.emit('error', err)
this.emit('close')
cb()
})
}
_setupData (event) {
if (!event.channel) {
// In some situations `pc.createDataChannel()` returns `undefined` (in wrtc),
// which is invalid behavior. Handle it gracefully.
// See: https://github.com/feross/simple-peer/issues/163
return this.destroy(errCode(new Error('Data channel event is missing `channel` property'), 'ERR_DATA_CHANNEL'))
}
this._channel = event.channel
this._channel.binaryType = 'arraybuffer'
if (typeof this._channel.bufferedAmountLowThreshold === 'number') {
this._channel.bufferedAmountLowThreshold = MAX_BUFFERED_AMOUNT
}
this.channelName = this._channel.label
this._channel.onmessage = event => {
this._onChannelMessage(event)
}
this._channel.onbufferedamountlow = () => {
this._onChannelBufferedAmountLow()
}
this._channel.onopen = () => {
this._onChannelOpen()
}
this._channel.onclose = () => {
this._onChannelClose()
}
this._channel.onerror = err => {
this.destroy(errCode(err, 'ERR_DATA_CHANNEL'))
}
// HACK: Chrome will sometimes get stuck in readyState "closing", let's check for this condition
// https://bugs.chromium.org/p/chromium/issues/detail?id=882743
let isClosing = false
this._closingInterval = setInterval(() => { // No "onclosing" event
if (this._channel && this._channel.readyState === 'closing') {
if (isClosing) this._onChannelClose() // closing timed out: equivalent to onclose firing
isClosing = true
} else {
isClosing = false
}
}, CHANNEL_CLOSING_TIMEOUT)
}
_read () {}
_write (chunk, encoding, cb) {
if (this.destroyed) return cb(errCode(new Error('cannot write after peer is destroyed'), 'ERR_DATA_CHANNEL'))
if (this._connected) {
try {
this.send(chunk)
} catch (err) {
return this.destroy(errCode(err, 'ERR_DATA_CHANNEL'))
}
if (this._channel.bufferedAmount > MAX_BUFFERED_AMOUNT) {
this._debug('start backpressure: bufferedAmount %d', this._channel.bufferedAmount)
this._cb = cb
} else {
cb(null)
}
} else {
this._debug('write before connect')
this._chunk = chunk
this._cb = cb
}
}
// When stream finishes writing, close socket. Half open connections are not
// supported.
_onFinish () {
if (this.destroyed) return
// Wait a bit before destroying so the socket flushes.
// TODO: is there a more reliable way to accomplish this?
const destroySoon = () => {
setTimeout(() => this.destroy(), 1000)
}
if (this._connected) {
destroySoon()
} else {
this.once('connect', destroySoon)
}
}
_startIceCompleteTimeout () {
if (this.destroyed) return
if (this._iceCompleteTimer) return
this._debug('started iceComplete timeout')
this._iceCompleteTimer = setTimeout(() => {
if (!this._iceComplete) {
this._iceComplete = true
this._debug('iceComplete timeout completed')
this.emit('iceTimeout')
this.emit('_iceComplete')
}
}, this.iceCompleteTimeout)
}
_createOffer () {
if (this.destroyed) return
this._pc.createOffer(this.offerOptions)
.then(offer => {
if (this.destroyed) return
if (!this.trickle && !this.allowHalfTrickle) offer.sdp = filterTrickle(offer.sdp)
offer.sdp = this.sdpTransform(offer.sdp)
const sendOffer = () => {
if (this.destroyed) return
const signal = this._pc.localDescription || offer
this._debug('signal')
this.emit('signal', {
type: signal.type,
sdp: signal.sdp
})
}
const onSuccess = () => {
this._debug('createOffer success')
if (this.destroyed) return
if (this.trickle || this._iceComplete) sendOffer()
else this.once('_iceComplete', sendOffer) // wait for candidates
}
const onError = err => {
this.destroy(errCode(err, 'ERR_SET_LOCAL_DESCRIPTION'))
}
this._pc.setLocalDescription(offer)
.then(onSuccess)
.catch(onError)
})
.catch(err => {
this.destroy(errCode(err, 'ERR_CREATE_OFFER'))
})
}
_requestMissingTransceivers () {
if (this._pc.getTransceivers) {
this._pc.getTransceivers().forEach(transceiver => {
if (!transceiver.mid && transceiver.sender.track && !transceiver.requested) {
transceiver.requested = true // HACK: Safari returns negotiated transceivers with a null mid
this.addTransceiver(transceiver.sender.track.kind)
}
})
}
}
_createAnswer () {
if (this.destroyed) return
this._pc.createAnswer(this.answerOptions)
.then(answer => {
if (this.destroyed) return
if (!this.trickle && !this.allowHalfTrickle) answer.sdp = filterTrickle(answer.sdp)
answer.sdp = this.sdpTransform(answer.sdp)
const sendAnswer = () => {
if (this.destroyed) return
const signal = this._pc.localDescription || answer
this._debug('signal')
this.emit('signal', {
type: signal.type,
sdp: signal.sdp
})
if (!this.initiator) this._requestMissingTransceivers()
}
const onSuccess = () => {
if (this.destroyed) return
if (this.trickle || this._iceComplete) sendAnswer()
else this.once('_iceComplete', sendAnswer)
}
const onError = err => {
this.destroy(errCode(err, 'ERR_SET_LOCAL_DESCRIPTION'))
}
this._pc.setLocalDescription(answer)
.then(onSuccess)
.catch(onError)
})
.catch(err => {
this.destroy(errCode(err, 'ERR_CREATE_ANSWER'))
})
}
_onConnectionStateChange () {
if (this.destroyed) return
if (this._pc.connectionState === 'failed') {
this.destroy(errCode(new Error('Connection failed.'), 'ERR_CONNECTION_FAILURE'))
}
}
_onIceStateChange () {
if (this.destroyed) return
const iceConnectionState = this._pc.iceConnectionState
const iceGatheringState = this._pc.iceGatheringState
this._debug(
'iceStateChange (connection: %s) (gathering: %s)',
iceConnectionState,
iceGatheringState
)
this.emit('iceStateChange', iceConnectionState, iceGatheringState)
if (iceConnectionState === 'connected' || iceConnectionState === 'completed') {
this._pcReady = true
this._maybeReady()
}
if (iceConnectionState === 'failed') {
this.destroy(errCode(new Error('Ice connection failed.'), 'ERR_ICE_CONNECTION_FAILURE'))
}
if (iceConnectionState === 'closed') {
this.destroy(errCode(new Error('Ice connection closed.'), 'ERR_ICE_CONNECTION_CLOSED'))
}
}
getStats (cb) {
// statreports can come with a value array instead of properties
const flattenValues = report => {
if (Object.prototype.toString.call(report.values) === '[object Array]') {
report.values.forEach(value => {
Object.assign(report, value)
})
}
return report
}
// Promise-based getStats() (standard)
if (this._pc.getStats.length === 0 || this._isReactNativeWebrtc) {
this._pc.getStats()
.then(res => {
const reports = []
res.forEach(report => {
reports.push(flattenValues(report))
})
cb(null, reports)
}, err => cb(err))
// Single-parameter callback-based getStats() (non-standard)
} else if (this._pc.getStats.length > 0) {
this._pc.getStats(res => {
// If we destroy connection in `connect` callback this code might happen to run when actual connection is already closed
if (this.destroyed) return
const reports = []
res.result().forEach(result => {
const report = {}
result.names().forEach(name => {
report[name] = result.stat(name)
})
report.id = result.id
report.type = result.type
report.timestamp = result.timestamp
reports.push(flattenValues(report))
})
cb(null, reports)
}, err => cb(err))
// Unknown browser, skip getStats() since it's anyone's guess which style of
// getStats() they implement.
} else {
cb(null, [])
}
}
_maybeReady () {
this._debug('maybeReady pc %s channel %s', this._pcReady, this._channelReady)
if (this._connected || this._connecting || !this._pcReady || !this._channelReady) return
this._connecting = true
// HACK: We can't rely on order here, for details see https://github.com/js-platform/node-webrtc/issues/339
const findCandidatePair = () => {
if (this.destroyed) return
this.getStats((err, items) => {
if (this.destroyed) return
// Treat getStats error as non-fatal. It's not essential.
if (err) items = []
const remoteCandidates = {}
const localCandidates = {}
const candidatePairs = {}
let foundSelectedCandidatePair = false
items.forEach(item => {
// TODO: Once all browsers support the hyphenated stats report types, remove
// the non-hypenated ones
if (item.type === 'remotecandidate' || item.type === 'remote-candidate') {
remoteCandidates[item.id] = item
}
if (item.type === 'localcandidate' || item.type === 'local-candidate') {
localCandidates[item.id] = item
}
if (item.type === 'candidatepair' || item.type === 'candidate-pair') {
candidatePairs[item.id] = item
}
})
const setSelectedCandidatePair = selectedCandidatePair => {
foundSelectedCandidatePair = true
let local = localCandidates[selectedCandidatePair.localCandidateId]
if (local && (local.ip || local.address)) {
// Spec
this.localAddress = local.ip || local.address
this.localPort = Number(local.port)
} else if (local && local.ipAddress) {
// Firefox
this.localAddress = local.ipAddress
this.localPort = Number(local.portNumber)
} else if (typeof selectedCandidatePair.googLocalAddress === 'string') {
// TODO: remove this once Chrome 58 is released
local = selectedCandidatePair.googLocalAddress.split(':')
this.localAddress = local[0]
this.localPort = Number(local[1])
}
if (this.localAddress) {
this.localFamily = this.localAddress.includes(':') ? 'IPv6' : 'IPv4'
}
let remote = remoteCandidates[selectedCandidatePair.remoteCandidateId]
if (remote && (remote.ip || remote.address)) {
// Spec
this.remoteAddress = remote.ip || remote.address
this.remotePort = Number(remote.port)
} else if (remote && remote.ipAddress) {
// Firefox
this.remoteAddress = remote.ipAddress
this.remotePort = Number(remote.portNumber)
} else if (typeof selectedCandidatePair.googRemoteAddress === 'string') {
// TODO: remove this once Chrome 58 is released
remote = selectedCandidatePair.googRemoteAddress.split(':')
this.remoteAddress = remote[0]
this.remotePort = Number(remote[1])
}
if (this.remoteAddress) {
this.remoteFamily = this.remoteAddress.includes(':') ? 'IPv6' : 'IPv4'
}
this._debug(
'connect local: %s:%s remote: %s:%s',
this.localAddress,
this.localPort,
this.remoteAddress,
this.remotePort
)
}
items.forEach(item => {
// Spec-compliant
if (item.type === 'transport' && item.selectedCandidatePairId) {
setSelectedCandidatePair(candidatePairs[item.selectedCandidatePairId])
}
// Old implementations
if (
(item.type === 'googCandidatePair' && item.googActiveConnection === 'true') ||
((item.type === 'candidatepair' || item.type === 'candidate-pair') && item.selected)
) {
setSelectedCandidatePair(item)
}
})
// Ignore candidate pair selection in browsers like Safari 11 that do not have any local or remote candidates
// But wait until at least 1 candidate pair is available
if (!foundSelectedCandidatePair && (!Object.keys(candidatePairs).length || Object.keys(localCandidates).length)) {
setTimeout(findCandidatePair, 100)
return
} else {
this._connecting = false
this._connected = true
}
if (this._chunk) {
try {
this.send(this._chunk)
} catch (err) {
return this.destroy(errCode(err, 'ERR_DATA_CHANNEL'))
}
this._chunk = null
this._debug('sent chunk from "write before connect"')
const cb = this._cb
this._cb = null
cb(null)
}
// If `bufferedAmountLowThreshold` and 'onbufferedamountlow' are unsupported,
// fallback to using setInterval to implement backpressure.
if (typeof this._channel.bufferedAmountLowThreshold !== 'number') {
this._interval = setInterval(() => this._onInterval(), 150)
if (this._interval.unref) this._interval.unref()
}
this._debug('connect')
this.emit('connect')
})
}
findCandidatePair()
}
_onInterval () {
if (!this._cb || !this._channel || this._channel.bufferedAmount > MAX_BUFFERED_AMOUNT) {
return
}
this._onChannelBufferedAmountLow()
}
_onSignalingStateChange () {
if (this.destroyed) return
if (this._pc.signalingState === 'stable') {
this._isNegotiating = false
// HACK: Firefox doesn't yet support removing tracks when signalingState !== 'stable'
this._debug('flushing sender queue', this._sendersAwaitingStable)
this._sendersAwaitingStable.forEach(sender => {
this._pc.removeTrack(sender)
this._queuedNegotiation = true
})
this._sendersAwaitingStable = []
if (this._queuedNegotiation) {
this._debug('flushing negotiation queue')
this._queuedNegotiation = false
this._needsNegotiation() // negotiate again
} else {
this._debug('negotiated')
this.emit('negotiated')
}
}
this._debug('signalingStateChange %s', this._pc.signalingState)
this.emit('signalingStateChange', this._pc.signalingState)
}
_onIceCandidate (event) {
if (this.destroyed) return
if (event.candidate && this.trickle) {
this.emit('signal', {
type: 'candidate',
candidate: {
candidate: event.candidate.candidate,
sdpMLineIndex: event.candidate.sdpMLineIndex,
sdpMid: event.candidate.sdpMid
}
})
} else if (!event.candidate && !this._iceComplete) {
this._iceComplete = true
this.emit('_iceComplete')
}
// as soon as we've received one valid candidate start timeout
if (event.candidate) {
this._startIceCompleteTimeout()
}
}
_onChannelMessage (event) {
if (this.destroyed) return
let data = event.data
if (data instanceof ArrayBuffer) data = Buffer.from(data)
this.push(data)
}
_onChannelBufferedAmountLow () {
if (this.destroyed || !this._cb) return
this._debug('ending backpressure: bufferedAmount %d', this._channel.bufferedAmount)
const cb = this._cb
this._cb = null
cb(null)
}
_onChannelOpen () {
if (this._connected || this.destroyed) return
this._debug('on channel open')
this._channelReady = true
this._maybeReady()
}
_onChannelClose () {
if (this.destroyed) return
this._debug('on channel close')
this.destroy()
}
_onTrack (event) {
if (this.destroyed) return
event.streams.forEach(eventStream => {
this._debug('on track')
this.emit('track', event.track, eventStream)
this._remoteTracks.push({
track: event.track,
stream: eventStream
})
if (this._remoteStreams.some(remoteStream => {
return remoteStream.id === eventStream.id
})) return // Only fire one 'stream' event, even though there may be multiple tracks per stream
this._remoteStreams.push(eventStream)
queueMicrotask(() => {
this._debug('on stream')
this.emit('stream', eventStream) // ensure all tracks have been added
})
})
}
_debug () {
const args = [].slice.call(arguments)
args[0] = '[' + this._id + '] ' + args[0]
debug.apply(null, args)
}
}
Peer.WEBRTC_SUPPORT = !!getBrowserRTC()
/**
* Expose peer and data channel config for overriding all Peer
* instances. Otherwise, just set opts.config or opts.channelConfig
* when constructing a Peer.
*/
Peer.config = {
iceServers: [
{
urls: [
'stun:stun.l.google.com:19302',
'stun:global.stun.twilio.com:3478'
]
}
],
sdpSemantics: 'unified-plan'
}
Peer.channelConfig = {}
module.exports = Peer
},{"buffer":60,"debug":224,"err-code":97,"get-browser-rtc":115,"queue-microtask":193,"randombytes":195,"readable-stream":241}],224:[function(require,module,exports){
arguments[4][13][0].apply(exports,arguments)
},{"./common":225,"_process":187,"dup":13}],225:[function(require,module,exports){
arguments[4][14][0].apply(exports,arguments)
},{"dup":14,"ms":226}],226:[function(require,module,exports){
arguments[4][15][0].apply(exports,arguments)
},{"dup":15}],227:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],228:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":230,"./_stream_writable":232,"_process":187,"dup":17,"inherits":119}],229:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":231,"dup":18,"inherits":119}],230:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":227,"./_stream_duplex":228,"./internal/streams/async_iterator":233,"./internal/streams/buffer_list":234,"./internal/streams/destroy":235,"./internal/streams/from":237,"./internal/streams/state":239,"./internal/streams/stream":240,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],231:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":227,"./_stream_duplex":228,"dup":20,"inherits":119}],232:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":227,"./_stream_duplex":228,"./internal/streams/destroy":235,"./internal/streams/state":239,"./internal/streams/stream":240,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],233:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":236,"_process":187,"dup":22}],234:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],235:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],236:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":227,"dup":25}],237:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],238:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":227,"./end-of-stream":236,"dup":27}],239:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":227,"dup":28}],240:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],241:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":228,"./lib/_stream_passthrough.js":229,"./lib/_stream_readable.js":230,"./lib/_stream_transform.js":231,"./lib/_stream_writable.js":232,"./lib/internal/streams/end-of-stream.js":236,"./lib/internal/streams/pipeline.js":238,"dup":30}],242:[function(require,module,exports){
/* global self */
var Rusha = require('rusha')
var rushaWorkerSha1 = require('./rusha-worker-sha1')
var rusha = new Rusha()
var scope = typeof window !== 'undefined' ? window : self
var crypto = scope.crypto || scope.msCrypto || {}
var subtle = crypto.subtle || crypto.webkitSubtle
function sha1sync (buf) {
return rusha.digest(buf)
}
// Browsers throw if they lack support for an algorithm.
// Promise will be rejected on non-secure origins. (http://goo.gl/lq4gCo)
try {
subtle.digest({ name: 'sha-1' }, new Uint8Array()).catch(function () {
subtle = false
})
} catch (err) { subtle = false }
function sha1 (buf, cb) {
if (!subtle) {
if (typeof window !== 'undefined') {
rushaWorkerSha1(buf, function onRushaWorkerSha1 (err, hash) {
if (err) {
// On error, fallback to synchronous method which cannot fail
cb(sha1sync(buf))
return
}
cb(hash)
})
} else {
queueMicrotask(() => cb(sha1sync(buf)))
}
return
}
if (typeof buf === 'string') {
buf = uint8array(buf)
}
subtle.digest({ name: 'sha-1' }, buf)
.then(function succeed (result) {
cb(hex(new Uint8Array(result)))
},
function fail () {
// On error, fallback to synchronous method which cannot fail
cb(sha1sync(buf))
})
}
function uint8array (s) {
var l = s.length
var array = new Uint8Array(l)
for (var i = 0; i < l; i++) {
array[i] = s.charCodeAt(i)
}
return array
}
function hex (buf) {
var l = buf.length
var chars = []
for (var i = 0; i < l; i++) {
var bite = buf[i]
chars.push((bite >>> 4).toString(16))
chars.push((bite & 0x0f).toString(16))
}
return chars.join('')
}
module.exports = sha1
module.exports.sync = sha1sync
},{"./rusha-worker-sha1":243,"rusha":219}],243:[function(require,module,exports){
var Rusha = require('rusha')
var worker
var nextTaskId
var cbs
function init () {
worker = Rusha.createWorker()
nextTaskId = 1
cbs = {} // taskId -> cb
worker.onmessage = function onRushaMessage (e) {
var taskId = e.data.id
var cb = cbs[taskId]
delete cbs[taskId]
if (e.data.error != null) {
cb(new Error('Rusha worker error: ' + e.data.error))
} else {
cb(null, e.data.hash)
}
}
}
function sha1 (buf, cb) {
if (!worker) init()
cbs[nextTaskId] = cb
worker.postMessage({ id: nextTaskId, data: buf })
nextTaskId += 1
}
module.exports = sha1
},{"rusha":219}],244:[function(require,module,exports){
(function (Buffer){(function (){
/* global WebSocket, DOMException */
const debug = require('debug')('simple-websocket')
const randombytes = require('randombytes')
const stream = require('readable-stream')
const queueMicrotask = require('queue-microtask') // TODO: remove when Node 10 is not supported
const ws = require('ws') // websockets in node - will be empty object in browser
const _WebSocket = typeof ws !== 'function' ? WebSocket : ws
const MAX_BUFFERED_AMOUNT = 64 * 1024
/**
* WebSocket. Same API as node core `net.Socket`. Duplex stream.
* @param {Object} opts
* @param {string=} opts.url websocket server url
* @param {string=} opts.socket raw websocket instance to wrap
*/
class Socket extends stream.Duplex {
constructor (opts = {}) {
// Support simple usage: `new Socket(url)`
if (typeof opts === 'string') {
opts = { url: opts }
}
opts = Object.assign({
allowHalfOpen: false
}, opts)
super(opts)
if (opts.url == null && opts.socket == null) {
throw new Error('Missing required `url` or `socket` option')
}
if (opts.url != null && opts.socket != null) {
throw new Error('Must specify either `url` or `socket` option, not both')
}
this._id = randombytes(4).toString('hex').slice(0, 7)
this._debug('new websocket: %o', opts)
this.connected = false
this.destroyed = false
this._chunk = null
this._cb = null
this._interval = null
if (opts.socket) {
this.url = opts.socket.url
this._ws = opts.socket
this.connected = opts.socket.readyState === _WebSocket.OPEN
} else {
this.url = opts.url
try {
if (typeof ws === 'function') {
// `ws` package accepts options
this._ws = new _WebSocket(opts.url, opts)
} else {
this._ws = new _WebSocket(opts.url)
}
} catch (err) {
queueMicrotask(() => this.destroy(err))
return
}
}
this._ws.binaryType = 'arraybuffer'
this._ws.onopen = () => {
this._onOpen()
}
this._ws.onmessage = event => {
this._onMessage(event)
}
this._ws.onclose = () => {
this._onClose()
}
this._ws.onerror = () => {
this.destroy(new Error('connection error to ' + this.url))
}
this._onFinishBound = () => {
this._onFinish()
}
this.once('finish', this._onFinishBound)
}
/**
* Send text/binary data to the WebSocket server.
* @param {TypedArrayView|ArrayBuffer|Buffer|string|Blob|Object} chunk
*/
send (chunk) {
this._ws.send(chunk)
}
// TODO: Delete this method once readable-stream is updated to contain a default
// implementation of destroy() that automatically calls _destroy()
// See: https://github.com/nodejs/readable-stream/issues/283
destroy (err) {
this._destroy(err, () => {})
}
_destroy (err, cb) {
if (this.destroyed) return
this._debug('destroy (error: %s)', err && (err.message || err))
this.readable = this.writable = false
if (!this._readableState.ended) this.push(null)
if (!this._writableState.finished) this.end()
this.connected = false
this.destroyed = true
clearInterval(this._interval)
this._interval = null
this._chunk = null
this._cb = null
if (this._onFinishBound) this.removeListener('finish', this._onFinishBound)
this._onFinishBound = null
if (this._ws) {
const ws = this._ws
const onClose = () => {
ws.onclose = null
}
if (ws.readyState === _WebSocket.CLOSED) {
onClose()
} else {
try {
ws.onclose = onClose
ws.close()
} catch (err) {
onClose()
}
}
ws.onopen = null
ws.onmessage = null
ws.onerror = () => {}
}
this._ws = null
if (err) {
if (typeof DOMException !== 'undefined' && err instanceof DOMException) {
// Convert Edge DOMException object to Error object
const code = err.code
err = new Error(err.message)
err.code = code
}
this.emit('error', err)
}
this.emit('close')
cb()
}
_read () {}
_write (chunk, encoding, cb) {
if (this.destroyed) return cb(new Error('cannot write after socket is destroyed'))
if (this.connected) {
try {
this.send(chunk)
} catch (err) {
return this.destroy(err)
}
if (typeof ws !== 'function' && this._ws.bufferedAmount > MAX_BUFFERED_AMOUNT) {
this._debug('start backpressure: bufferedAmount %d', this._ws.bufferedAmount)
this._cb = cb
} else {
cb(null)
}
} else {
this._debug('write before connect')
this._chunk = chunk
this._cb = cb
}
}
// When stream finishes writing, close socket. Half open connections are not
// supported.
_onFinish () {
if (this.destroyed) return
// Wait a bit before destroying so the socket flushes.
// TODO: is there a more reliable way to accomplish this?
const destroySoon = () => {
setTimeout(() => this.destroy(), 1000)
}
if (this.connected) {
destroySoon()
} else {
this.once('connect', destroySoon)
}
}
_onMessage (event) {
if (this.destroyed) return
let data = event.data
if (data instanceof ArrayBuffer) data = Buffer.from(data)
this.push(data)
}
_onOpen () {
if (this.connected || this.destroyed) return
this.connected = true
if (this._chunk) {
try {
this.send(this._chunk)
} catch (err) {
return this.destroy(err)
}
this._chunk = null
this._debug('sent chunk from "write before connect"')
const cb = this._cb
this._cb = null
cb(null)
}
// Backpressure is not implemented in Node.js. The `ws` module has a buggy
// `bufferedAmount` property. See: https://github.com/websockets/ws/issues/492
if (typeof ws !== 'function') {
this._interval = setInterval(() => this._onInterval(), 150)
if (this._interval.unref) this._interval.unref()
}
this._debug('connect')
this.emit('connect')
}
_onInterval () {
if (!this._cb || !this._ws || this._ws.bufferedAmount > MAX_BUFFERED_AMOUNT) {
return
}
this._debug('ending backpressure: bufferedAmount %d', this._ws.bufferedAmount)
const cb = this._cb
this._cb = null
cb(null)
}
_onClose () {
if (this.destroyed) return
this._debug('on close')
this.destroy()
}
_debug () {
const args = [].slice.call(arguments)
args[0] = '[' + this._id + '] ' + args[0]
debug.apply(null, args)
}
}
Socket.WEBSOCKET_SUPPORT = !!_WebSocket
module.exports = Socket
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60,"debug":245,"queue-microtask":193,"randombytes":195,"readable-stream":262,"ws":55}],245:[function(require,module,exports){
arguments[4][13][0].apply(exports,arguments)
},{"./common":246,"_process":187,"dup":13}],246:[function(require,module,exports){
arguments[4][14][0].apply(exports,arguments)
},{"dup":14,"ms":247}],247:[function(require,module,exports){
arguments[4][15][0].apply(exports,arguments)
},{"dup":15}],248:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],249:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":251,"./_stream_writable":253,"_process":187,"dup":17,"inherits":119}],250:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":252,"dup":18,"inherits":119}],251:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":248,"./_stream_duplex":249,"./internal/streams/async_iterator":254,"./internal/streams/buffer_list":255,"./internal/streams/destroy":256,"./internal/streams/from":258,"./internal/streams/state":260,"./internal/streams/stream":261,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],252:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":248,"./_stream_duplex":249,"dup":20,"inherits":119}],253:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":248,"./_stream_duplex":249,"./internal/streams/destroy":256,"./internal/streams/state":260,"./internal/streams/stream":261,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],254:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":257,"_process":187,"dup":22}],255:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],256:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],257:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":248,"dup":25}],258:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],259:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":248,"./end-of-stream":257,"dup":27}],260:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":248,"dup":28}],261:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],262:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":249,"./lib/_stream_passthrough.js":250,"./lib/_stream_readable.js":251,"./lib/_stream_transform.js":252,"./lib/_stream_writable.js":253,"./lib/internal/streams/end-of-stream.js":257,"./lib/internal/streams/pipeline.js":259,"dup":30}],263:[function(require,module,exports){
var tick = 1
var maxTick = 65535
var resolution = 4
var timer
var inc = function () {
tick = (tick + 1) & maxTick
}
module.exports = function (seconds) {
if (!timer) {
timer = setInterval(inc, (1000 / resolution) | 0)
if (timer.unref) timer.unref()
}
var size = resolution * (seconds || 5)
var buffer = [0]
var pointer = 1
var last = (tick - 1) & maxTick
return function (delta) {
var dist = (tick - last) & maxTick
if (dist > size) dist = size
last = tick
while (dist--) {
if (pointer === size) pointer = 0
buffer[pointer] = buffer[pointer === 0 ? size - 1 : pointer - 1]
pointer++
}
if (delta) buffer[pointer - 1] += delta
var top = buffer[pointer - 1]
var btm = buffer.length < size ? 0 : buffer[pointer === size ? 0 : pointer]
return buffer.length < resolution ? top : (top - btm) * resolution / buffer.length
}
}
},{}],264:[function(require,module,exports){
(function (global){(function (){
var ClientRequest = require('./lib/request')
var response = 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 = response.IncomingMessage
http.Agent = function () {}
http.Agent.defaultMaxSockets = 4
http.globalAgent = new http.Agent()
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)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./lib/request":266,"./lib/response":267,"builtin-status-codes":61,"url":299,"xtend":336}],265:[function(require,module,exports){
(function (global){(function (){
exports.fetch = isFunction(global.fetch) && isFunction(global.ReadableStream)
exports.writableStream = isFunction(global.WritableStream)
exports.abortController = isFunction(global.AbortController)
// 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
}
// If fetch is supported, then arraybuffer will be supported too. Skip calling
// checkTypeSupport(), since that calls getXHR().
exports.arraybuffer = exports.fetch || 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 && checkTypeSupport('ms-stream')
exports.mozchunkedarraybuffer = !exports.fetch && 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)
function isFunction (value) {
return typeof value === 'function'
}
xhr = null // Help gc
}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],266:[function(require,module,exports){
(function (process,global,Buffer){(function (){
var capability = require('./capability')
var inherits = require('inherits')
var response = require('./response')
var stream = require('readable-stream')
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 {
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 ' + Buffer.from(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._fetchTimer = null
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') {
body = new Blob(self._body, {
type: (headersObj['content-type'] || {}).value || ''
});
}
// 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) {
self._fetchTimer = 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) {
global.clearTimeout(self._fetchTimer)
if (!self._destroyed)
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
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._fetchTimer)
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
global.clearTimeout(self._fetchTimer)
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',
'via'
]
}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
},{"./capability":265,"./response":267,"_process":187,"buffer":60,"inherits":119,"readable-stream":282}],267:[function(require,module,exports){
(function (process,global,Buffer){(function (){
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, fetchTimer) {
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) {
reject()
} else if(self.push(Buffer.from(chunk))) {
resolve()
} else {
self._resumeFetch = resolve
}
})
},
close: function () {
global.clearTimeout(fetchTimer)
if (!self._destroyed)
self.push(null)
},
abort: function (err) {
if (!self._destroyed)
self.emit('error', err)
}
})
try {
response.body.pipeTo(writable).catch(function (err) {
global.clearTimeout(fetchTimer)
if (!self._destroyed)
self.emit('error', err)
})
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) {
global.clearTimeout(fetchTimer)
self.push(null)
return
}
self.push(Buffer.from(result.value))
read()
}).catch(function (err) {
global.clearTimeout(fetchTimer)
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':
response = xhr.responseText
if (response.length > self._pos) {
var newData = response.substr(self._pos)
if (self._charset === 'x-user-defined') {
var buffer = Buffer.alloc(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(Buffer.from(new Uint8Array(response)))
break
case 'moz-chunked-arraybuffer': // take whole
response = xhr.response
if (xhr.readyState !== rStates.LOADING || !response)
break
self.push(Buffer.from(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(Buffer.from(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)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
},{"./capability":265,"_process":187,"buffer":60,"inherits":119,"readable-stream":282}],268:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],269:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":271,"./_stream_writable":273,"_process":187,"dup":17,"inherits":119}],270:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":272,"dup":18,"inherits":119}],271:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":268,"./_stream_duplex":269,"./internal/streams/async_iterator":274,"./internal/streams/buffer_list":275,"./internal/streams/destroy":276,"./internal/streams/from":278,"./internal/streams/state":280,"./internal/streams/stream":281,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],272:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":268,"./_stream_duplex":269,"dup":20,"inherits":119}],273:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":268,"./_stream_duplex":269,"./internal/streams/destroy":276,"./internal/streams/state":280,"./internal/streams/stream":281,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],274:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":277,"_process":187,"dup":22}],275:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],276:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],277:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":268,"dup":25}],278:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],279:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":268,"./end-of-stream":277,"dup":27}],280:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":268,"dup":28}],281:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],282:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":269,"./lib/_stream_passthrough.js":270,"./lib/_stream_readable.js":271,"./lib/_stream_transform.js":272,"./lib/_stream_writable.js":273,"./lib/internal/streams/end-of-stream.js":277,"./lib/internal/streams/pipeline.js":279,"dup":30}],283:[function(require,module,exports){
/*! stream-to-blob-url. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
module.exports = getBlobURL
const getBlob = require('stream-to-blob')
async function getBlobURL (stream, mimeType) {
const blob = await getBlob(stream, mimeType)
const url = URL.createObjectURL(blob)
return url
}
},{"stream-to-blob":284}],284:[function(require,module,exports){
/*! stream-to-blob. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/* global Blob */
module.exports = streamToBlob
function streamToBlob (stream, mimeType) {
if (mimeType != null && typeof mimeType !== 'string') {
throw new Error('Invalid mimetype, expected string.')
}
return new Promise((resolve, reject) => {
const chunks = []
stream
.on('data', chunk => chunks.push(chunk))
.once('end', () => {
const blob = mimeType != null
? new Blob(chunks, { type: mimeType })
: new Blob(chunks)
resolve(blob)
})
.once('error', reject)
})
}
},{}],285:[function(require,module,exports){
(function (Buffer){(function (){
/*! stream-with-known-length-to-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
var once = require('once')
module.exports = function getBuffer (stream, length, cb) {
cb = once(cb)
var buf = Buffer.alloc(length)
var offset = 0
stream
.on('data', function (chunk) {
chunk.copy(buf, offset)
offset += chunk.length
})
.on('end', function () { cb(null, buf) })
.on('error', cb)
}
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60,"once":183}],286:[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';
/*<replacement>*/
var Buffer = require('safe-buffer').Buffer;
/*</replacement>*/
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. If an invalid byte is detected, -2 is returned.
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 byte >> 6 === 0x02 ? -1 : -2;
}
// 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 || nb === -2) return 0;
nb = utf8CheckByte(buf[j]);
if (nb >= 0) {
if (nb > 0) self.lastNeed = nb - 2;
return nb;
}
if (--j < i || nb === -2) 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
// a single UTF-8 replacement character ('\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';
}
if (self.lastNeed > 1 && buf.length > 1) {
if ((buf[1] & 0xC0) !== 0x80) {
self.lastNeed = 1;
return '\ufffd';
}
if (self.lastNeed > 2 && buf.length > 2) {
if ((buf[2] & 0xC0) !== 0x80) {
self.lastNeed = 2;
return '\ufffd';
}
}
}
}
// 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 is added when ending on a partial
// character.
function utf8End(buf) {
var r = buf && buf.length ? this.write(buf) : '';
if (this.lastNeed) return r + '\ufffd';
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":220}],287:[function(require,module,exports){
/*
Copyright (c) 2011, Chris Umbel
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 base32 = require('./thirty-two');
exports.encode = base32.encode;
exports.decode = base32.decode;
},{"./thirty-two":288}],288:[function(require,module,exports){
(function (Buffer){(function (){
/*
Copyright (c) 2011, Chris Umbel
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 charTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
var byteTable = [
0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff
];
function quintetCount(buff) {
var quintets = Math.floor(buff.length / 5);
return buff.length % 5 === 0 ? quintets: quintets + 1;
}
exports.encode = function(plain) {
if(!Buffer.isBuffer(plain)){
plain = new Buffer(plain);
}
var i = 0;
var j = 0;
var shiftIndex = 0;
var digit = 0;
var encoded = new Buffer(quintetCount(plain) * 8);
/* byte by byte isn't as pretty as quintet by quintet but tests a bit
faster. will have to revisit. */
while(i < plain.length) {
var current = plain[i];
if(shiftIndex > 3) {
digit = current & (0xff >> shiftIndex);
shiftIndex = (shiftIndex + 5) % 8;
digit = (digit << shiftIndex) | ((i + 1 < plain.length) ?
plain[i + 1] : 0) >> (8 - shiftIndex);
i++;
} else {
digit = (current >> (8 - (shiftIndex + 5))) & 0x1f;
shiftIndex = (shiftIndex + 5) % 8;
if(shiftIndex === 0) i++;
}
encoded[j] = charTable.charCodeAt(digit);
j++;
}
for(i = j; i < encoded.length; i++) {
encoded[i] = 0x3d; //'='.charCodeAt(0)
}
return encoded;
};
exports.decode = function(encoded) {
var shiftIndex = 0;
var plainDigit = 0;
var plainChar;
var plainPos = 0;
if(!Buffer.isBuffer(encoded)){
encoded = new Buffer(encoded);
}
var decoded = new Buffer(Math.ceil(encoded.length * 5 / 8));
/* byte by byte isn't as pretty as octet by octet but tests a bit
faster. will have to revisit. */
for(var i = 0; i < encoded.length; i++) {
if(encoded[i] === 0x3d){ //'='
break;
}
var encodedByte = encoded[i] - 0x30;
if(encodedByte < byteTable.length) {
plainDigit = byteTable[encodedByte];
if(shiftIndex <= 3) {
shiftIndex = (shiftIndex + 5) % 8;
if(shiftIndex === 0) {
plainChar |= plainDigit;
decoded[plainPos] = plainChar;
plainPos++;
plainChar = 0;
} else {
plainChar |= 0xff & (plainDigit << (8 - shiftIndex));
}
} else {
shiftIndex = (shiftIndex + 5) % 8;
plainChar |= 0xff & (plainDigit >>> shiftIndex);
decoded[plainPos] = plainChar;
plainPos++;
plainChar = 0xff & (plainDigit << (8 - shiftIndex));
}
} else {
throw new Error('Invalid input - it is not base32 encoded string');
}
}
return decoded.slice(0, plainPos);
};
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60}],289:[function(require,module,exports){
(function (process){(function (){
/**!
* tippy.js v6.2.7
* (c) 2017-2020 atomiks
* MIT License
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var core = require('@popperjs/core');
var ROUND_ARROW = '<svg width="16" height="6" xmlns="http://www.w3.org/2000/svg"><path d="M0 6s1.796-.013 4.67-3.615C5.851.9 6.93.006 8 0c1.07-.006 2.148.887 3.343 2.385C14.233 6.005 16 6 16 6H0z"></svg>';
var BOX_CLASS = "tippy-box";
var CONTENT_CLASS = "tippy-content";
var BACKDROP_CLASS = "tippy-backdrop";
var ARROW_CLASS = "tippy-arrow";
var SVG_ARROW_CLASS = "tippy-svg-arrow";
var TOUCH_OPTIONS = {
passive: true,
capture: true
};
function hasOwnProperty(obj, key) {
return {}.hasOwnProperty.call(obj, key);
}
function getValueAtIndexOrReturn(value, index, defaultValue) {
if (Array.isArray(value)) {
var v = value[index];
return v == null ? Array.isArray(defaultValue) ? defaultValue[index] : defaultValue : v;
}
return value;
}
function isType(value, type) {
var str = {}.toString.call(value);
return str.indexOf('[object') === 0 && str.indexOf(type + "]") > -1;
}
function invokeWithArgsOrReturn(value, args) {
return typeof value === 'function' ? value.apply(void 0, args) : value;
}
function debounce(fn, ms) {
// Avoid wrapping in `setTimeout` if ms is 0 anyway
if (ms === 0) {
return fn;
}
var timeout;
return function (arg) {
clearTimeout(timeout);
timeout = setTimeout(function () {
fn(arg);
}, ms);
};
}
function removeProperties(obj, keys) {
var clone = Object.assign({}, obj);
keys.forEach(function (key) {
delete clone[key];
});
return clone;
}
function splitBySpaces(value) {
return value.split(/\s+/).filter(Boolean);
}
function normalizeToArray(value) {
return [].concat(value);
}
function pushIfUnique(arr, value) {
if (arr.indexOf(value) === -1) {
arr.push(value);
}
}
function unique(arr) {
return arr.filter(function (item, index) {
return arr.indexOf(item) === index;
});
}
function getBasePlacement(placement) {
return placement.split('-')[0];
}
function arrayFrom(value) {
return [].slice.call(value);
}
function removeUndefinedProps(obj) {
return Object.keys(obj).reduce(function (acc, key) {
if (obj[key] !== undefined) {
acc[key] = obj[key];
}
return acc;
}, {});
}
function div() {
return document.createElement('div');
}
function isElement(value) {
return ['Element', 'Fragment'].some(function (type) {
return isType(value, type);
});
}
function isNodeList(value) {
return isType(value, 'NodeList');
}
function isMouseEvent(value) {
return isType(value, 'MouseEvent');
}
function isReferenceElement(value) {
return !!(value && value._tippy && value._tippy.reference === value);
}
function getArrayOfElements(value) {
if (isElement(value)) {
return [value];
}
if (isNodeList(value)) {
return arrayFrom(value);
}
if (Array.isArray(value)) {
return value;
}
return arrayFrom(document.querySelectorAll(value));
}
function setTransitionDuration(els, value) {
els.forEach(function (el) {
if (el) {
el.style.transitionDuration = value + "ms";
}
});
}
function setVisibilityState(els, state) {
els.forEach(function (el) {
if (el) {
el.setAttribute('data-state', state);
}
});
}
function getOwnerDocument(elementOrElements) {
var _normalizeToArray = normalizeToArray(elementOrElements),
element = _normalizeToArray[0];
return element ? element.ownerDocument || document : document;
}
function isCursorOutsideInteractiveBorder(popperTreeData, event) {
var clientX = event.clientX,
clientY = event.clientY;
return popperTreeData.every(function (_ref) {
var popperRect = _ref.popperRect,
popperState = _ref.popperState,
props = _ref.props;
var interactiveBorder = props.interactiveBorder;
var basePlacement = getBasePlacement(popperState.placement);
var offsetData = popperState.modifiersData.offset;
if (!offsetData) {
return true;
}
var topDistance = basePlacement === 'bottom' ? offsetData.top.y : 0;
var bottomDistance = basePlacement === 'top' ? offsetData.bottom.y : 0;
var leftDistance = basePlacement === 'right' ? offsetData.left.x : 0;
var rightDistance = basePlacement === 'left' ? offsetData.right.x : 0;
var exceedsTop = popperRect.top - clientY + topDistance > interactiveBorder;
var exceedsBottom = clientY - popperRect.bottom - bottomDistance > interactiveBorder;
var exceedsLeft = popperRect.left - clientX + leftDistance > interactiveBorder;
var exceedsRight = clientX - popperRect.right - rightDistance > interactiveBorder;
return exceedsTop || exceedsBottom || exceedsLeft || exceedsRight;
});
}
function updateTransitionEndListener(box, action, listener) {
var method = action + "EventListener"; // some browsers apparently support `transition` (unprefixed) but only fire
// `webkitTransitionEnd`...
['transitionend', 'webkitTransitionEnd'].forEach(function (event) {
box[method](event, listener);
});
}
var currentInput = {
isTouch: false
};
var lastMouseMoveTime = 0;
/**
* When a `touchstart` event is fired, it's assumed the user is using touch
* input. We'll bind a `mousemove` event listener to listen for mouse input in
* the future. This way, the `isTouch` property is fully dynamic and will handle
* hybrid devices that use a mix of touch + mouse input.
*/
function onDocumentTouchStart() {
if (currentInput.isTouch) {
return;
}
currentInput.isTouch = true;
if (window.performance) {
document.addEventListener('mousemove', onDocumentMouseMove);
}
}
/**
* When two `mousemove` event are fired consecutively within 20ms, it's assumed
* the user is using mouse input again. `mousemove` can fire on touch devices as
* well, but very rarely that quickly.
*/
function onDocumentMouseMove() {
var now = performance.now();
if (now - lastMouseMoveTime < 20) {
currentInput.isTouch = false;
document.removeEventListener('mousemove', onDocumentMouseMove);
}
lastMouseMoveTime = now;
}
/**
* When an element is in focus and has a tippy, leaving the tab/window and
* returning causes it to show again. For mouse users this is unexpected, but
* for keyboard use it makes sense.
* TODO: find a better technique to solve this problem
*/
function onWindowBlur() {
var activeElement = document.activeElement;
if (isReferenceElement(activeElement)) {
var instance = activeElement._tippy;
if (activeElement.blur && !instance.state.isVisible) {
activeElement.blur();
}
}
}
function bindGlobalEventListeners() {
document.addEventListener('touchstart', onDocumentTouchStart, TOUCH_OPTIONS);
window.addEventListener('blur', onWindowBlur);
}
var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
var ua = isBrowser ? navigator.userAgent : '';
var isIE = /MSIE |Trident\//.test(ua);
function createMemoryLeakWarning(method) {
var txt = method === 'destroy' ? 'n already-' : ' ';
return [method + "() was called on a" + txt + "destroyed instance. This is a no-op but", 'indicates a potential memory leak.'].join(' ');
}
function clean(value) {
var spacesAndTabs = /[ \t]{2,}/g;
var lineStartWithSpaces = /^[ \t]*/gm;
return value.replace(spacesAndTabs, ' ').replace(lineStartWithSpaces, '').trim();
}
function getDevMessage(message) {
return clean("\n %ctippy.js\n\n %c" + clean(message) + "\n\n %c\uD83D\uDC77\u200D This is a development-only message. It will be removed in production.\n ");
}
function getFormattedMessage(message) {
return [getDevMessage(message), // title
'color: #00C584; font-size: 1.3em; font-weight: bold;', // message
'line-height: 1.5', // footer
'color: #a6a095;'];
} // Assume warnings and errors never have the same message
var visitedMessages;
if (process.env.NODE_ENV !== "production") {
resetVisitedMessages();
}
function resetVisitedMessages() {
visitedMessages = new Set();
}
function warnWhen(condition, message) {
if (condition && !visitedMessages.has(message)) {
var _console;
visitedMessages.add(message);
(_console = console).warn.apply(_console, getFormattedMessage(message));
}
}
function errorWhen(condition, message) {
if (condition && !visitedMessages.has(message)) {
var _console2;
visitedMessages.add(message);
(_console2 = console).error.apply(_console2, getFormattedMessage(message));
}
}
function validateTargets(targets) {
var didPassFalsyValue = !targets;
var didPassPlainObject = Object.prototype.toString.call(targets) === '[object Object]' && !targets.addEventListener;
errorWhen(didPassFalsyValue, ['tippy() was passed', '`' + String(targets) + '`', 'as its targets (first) argument. Valid types are: String, Element,', 'Element[], or NodeList.'].join(' '));
errorWhen(didPassPlainObject, ['tippy() was passed a plain object which is not supported as an argument', 'for virtual positioning. Use props.getReferenceClientRect instead.'].join(' '));
}
var pluginProps = {
animateFill: false,
followCursor: false,
inlinePositioning: false,
sticky: false
};
var renderProps = {
allowHTML: false,
animation: 'fade',
arrow: true,
content: '',
inertia: false,
maxWidth: 350,
role: 'tooltip',
theme: '',
zIndex: 9999
};
var defaultProps = Object.assign({
appendTo: function appendTo() {
return document.body;
},
aria: {
content: 'auto',
expanded: 'auto'
},
delay: 0,
duration: [300, 250],
getReferenceClientRect: null,
hideOnClick: true,
ignoreAttributes: false,
interactive: false,
interactiveBorder: 2,
interactiveDebounce: 0,
moveTransition: '',
offset: [0, 10],
onAfterUpdate: function onAfterUpdate() {},
onBeforeUpdate: function onBeforeUpdate() {},
onCreate: function onCreate() {},
onDestroy: function onDestroy() {},
onHidden: function onHidden() {},
onHide: function onHide() {},
onMount: function onMount() {},
onShow: function onShow() {},
onShown: function onShown() {},
onTrigger: function onTrigger() {},
onUntrigger: function onUntrigger() {},
onClickOutside: function onClickOutside() {},
placement: 'top',
plugins: [],
popperOptions: {},
render: null,
showOnCreate: false,
touch: true,
trigger: 'mouseenter focus',
triggerTarget: null
}, pluginProps, {}, renderProps);
var defaultKeys = Object.keys(defaultProps);
var setDefaultProps = function setDefaultProps(partialProps) {
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
validateProps(partialProps, []);
}
var keys = Object.keys(partialProps);
keys.forEach(function (key) {
defaultProps[key] = partialProps[key];
});
};
function getExtendedPassedProps(passedProps) {
var plugins = passedProps.plugins || [];
var pluginProps = plugins.reduce(function (acc, plugin) {
var name = plugin.name,
defaultValue = plugin.defaultValue;
if (name) {
acc[name] = passedProps[name] !== undefined ? passedProps[name] : defaultValue;
}
return acc;
}, {});
return Object.assign({}, passedProps, {}, pluginProps);
}
function getDataAttributeProps(reference, plugins) {
var propKeys = plugins ? Object.keys(getExtendedPassedProps(Object.assign({}, defaultProps, {
plugins: plugins
}))) : defaultKeys;
var props = propKeys.reduce(function (acc, key) {
var valueAsString = (reference.getAttribute("data-tippy-" + key) || '').trim();
if (!valueAsString) {
return acc;
}
if (key === 'content') {
acc[key] = valueAsString;
} else {
try {
acc[key] = JSON.parse(valueAsString);
} catch (e) {
acc[key] = valueAsString;
}
}
return acc;
}, {});
return props;
}
function evaluateProps(reference, props) {
var out = Object.assign({}, props, {
content: invokeWithArgsOrReturn(props.content, [reference])
}, props.ignoreAttributes ? {} : getDataAttributeProps(reference, props.plugins));
out.aria = Object.assign({}, defaultProps.aria, {}, out.aria);
out.aria = {
expanded: out.aria.expanded === 'auto' ? props.interactive : out.aria.expanded,
content: out.aria.content === 'auto' ? props.interactive ? null : 'describedby' : out.aria.content
};
return out;
}
function validateProps(partialProps, plugins) {
if (partialProps === void 0) {
partialProps = {};
}
if (plugins === void 0) {
plugins = [];
}
var keys = Object.keys(partialProps);
keys.forEach(function (prop) {
var nonPluginProps = removeProperties(defaultProps, Object.keys(pluginProps));
var didPassUnknownProp = !hasOwnProperty(nonPluginProps, prop); // Check if the prop exists in `plugins`
if (didPassUnknownProp) {
didPassUnknownProp = plugins.filter(function (plugin) {
return plugin.name === prop;
}).length === 0;
}
warnWhen(didPassUnknownProp, ["`" + prop + "`", "is not a valid prop. You may have spelled it incorrectly, or if it's", 'a plugin, forgot to pass it in an array as props.plugins.', '\n\n', 'All props: https://atomiks.github.io/tippyjs/v6/all-props/\n', 'Plugins: https://atomiks.github.io/tippyjs/v6/plugins/'].join(' '));
});
}
var innerHTML = function innerHTML() {
return 'innerHTML';
};
function dangerouslySetInnerHTML(element, html) {
element[innerHTML()] = html;
}
function createArrowElement(value) {
var arrow = div();
if (value === true) {
arrow.className = ARROW_CLASS;
} else {
arrow.className = SVG_ARROW_CLASS;
if (isElement(value)) {
arrow.appendChild(value);
} else {
dangerouslySetInnerHTML(arrow, value);
}
}
return arrow;
}
function setContent(content, props) {
if (isElement(props.content)) {
dangerouslySetInnerHTML(content, '');
content.appendChild(props.content);
} else if (typeof props.content !== 'function') {
if (props.allowHTML) {
dangerouslySetInnerHTML(content, props.content);
} else {
content.textContent = props.content;
}
}
}
function getChildren(popper) {
var box = popper.firstElementChild;
var boxChildren = arrayFrom(box.children);
return {
box: box,
content: boxChildren.find(function (node) {
return node.classList.contains(CONTENT_CLASS);
}),
arrow: boxChildren.find(function (node) {
return node.classList.contains(ARROW_CLASS) || node.classList.contains(SVG_ARROW_CLASS);
}),
backdrop: boxChildren.find(function (node) {
return node.classList.contains(BACKDROP_CLASS);
})
};
}
function render(instance) {
var popper = div();
var box = div();
box.className = BOX_CLASS;
box.setAttribute('data-state', 'hidden');
box.setAttribute('tabindex', '-1');
var content = div();
content.className = CONTENT_CLASS;
content.setAttribute('data-state', 'hidden');
setContent(content, instance.props);
popper.appendChild(box);
box.appendChild(content);
onUpdate(instance.props, instance.props);
function onUpdate(prevProps, nextProps) {
var _getChildren = getChildren(popper),
box = _getChildren.box,
content = _getChildren.content,
arrow = _getChildren.arrow;
if (nextProps.theme) {
box.setAttribute('data-theme', nextProps.theme);
} else {
box.removeAttribute('data-theme');
}
if (typeof nextProps.animation === 'string') {
box.setAttribute('data-animation', nextProps.animation);
} else {
box.removeAttribute('data-animation');
}
if (nextProps.inertia) {
box.setAttribute('data-inertia', '');
} else {
box.removeAttribute('data-inertia');
}
box.style.maxWidth = typeof nextProps.maxWidth === 'number' ? nextProps.maxWidth + "px" : nextProps.maxWidth;
if (nextProps.role) {
box.setAttribute('role', nextProps.role);
} else {
box.removeAttribute('role');
}
if (prevProps.content !== nextProps.content || prevProps.allowHTML !== nextProps.allowHTML) {
setContent(content, instance.props);
}
if (nextProps.arrow) {
if (!arrow) {
box.appendChild(createArrowElement(nextProps.arrow));
} else if (prevProps.arrow !== nextProps.arrow) {
box.removeChild(arrow);
box.appendChild(createArrowElement(nextProps.arrow));
}
} else if (arrow) {
box.removeChild(arrow);
}
}
return {
popper: popper,
onUpdate: onUpdate
};
} // Runtime check to identify if the render function is the default one; this
// way we can apply default CSS transitions logic and it can be tree-shaken away
render.$$tippy = true;
var idCounter = 1;
var mouseMoveListeners = []; // Used by `hideAll()`
var mountedInstances = [];
function createTippy(reference, passedProps) {
var props = evaluateProps(reference, Object.assign({}, defaultProps, {}, getExtendedPassedProps(removeUndefinedProps(passedProps)))); // ===========================================================================
// 🔒 Private members
// ===========================================================================
var showTimeout;
var hideTimeout;
var scheduleHideAnimationFrame;
var isVisibleFromClick = false;
var didHideDueToDocumentMouseDown = false;
var didTouchMove = false;
var ignoreOnFirstUpdate = false;
var lastTriggerEvent;
var currentTransitionEndListener;
var onFirstUpdate;
var listeners = [];
var debouncedOnMouseMove = debounce(onMouseMove, props.interactiveDebounce);
var currentTarget; // ===========================================================================
// 🔑 Public members
// ===========================================================================
var id = idCounter++;
var popperInstance = null;
var plugins = unique(props.plugins);
var state = {
// Is the instance currently enabled?
isEnabled: true,
// Is the tippy currently showing and not transitioning out?
isVisible: false,
// Has the instance been destroyed?
isDestroyed: false,
// Is the tippy currently mounted to the DOM?
isMounted: false,
// Has the tippy finished transitioning in?
isShown: false
};
var instance = {
// properties
id: id,
reference: reference,
popper: div(),
popperInstance: popperInstance,
props: props,
state: state,
plugins: plugins,
// methods
clearDelayTimeouts: clearDelayTimeouts,
setProps: setProps,
setContent: setContent,
show: show,
hide: hide,
hideWithInteractivity: hideWithInteractivity,
enable: enable,
disable: disable,
unmount: unmount,
destroy: destroy
}; // TODO: Investigate why this early return causes a TDZ error in the tests —
// it doesn't seem to happen in the browser
/* istanbul ignore if */
if (!props.render) {
if (process.env.NODE_ENV !== "production") {
errorWhen(true, 'render() function has not been supplied.');
}
return instance;
} // ===========================================================================
// Initial mutations
// ===========================================================================
var _props$render = props.render(instance),
popper = _props$render.popper,
onUpdate = _props$render.onUpdate;
popper.setAttribute('data-tippy-root', '');
popper.id = "tippy-" + instance.id;
instance.popper = popper;
reference._tippy = instance;
popper._tippy = instance;
var pluginsHooks = plugins.map(function (plugin) {
return plugin.fn(instance);
});
var hasAriaExpanded = reference.hasAttribute('aria-expanded');
addListeners();
handleAriaExpandedAttribute();
handleStyles();
invokeHook('onCreate', [instance]);
if (props.showOnCreate) {
scheduleShow();
} // Prevent a tippy with a delay from hiding if the cursor left then returned
// before it started hiding
popper.addEventListener('mouseenter', function () {
if (instance.props.interactive && instance.state.isVisible) {
instance.clearDelayTimeouts();
}
});
popper.addEventListener('mouseleave', function (event) {
if (instance.props.interactive && instance.props.trigger.indexOf('mouseenter') >= 0) {
getDocument().addEventListener('mousemove', debouncedOnMouseMove);
debouncedOnMouseMove(event);
}
});
return instance; // ===========================================================================
// 🔒 Private methods
// ===========================================================================
function getNormalizedTouchSettings() {
var touch = instance.props.touch;
return Array.isArray(touch) ? touch : [touch, 0];
}
function getIsCustomTouchBehavior() {
return getNormalizedTouchSettings()[0] === 'hold';
}
function getIsDefaultRenderFn() {
var _instance$props$rende;
// @ts-ignore
return !!((_instance$props$rende = instance.props.render) == null ? void 0 : _instance$props$rende.$$tippy);
}
function getCurrentTarget() {
return currentTarget || reference;
}
function getDocument() {
var parent = getCurrentTarget().parentNode;
return parent ? getOwnerDocument(parent) : document;
}
function getDefaultTemplateChildren() {
return getChildren(popper);
}
function getDelay(isShow) {
// For touch or keyboard input, force `0` delay for UX reasons
// Also if the instance is mounted but not visible (transitioning out),
// ignore delay
if (instance.state.isMounted && !instance.state.isVisible || currentInput.isTouch || lastTriggerEvent && lastTriggerEvent.type === 'focus') {
return 0;
}
return getValueAtIndexOrReturn(instance.props.delay, isShow ? 0 : 1, defaultProps.delay);
}
function handleStyles() {
popper.style.pointerEvents = instance.props.interactive && instance.state.isVisible ? '' : 'none';
popper.style.zIndex = "" + instance.props.zIndex;
}
function invokeHook(hook, args, shouldInvokePropsHook) {
if (shouldInvokePropsHook === void 0) {
shouldInvokePropsHook = true;
}
pluginsHooks.forEach(function (pluginHooks) {
if (pluginHooks[hook]) {
pluginHooks[hook].apply(void 0, args);
}
});
if (shouldInvokePropsHook) {
var _instance$props;
(_instance$props = instance.props)[hook].apply(_instance$props, args);
}
}
function handleAriaContentAttribute() {
var aria = instance.props.aria;
if (!aria.content) {
return;
}
var attr = "aria-" + aria.content;
var id = popper.id;
var nodes = normalizeToArray(instance.props.triggerTarget || reference);
nodes.forEach(function (node) {
var currentValue = node.getAttribute(attr);
if (instance.state.isVisible) {
node.setAttribute(attr, currentValue ? currentValue + " " + id : id);
} else {
var nextValue = currentValue && currentValue.replace(id, '').trim();
if (nextValue) {
node.setAttribute(attr, nextValue);
} else {
node.removeAttribute(attr);
}
}
});
}
function handleAriaExpandedAttribute() {
if (hasAriaExpanded || !instance.props.aria.expanded) {
return;
}
var nodes = normalizeToArray(instance.props.triggerTarget || reference);
nodes.forEach(function (node) {
if (instance.props.interactive) {
node.setAttribute('aria-expanded', instance.state.isVisible && node === getCurrentTarget() ? 'true' : 'false');
} else {
node.removeAttribute('aria-expanded');
}
});
}
function cleanupInteractiveMouseListeners() {
getDocument().removeEventListener('mousemove', debouncedOnMouseMove);
mouseMoveListeners = mouseMoveListeners.filter(function (listener) {
return listener !== debouncedOnMouseMove;
});
}
function onDocumentPress(event) {
// Moved finger to scroll instead of an intentional tap outside
if (currentInput.isTouch) {
if (didTouchMove || event.type === 'mousedown') {
return;
}
} // Clicked on interactive popper
if (instance.props.interactive && popper.contains(event.target)) {
return;
} // Clicked on the event listeners target
if (getCurrentTarget().contains(event.target)) {
if (currentInput.isTouch) {
return;
}
if (instance.state.isVisible && instance.props.trigger.indexOf('click') >= 0) {
return;
}
} else {
invokeHook('onClickOutside', [instance, event]);
}
if (instance.props.hideOnClick === true) {
instance.clearDelayTimeouts();
instance.hide(); // `mousedown` event is fired right before `focus` if pressing the
// currentTarget. This lets a tippy with `focus` trigger know that it
// should not show
didHideDueToDocumentMouseDown = true;
setTimeout(function () {
didHideDueToDocumentMouseDown = false;
}); // The listener gets added in `scheduleShow()`, but this may be hiding it
// before it shows, and hide()'s early bail-out behavior can prevent it
// from being cleaned up
if (!instance.state.isMounted) {
removeDocumentPress();
}
}
}
function onTouchMove() {
didTouchMove = true;
}
function onTouchStart() {
didTouchMove = false;
}
function addDocumentPress() {
var doc = getDocument();
doc.addEventListener('mousedown', onDocumentPress, true);
doc.addEventListener('touchend', onDocumentPress, TOUCH_OPTIONS);
doc.addEventListener('touchstart', onTouchStart, TOUCH_OPTIONS);
doc.addEventListener('touchmove', onTouchMove, TOUCH_OPTIONS);
}
function removeDocumentPress() {
var doc = getDocument();
doc.removeEventListener('mousedown', onDocumentPress, true);
doc.removeEventListener('touchend', onDocumentPress, TOUCH_OPTIONS);
doc.removeEventListener('touchstart', onTouchStart, TOUCH_OPTIONS);
doc.removeEventListener('touchmove', onTouchMove, TOUCH_OPTIONS);
}
function onTransitionedOut(duration, callback) {
onTransitionEnd(duration, function () {
if (!instance.state.isVisible && popper.parentNode && popper.parentNode.contains(popper)) {
callback();
}
});
}
function onTransitionedIn(duration, callback) {
onTransitionEnd(duration, callback);
}
function onTransitionEnd(duration, callback) {
var box = getDefaultTemplateChildren().box;
function listener(event) {
if (event.target === box) {
updateTransitionEndListener(box, 'remove', listener);
callback();
}
} // Make callback synchronous if duration is 0
// `transitionend` won't fire otherwise
if (duration === 0) {
return callback();
}
updateTransitionEndListener(box, 'remove', currentTransitionEndListener);
updateTransitionEndListener(box, 'add', listener);
currentTransitionEndListener = listener;
}
function on(eventType, handler, options) {
if (options === void 0) {
options = false;
}
var nodes = normalizeToArray(instance.props.triggerTarget || reference);
nodes.forEach(function (node) {
node.addEventListener(eventType, handler, options);
listeners.push({
node: node,
eventType: eventType,
handler: handler,
options: options
});
});
}
function addListeners() {
if (getIsCustomTouchBehavior()) {
on('touchstart', onTrigger, {
passive: true
});
on('touchend', onMouseLeave, {
passive: true
});
}
splitBySpaces(instance.props.trigger).forEach(function (eventType) {
if (eventType === 'manual') {
return;
}
on(eventType, onTrigger);
switch (eventType) {
case 'mouseenter':
on('mouseleave', onMouseLeave);
break;
case 'focus':
on(isIE ? 'focusout' : 'blur', onBlurOrFocusOut);
break;
case 'focusin':
on('focusout', onBlurOrFocusOut);
break;
}
});
}
function removeListeners() {
listeners.forEach(function (_ref) {
var node = _ref.node,
eventType = _ref.eventType,
handler = _ref.handler,
options = _ref.options;
node.removeEventListener(eventType, handler, options);
});
listeners = [];
}
function onTrigger(event) {
var _lastTriggerEvent;
var shouldScheduleClickHide = false;
if (!instance.state.isEnabled || isEventListenerStopped(event) || didHideDueToDocumentMouseDown) {
return;
}
var wasFocused = ((_lastTriggerEvent = lastTriggerEvent) == null ? void 0 : _lastTriggerEvent.type) === 'focus';
lastTriggerEvent = event;
currentTarget = event.currentTarget;
handleAriaExpandedAttribute();
if (!instance.state.isVisible && isMouseEvent(event)) {
// If scrolling, `mouseenter` events can be fired if the cursor lands
// over a new target, but `mousemove` events don't get fired. This
// causes interactive tooltips to get stuck open until the cursor is
// moved
mouseMoveListeners.forEach(function (listener) {
return listener(event);
});
} // Toggle show/hide when clicking click-triggered tooltips
if (event.type === 'click' && (instance.props.trigger.indexOf('mouseenter') < 0 || isVisibleFromClick) && instance.props.hideOnClick !== false && instance.state.isVisible) {
shouldScheduleClickHide = true;
} else {
scheduleShow(event);
}
if (event.type === 'click') {
isVisibleFromClick = !shouldScheduleClickHide;
}
if (shouldScheduleClickHide && !wasFocused) {
scheduleHide(event);
}
}
function onMouseMove(event) {
var target = event.target;
var isCursorOverReferenceOrPopper = getCurrentTarget().contains(target) || popper.contains(target);
if (event.type === 'mousemove' && isCursorOverReferenceOrPopper) {
return;
}
var popperTreeData = getNestedPopperTree().concat(popper).map(function (popper) {
var _instance$popperInsta;
var instance = popper._tippy;
var state = (_instance$popperInsta = instance.popperInstance) == null ? void 0 : _instance$popperInsta.state;
if (state) {
return {
popperRect: popper.getBoundingClientRect(),
popperState: state,
props: props
};
}
return null;
}).filter(Boolean);
if (isCursorOutsideInteractiveBorder(popperTreeData, event)) {
cleanupInteractiveMouseListeners();
scheduleHide(event);
}
}
function onMouseLeave(event) {
var shouldBail = isEventListenerStopped(event) || instance.props.trigger.indexOf('click') >= 0 && isVisibleFromClick;
if (shouldBail) {
return;
}
if (instance.props.interactive) {
instance.hideWithInteractivity(event);
return;
}
scheduleHide(event);
}
function onBlurOrFocusOut(event) {
if (instance.props.trigger.indexOf('focusin') < 0 && event.target !== getCurrentTarget()) {
return;
} // If focus was moved to within the popper
if (instance.props.interactive && event.relatedTarget && popper.contains(event.relatedTarget)) {
return;
}
scheduleHide(event);
}
function isEventListenerStopped(event) {
return currentInput.isTouch ? getIsCustomTouchBehavior() !== event.type.indexOf('touch') >= 0 : false;
}
function createPopperInstance() {
destroyPopperInstance();
var _instance$props2 = instance.props,
popperOptions = _instance$props2.popperOptions,
placement = _instance$props2.placement,
offset = _instance$props2.offset,
getReferenceClientRect = _instance$props2.getReferenceClientRect,
moveTransition = _instance$props2.moveTransition;
var arrow = getIsDefaultRenderFn() ? getChildren(popper).arrow : null;
var computedReference = getReferenceClientRect ? {
getBoundingClientRect: getReferenceClientRect,
contextElement: getReferenceClientRect.contextElement || getCurrentTarget()
} : reference;
var tippyModifier = {
name: '$$tippy',
enabled: true,
phase: 'beforeWrite',
requires: ['computeStyles'],
fn: function fn(_ref2) {
var state = _ref2.state;
if (getIsDefaultRenderFn()) {
var _getDefaultTemplateCh = getDefaultTemplateChildren(),
box = _getDefaultTemplateCh.box;
['placement', 'reference-hidden', 'escaped'].forEach(function (attr) {
if (attr === 'placement') {
box.setAttribute('data-placement', state.placement);
} else {
if (state.attributes.popper["data-popper-" + attr]) {
box.setAttribute("data-" + attr, '');
} else {
box.removeAttribute("data-" + attr);
}
}
});
state.attributes.popper = {};
}
}
};
var modifiers = [{
name: 'offset',
options: {
offset: offset
}
}, {
name: 'preventOverflow',
options: {
padding: {
top: 2,
bottom: 2,
left: 5,
right: 5
}
}
}, {
name: 'flip',
options: {
padding: 5
}
}, {
name: 'computeStyles',
options: {
adaptive: !moveTransition
}
}, tippyModifier];
if (getIsDefaultRenderFn() && arrow) {
modifiers.push({
name: 'arrow',
options: {
element: arrow,
padding: 3
}
});
}
modifiers.push.apply(modifiers, (popperOptions == null ? void 0 : popperOptions.modifiers) || []);
instance.popperInstance = core.createPopper(computedReference, popper, Object.assign({}, popperOptions, {
placement: placement,
onFirstUpdate: onFirstUpdate,
modifiers: modifiers
}));
}
function destroyPopperInstance() {
if (instance.popperInstance) {
instance.popperInstance.destroy();
instance.popperInstance = null;
}
}
function mount() {
var appendTo = instance.props.appendTo;
var parentNode; // By default, we'll append the popper to the triggerTargets's parentNode so
// it's directly after the reference element so the elements inside the
// tippy can be tabbed to
// If there are clipping issues, the user can specify a different appendTo
// and ensure focus management is handled correctly manually
var node = getCurrentTarget();
if (instance.props.interactive && appendTo === defaultProps.appendTo || appendTo === 'parent') {
parentNode = node.parentNode;
} else {
parentNode = invokeWithArgsOrReturn(appendTo, [node]);
} // The popper element needs to exist on the DOM before its position can be
// updated as Popper needs to read its dimensions
if (!parentNode.contains(popper)) {
parentNode.appendChild(popper);
}
createPopperInstance();
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
// Accessibility check
warnWhen(instance.props.interactive && appendTo === defaultProps.appendTo && node.nextElementSibling !== popper, ['Interactive tippy element may not be accessible via keyboard', 'navigation because it is not directly after the reference element', 'in the DOM source order.', '\n\n', 'Using a wrapper <div> or <span> tag around the reference element', 'solves this by creating a new parentNode context.', '\n\n', 'Specifying `appendTo: document.body` silences this warning, but it', 'assumes you are using a focus management solution to handle', 'keyboard navigation.', '\n\n', 'See: https://atomiks.github.io/tippyjs/v6/accessibility/#interactivity'].join(' '));
}
}
function getNestedPopperTree() {
return arrayFrom(popper.querySelectorAll('[data-tippy-root]'));
}
function scheduleShow(event) {
instance.clearDelayTimeouts();
if (event) {
invokeHook('onTrigger', [instance, event]);
}
addDocumentPress();
var delay = getDelay(true);
var _getNormalizedTouchSe = getNormalizedTouchSettings(),
touchValue = _getNormalizedTouchSe[0],
touchDelay = _getNormalizedTouchSe[1];
if (currentInput.isTouch && touchValue === 'hold' && touchDelay) {
delay = touchDelay;
}
if (delay) {
showTimeout = setTimeout(function () {
instance.show();
}, delay);
} else {
instance.show();
}
}
function scheduleHide(event) {
instance.clearDelayTimeouts();
invokeHook('onUntrigger', [instance, event]);
if (!instance.state.isVisible) {
removeDocumentPress();
return;
} // For interactive tippies, scheduleHide is added to a document.body handler
// from onMouseLeave so must intercept scheduled hides from mousemove/leave
// events when trigger contains mouseenter and click, and the tip is
// currently shown as a result of a click.
if (instance.props.trigger.indexOf('mouseenter') >= 0 && instance.props.trigger.indexOf('click') >= 0 && ['mouseleave', 'mousemove'].indexOf(event.type) >= 0 && isVisibleFromClick) {
return;
}
var delay = getDelay(false);
if (delay) {
hideTimeout = setTimeout(function () {
if (instance.state.isVisible) {
instance.hide();
}
}, delay);
} else {
// Fixes a `transitionend` problem when it fires 1 frame too
// late sometimes, we don't want hide() to be called.
scheduleHideAnimationFrame = requestAnimationFrame(function () {
instance.hide();
});
}
} // ===========================================================================
// 🔑 Public methods
// ===========================================================================
function enable() {
instance.state.isEnabled = true;
}
function disable() {
// Disabling the instance should also hide it
// https://github.com/atomiks/tippy.js-react/issues/106
instance.hide();
instance.state.isEnabled = false;
}
function clearDelayTimeouts() {
clearTimeout(showTimeout);
clearTimeout(hideTimeout);
cancelAnimationFrame(scheduleHideAnimationFrame);
}
function setProps(partialProps) {
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('setProps'));
}
if (instance.state.isDestroyed) {
return;
}
invokeHook('onBeforeUpdate', [instance, partialProps]);
removeListeners();
var prevProps = instance.props;
var nextProps = evaluateProps(reference, Object.assign({}, instance.props, {}, partialProps, {
ignoreAttributes: true
}));
instance.props = nextProps;
addListeners();
if (prevProps.interactiveDebounce !== nextProps.interactiveDebounce) {
cleanupInteractiveMouseListeners();
debouncedOnMouseMove = debounce(onMouseMove, nextProps.interactiveDebounce);
} // Ensure stale aria-expanded attributes are removed
if (prevProps.triggerTarget && !nextProps.triggerTarget) {
normalizeToArray(prevProps.triggerTarget).forEach(function (node) {
node.removeAttribute('aria-expanded');
});
} else if (nextProps.triggerTarget) {
reference.removeAttribute('aria-expanded');
}
handleAriaExpandedAttribute();
handleStyles();
if (onUpdate) {
onUpdate(prevProps, nextProps);
}
if (instance.popperInstance) {
createPopperInstance(); // Fixes an issue with nested tippies if they are all getting re-rendered,
// and the nested ones get re-rendered first.
// https://github.com/atomiks/tippyjs-react/issues/177
// TODO: find a cleaner / more efficient solution(!)
getNestedPopperTree().forEach(function (nestedPopper) {
// React (and other UI libs likely) requires a rAF wrapper as it flushes
// its work in one
requestAnimationFrame(nestedPopper._tippy.popperInstance.forceUpdate);
});
}
invokeHook('onAfterUpdate', [instance, partialProps]);
}
function setContent(content) {
instance.setProps({
content: content
});
}
function show() {
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('show'));
} // Early bail-out
var isAlreadyVisible = instance.state.isVisible;
var isDestroyed = instance.state.isDestroyed;
var isDisabled = !instance.state.isEnabled;
var isTouchAndTouchDisabled = currentInput.isTouch && !instance.props.touch;
var duration = getValueAtIndexOrReturn(instance.props.duration, 0, defaultProps.duration);
if (isAlreadyVisible || isDestroyed || isDisabled || isTouchAndTouchDisabled) {
return;
} // Normalize `disabled` behavior across browsers.
// Firefox allows events on disabled elements, but Chrome doesn't.
// Using a wrapper element (i.e. <span>) is recommended.
if (getCurrentTarget().hasAttribute('disabled')) {
return;
}
invokeHook('onShow', [instance], false);
if (instance.props.onShow(instance) === false) {
return;
}
instance.state.isVisible = true;
if (getIsDefaultRenderFn()) {
popper.style.visibility = 'visible';
}
handleStyles();
addDocumentPress();
if (!instance.state.isMounted) {
popper.style.transition = 'none';
} // If flipping to the opposite side after hiding at least once, the
// animation will use the wrong placement without resetting the duration
if (getIsDefaultRenderFn()) {
var _getDefaultTemplateCh2 = getDefaultTemplateChildren(),
box = _getDefaultTemplateCh2.box,
content = _getDefaultTemplateCh2.content;
setTransitionDuration([box, content], 0);
}
onFirstUpdate = function onFirstUpdate() {
if (!instance.state.isVisible || ignoreOnFirstUpdate) {
return;
}
ignoreOnFirstUpdate = true; // reflow
void popper.offsetHeight;
popper.style.transition = instance.props.moveTransition;
if (getIsDefaultRenderFn() && instance.props.animation) {
var _getDefaultTemplateCh3 = getDefaultTemplateChildren(),
_box = _getDefaultTemplateCh3.box,
_content = _getDefaultTemplateCh3.content;
setTransitionDuration([_box, _content], duration);
setVisibilityState([_box, _content], 'visible');
}
handleAriaContentAttribute();
handleAriaExpandedAttribute();
pushIfUnique(mountedInstances, instance);
instance.state.isMounted = true;
invokeHook('onMount', [instance]);
if (instance.props.animation && getIsDefaultRenderFn()) {
onTransitionedIn(duration, function () {
instance.state.isShown = true;
invokeHook('onShown', [instance]);
});
}
};
mount();
}
function hide() {
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('hide'));
} // Early bail-out
var isAlreadyHidden = !instance.state.isVisible;
var isDestroyed = instance.state.isDestroyed;
var isDisabled = !instance.state.isEnabled;
var duration = getValueAtIndexOrReturn(instance.props.duration, 1, defaultProps.duration);
if (isAlreadyHidden || isDestroyed || isDisabled) {
return;
}
invokeHook('onHide', [instance], false);
if (instance.props.onHide(instance) === false) {
return;
}
instance.state.isVisible = false;
instance.state.isShown = false;
ignoreOnFirstUpdate = false;
isVisibleFromClick = false;
if (getIsDefaultRenderFn()) {
popper.style.visibility = 'hidden';
}
cleanupInteractiveMouseListeners();
removeDocumentPress();
handleStyles();
if (getIsDefaultRenderFn()) {
var _getDefaultTemplateCh4 = getDefaultTemplateChildren(),
box = _getDefaultTemplateCh4.box,
content = _getDefaultTemplateCh4.content;
if (instance.props.animation) {
setTransitionDuration([box, content], duration);
setVisibilityState([box, content], 'hidden');
}
}
handleAriaContentAttribute();
handleAriaExpandedAttribute();
if (instance.props.animation) {
if (getIsDefaultRenderFn()) {
onTransitionedOut(duration, instance.unmount);
}
} else {
instance.unmount();
}
}
function hideWithInteractivity(event) {
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('hideWithInteractivity'));
}
getDocument().addEventListener('mousemove', debouncedOnMouseMove);
pushIfUnique(mouseMoveListeners, debouncedOnMouseMove);
debouncedOnMouseMove(event);
}
function unmount() {
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('unmount'));
}
if (instance.state.isVisible) {
instance.hide();
}
if (!instance.state.isMounted) {
return;
}
destroyPopperInstance(); // If a popper is not interactive, it will be appended outside the popper
// tree by default. This seems mainly for interactive tippies, but we should
// find a workaround if possible
getNestedPopperTree().forEach(function (nestedPopper) {
nestedPopper._tippy.unmount();
});
if (popper.parentNode) {
popper.parentNode.removeChild(popper);
}
mountedInstances = mountedInstances.filter(function (i) {
return i !== instance;
});
instance.state.isMounted = false;
invokeHook('onHidden', [instance]);
}
function destroy() {
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
warnWhen(instance.state.isDestroyed, createMemoryLeakWarning('destroy'));
}
if (instance.state.isDestroyed) {
return;
}
instance.clearDelayTimeouts();
instance.unmount();
removeListeners();
delete reference._tippy;
instance.state.isDestroyed = true;
invokeHook('onDestroy', [instance]);
}
}
function tippy(targets, optionalProps) {
if (optionalProps === void 0) {
optionalProps = {};
}
var plugins = defaultProps.plugins.concat(optionalProps.plugins || []);
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
validateTargets(targets);
validateProps(optionalProps, plugins);
}
bindGlobalEventListeners();
var passedProps = Object.assign({}, optionalProps, {
plugins: plugins
});
var elements = getArrayOfElements(targets);
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
var isSingleContentElement = isElement(passedProps.content);
var isMoreThanOneReferenceElement = elements.length > 1;
warnWhen(isSingleContentElement && isMoreThanOneReferenceElement, ['tippy() was passed an Element as the `content` prop, but more than', 'one tippy instance was created by this invocation. This means the', 'content element will only be appended to the last tippy instance.', '\n\n', 'Instead, pass the .innerHTML of the element, or use a function that', 'returns a cloned version of the element instead.', '\n\n', '1) content: element.innerHTML\n', '2) content: () => element.cloneNode(true)'].join(' '));
}
var instances = elements.reduce(function (acc, reference) {
var instance = reference && createTippy(reference, passedProps);
if (instance) {
acc.push(instance);
}
return acc;
}, []);
return isElement(targets) ? instances[0] : instances;
}
tippy.defaultProps = defaultProps;
tippy.setDefaultProps = setDefaultProps;
tippy.currentInput = currentInput;
var hideAll = function hideAll(_temp) {
var _ref = _temp === void 0 ? {} : _temp,
excludedReferenceOrInstance = _ref.exclude,
duration = _ref.duration;
mountedInstances.forEach(function (instance) {
var isExcluded = false;
if (excludedReferenceOrInstance) {
isExcluded = isReferenceElement(excludedReferenceOrInstance) ? instance.reference === excludedReferenceOrInstance : instance.popper === excludedReferenceOrInstance.popper;
}
if (!isExcluded) {
var originalDuration = instance.props.duration;
instance.setProps({
duration: duration
});
instance.hide();
if (!instance.state.isDestroyed) {
instance.setProps({
duration: originalDuration
});
}
}
});
};
var createSingleton = function createSingleton(tippyInstances, optionalProps) {
if (optionalProps === void 0) {
optionalProps = {};
}
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
errorWhen(!Array.isArray(tippyInstances), ['The first argument passed to createSingleton() must be an array of', 'tippy instances. The passed value was', String(tippyInstances)].join(' '));
}
var individualInstances = tippyInstances;
var references = [];
var currentTarget;
var overrides = optionalProps.overrides;
var interceptSetPropsCleanups = [];
function setReferences() {
references = individualInstances.map(function (instance) {
return instance.reference;
});
}
function enableInstances(isEnabled) {
individualInstances.forEach(function (instance) {
if (isEnabled) {
instance.enable();
} else {
instance.disable();
}
});
}
function interceptSetProps(singleton) {
return individualInstances.map(function (instance) {
var originalSetProps = instance.setProps;
instance.setProps = function (props) {
originalSetProps(props);
if (instance.reference === currentTarget) {
singleton.setProps(props);
}
};
return function () {
instance.setProps = originalSetProps;
};
});
}
enableInstances(false);
setReferences();
var plugin = {
fn: function fn() {
return {
onDestroy: function onDestroy() {
enableInstances(true);
},
onTrigger: function onTrigger(instance, event) {
var target = event.currentTarget;
var index = references.indexOf(target); // bail-out
if (target === currentTarget) {
return;
}
currentTarget = target;
var overrideProps = (overrides || []).concat('content').reduce(function (acc, prop) {
acc[prop] = individualInstances[index].props[prop];
return acc;
}, {});
instance.setProps(Object.assign({}, overrideProps, {
getReferenceClientRect: typeof overrideProps.getReferenceClientRect === 'function' ? overrideProps.getReferenceClientRect : function () {
return target.getBoundingClientRect();
}
}));
}
};
}
};
var singleton = tippy(div(), Object.assign({}, removeProperties(optionalProps, ['overrides']), {
plugins: [plugin].concat(optionalProps.plugins || []),
triggerTarget: references
}));
var originalSetProps = singleton.setProps;
singleton.setProps = function (props) {
overrides = props.overrides || overrides;
originalSetProps(props);
};
singleton.setInstances = function (nextInstances) {
enableInstances(true);
interceptSetPropsCleanups.forEach(function (fn) {
return fn();
});
individualInstances = nextInstances;
enableInstances(false);
setReferences();
interceptSetProps(singleton);
singleton.setProps({
triggerTarget: references
});
};
interceptSetPropsCleanups = interceptSetProps(singleton);
return singleton;
};
var BUBBLING_EVENTS_MAP = {
mouseover: 'mouseenter',
focusin: 'focus',
click: 'click'
};
/**
* Creates a delegate instance that controls the creation of tippy instances
* for child elements (`target` CSS selector).
*/
function delegate(targets, props) {
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
errorWhen(!(props && props.target), ['You must specity a `target` prop indicating a CSS selector string matching', 'the target elements that should receive a tippy.'].join(' '));
}
var listeners = [];
var childTippyInstances = [];
var disabled = false;
var target = props.target;
var nativeProps = removeProperties(props, ['target']);
var parentProps = Object.assign({}, nativeProps, {
trigger: 'manual',
touch: false
});
var childProps = Object.assign({}, nativeProps, {
showOnCreate: true
});
var returnValue = tippy(targets, parentProps);
var normalizedReturnValue = normalizeToArray(returnValue);
function onTrigger(event) {
if (!event.target || disabled) {
return;
}
var targetNode = event.target.closest(target);
if (!targetNode) {
return;
} // Get relevant trigger with fallbacks:
// 1. Check `data-tippy-trigger` attribute on target node
// 2. Fallback to `trigger` passed to `delegate()`
// 3. Fallback to `defaultProps.trigger`
var trigger = targetNode.getAttribute('data-tippy-trigger') || props.trigger || defaultProps.trigger; // @ts-ignore
if (targetNode._tippy) {
return;
}
if (event.type === 'touchstart' && typeof childProps.touch === 'boolean') {
return;
}
if (event.type !== 'touchstart' && trigger.indexOf(BUBBLING_EVENTS_MAP[event.type]) < 0) {
return;
}
var instance = tippy(targetNode, childProps);
if (instance) {
childTippyInstances = childTippyInstances.concat(instance);
}
}
function on(node, eventType, handler, options) {
if (options === void 0) {
options = false;
}
node.addEventListener(eventType, handler, options);
listeners.push({
node: node,
eventType: eventType,
handler: handler,
options: options
});
}
function addEventListeners(instance) {
var reference = instance.reference;
on(reference, 'touchstart', onTrigger);
on(reference, 'mouseover', onTrigger);
on(reference, 'focusin', onTrigger);
on(reference, 'click', onTrigger);
}
function removeEventListeners() {
listeners.forEach(function (_ref) {
var node = _ref.node,
eventType = _ref.eventType,
handler = _ref.handler,
options = _ref.options;
node.removeEventListener(eventType, handler, options);
});
listeners = [];
}
function applyMutations(instance) {
var originalDestroy = instance.destroy;
var originalEnable = instance.enable;
var originalDisable = instance.disable;
instance.destroy = function (shouldDestroyChildInstances) {
if (shouldDestroyChildInstances === void 0) {
shouldDestroyChildInstances = true;
}
if (shouldDestroyChildInstances) {
childTippyInstances.forEach(function (instance) {
instance.destroy();
});
}
childTippyInstances = [];
removeEventListeners();
originalDestroy();
};
instance.enable = function () {
originalEnable();
childTippyInstances.forEach(function (instance) {
return instance.enable();
});
disabled = false;
};
instance.disable = function () {
originalDisable();
childTippyInstances.forEach(function (instance) {
return instance.disable();
});
disabled = true;
};
addEventListeners(instance);
}
normalizedReturnValue.forEach(applyMutations);
return returnValue;
}
var animateFill = {
name: 'animateFill',
defaultValue: false,
fn: function fn(instance) {
var _instance$props$rende;
// @ts-ignore
if (!((_instance$props$rende = instance.props.render) == null ? void 0 : _instance$props$rende.$$tippy)) {
if (process.env.NODE_ENV !== "production") {
errorWhen(instance.props.animateFill, 'The `animateFill` plugin requires the default render function.');
}
return {};
}
var _getChildren = getChildren(instance.popper),
box = _getChildren.box,
content = _getChildren.content;
var backdrop = instance.props.animateFill ? createBackdropElement() : null;
return {
onCreate: function onCreate() {
if (backdrop) {
box.insertBefore(backdrop, box.firstElementChild);
box.setAttribute('data-animatefill', '');
box.style.overflow = 'hidden';
instance.setProps({
arrow: false,
animation: 'shift-away'
});
}
},
onMount: function onMount() {
if (backdrop) {
var transitionDuration = box.style.transitionDuration;
var duration = Number(transitionDuration.replace('ms', '')); // The content should fade in after the backdrop has mostly filled the
// tooltip element. `clip-path` is the other alternative but is not
// well-supported and is buggy on some devices.
content.style.transitionDelay = Math.round(duration / 10) + "ms";
backdrop.style.transitionDuration = transitionDuration;
setVisibilityState([backdrop], 'visible');
}
},
onShow: function onShow() {
if (backdrop) {
backdrop.style.transitionDuration = '0ms';
}
},
onHide: function onHide() {
if (backdrop) {
setVisibilityState([backdrop], 'hidden');
}
}
};
}
};
function createBackdropElement() {
var backdrop = div();
backdrop.className = BACKDROP_CLASS;
setVisibilityState([backdrop], 'hidden');
return backdrop;
}
var mouseCoords = {
clientX: 0,
clientY: 0
};
var activeInstances = [];
function storeMouseCoords(_ref) {
var clientX = _ref.clientX,
clientY = _ref.clientY;
mouseCoords = {
clientX: clientX,
clientY: clientY
};
}
function addMouseCoordsListener(doc) {
doc.addEventListener('mousemove', storeMouseCoords);
}
function removeMouseCoordsListener(doc) {
doc.removeEventListener('mousemove', storeMouseCoords);
}
var followCursor = {
name: 'followCursor',
defaultValue: false,
fn: function fn(instance) {
var reference = instance.reference;
var doc = getOwnerDocument(instance.props.triggerTarget || reference);
var isInternalUpdate = false;
var wasFocusEvent = false;
var isUnmounted = true;
var prevProps = instance.props;
function getIsInitialBehavior() {
return instance.props.followCursor === 'initial' && instance.state.isVisible;
}
function addListener() {
doc.addEventListener('mousemove', onMouseMove);
}
function removeListener() {
doc.removeEventListener('mousemove', onMouseMove);
}
function unsetGetReferenceClientRect() {
isInternalUpdate = true;
instance.setProps({
getReferenceClientRect: null
});
isInternalUpdate = false;
}
function onMouseMove(event) {
// If the instance is interactive, avoid updating the position unless it's
// over the reference element
var isCursorOverReference = event.target ? reference.contains(event.target) : true;
var followCursor = instance.props.followCursor;
var clientX = event.clientX,
clientY = event.clientY;
var rect = reference.getBoundingClientRect();
var relativeX = clientX - rect.left;
var relativeY = clientY - rect.top;
if (isCursorOverReference || !instance.props.interactive) {
instance.setProps({
getReferenceClientRect: function getReferenceClientRect() {
var rect = reference.getBoundingClientRect();
var x = clientX;
var y = clientY;
if (followCursor === 'initial') {
x = rect.left + relativeX;
y = rect.top + relativeY;
}
var top = followCursor === 'horizontal' ? rect.top : y;
var right = followCursor === 'vertical' ? rect.right : x;
var bottom = followCursor === 'horizontal' ? rect.bottom : y;
var left = followCursor === 'vertical' ? rect.left : x;
return {
width: right - left,
height: bottom - top,
top: top,
right: right,
bottom: bottom,
left: left
};
}
});
}
}
function create() {
if (instance.props.followCursor) {
activeInstances.push({
instance: instance,
doc: doc
});
addMouseCoordsListener(doc);
}
}
function destroy() {
activeInstances = activeInstances.filter(function (data) {
return data.instance !== instance;
});
if (activeInstances.filter(function (data) {
return data.doc === doc;
}).length === 0) {
removeMouseCoordsListener(doc);
}
}
return {
onCreate: create,
onDestroy: destroy,
onBeforeUpdate: function onBeforeUpdate() {
prevProps = instance.props;
},
onAfterUpdate: function onAfterUpdate(_, _ref2) {
var followCursor = _ref2.followCursor;
if (isInternalUpdate) {
return;
}
if (followCursor !== undefined && prevProps.followCursor !== followCursor) {
destroy();
if (followCursor) {
create();
if (instance.state.isMounted && !wasFocusEvent && !getIsInitialBehavior()) {
addListener();
}
} else {
removeListener();
unsetGetReferenceClientRect();
}
}
},
onMount: function onMount() {
if (instance.props.followCursor && !wasFocusEvent) {
if (isUnmounted) {
onMouseMove(mouseCoords);
isUnmounted = false;
}
if (!getIsInitialBehavior()) {
addListener();
}
}
},
onTrigger: function onTrigger(_, event) {
if (isMouseEvent(event)) {
mouseCoords = {
clientX: event.clientX,
clientY: event.clientY
};
}
wasFocusEvent = event.type === 'focus';
},
onHidden: function onHidden() {
if (instance.props.followCursor) {
unsetGetReferenceClientRect();
removeListener();
isUnmounted = true;
}
}
};
}
};
function getProps(props, modifier) {
var _props$popperOptions;
return {
popperOptions: Object.assign({}, props.popperOptions, {
modifiers: [].concat((((_props$popperOptions = props.popperOptions) == null ? void 0 : _props$popperOptions.modifiers) || []).filter(function (_ref) {
var name = _ref.name;
return name !== modifier.name;
}), [modifier])
})
};
}
var inlinePositioning = {
name: 'inlinePositioning',
defaultValue: false,
fn: function fn(instance) {
var reference = instance.reference;
function isEnabled() {
return !!instance.props.inlinePositioning;
}
var placement;
var cursorRectIndex = -1;
var isInternalUpdate = false;
var modifier = {
name: 'tippyInlinePositioning',
enabled: true,
phase: 'afterWrite',
fn: function fn(_ref2) {
var state = _ref2.state;
if (isEnabled()) {
if (placement !== state.placement) {
instance.setProps({
getReferenceClientRect: function getReferenceClientRect() {
return _getReferenceClientRect(state.placement);
}
});
}
placement = state.placement;
}
}
};
function _getReferenceClientRect(placement) {
return getInlineBoundingClientRect(getBasePlacement(placement), reference.getBoundingClientRect(), arrayFrom(reference.getClientRects()), cursorRectIndex);
}
function setInternalProps(partialProps) {
isInternalUpdate = true;
instance.setProps(partialProps);
isInternalUpdate = false;
}
function addModifier() {
if (!isInternalUpdate) {
setInternalProps(getProps(instance.props, modifier));
}
}
return {
onCreate: addModifier,
onAfterUpdate: addModifier,
onTrigger: function onTrigger(_, event) {
if (isMouseEvent(event)) {
var rects = arrayFrom(instance.reference.getClientRects());
var cursorRect = rects.find(function (rect) {
return rect.left - 2 <= event.clientX && rect.right + 2 >= event.clientX && rect.top - 2 <= event.clientY && rect.bottom + 2 >= event.clientY;
});
cursorRectIndex = rects.indexOf(cursorRect);
}
},
onUntrigger: function onUntrigger() {
cursorRectIndex = -1;
}
};
}
};
function getInlineBoundingClientRect(currentBasePlacement, boundingRect, clientRects, cursorRectIndex) {
// Not an inline element, or placement is not yet known
if (clientRects.length < 2 || currentBasePlacement === null) {
return boundingRect;
} // There are two rects and they are disjoined
if (clientRects.length === 2 && cursorRectIndex >= 0 && clientRects[0].left > clientRects[1].right) {
return clientRects[cursorRectIndex] || boundingRect;
}
switch (currentBasePlacement) {
case 'top':
case 'bottom':
{
var firstRect = clientRects[0];
var lastRect = clientRects[clientRects.length - 1];
var isTop = currentBasePlacement === 'top';
var top = firstRect.top;
var bottom = lastRect.bottom;
var left = isTop ? firstRect.left : lastRect.left;
var right = isTop ? firstRect.right : lastRect.right;
var width = right - left;
var height = bottom - top;
return {
top: top,
bottom: bottom,
left: left,
right: right,
width: width,
height: height
};
}
case 'left':
case 'right':
{
var minLeft = Math.min.apply(Math, clientRects.map(function (rects) {
return rects.left;
}));
var maxRight = Math.max.apply(Math, clientRects.map(function (rects) {
return rects.right;
}));
var measureRects = clientRects.filter(function (rect) {
return currentBasePlacement === 'left' ? rect.left === minLeft : rect.right === maxRight;
});
var _top = measureRects[0].top;
var _bottom = measureRects[measureRects.length - 1].bottom;
var _left = minLeft;
var _right = maxRight;
var _width = _right - _left;
var _height = _bottom - _top;
return {
top: _top,
bottom: _bottom,
left: _left,
right: _right,
width: _width,
height: _height
};
}
default:
{
return boundingRect;
}
}
}
var sticky = {
name: 'sticky',
defaultValue: false,
fn: function fn(instance) {
var reference = instance.reference,
popper = instance.popper;
function getReference() {
return instance.popperInstance ? instance.popperInstance.state.elements.reference : reference;
}
function shouldCheck(value) {
return instance.props.sticky === true || instance.props.sticky === value;
}
var prevRefRect = null;
var prevPopRect = null;
function updatePosition() {
var currentRefRect = shouldCheck('reference') ? getReference().getBoundingClientRect() : null;
var currentPopRect = shouldCheck('popper') ? popper.getBoundingClientRect() : null;
if (currentRefRect && areRectsDifferent(prevRefRect, currentRefRect) || currentPopRect && areRectsDifferent(prevPopRect, currentPopRect)) {
if (instance.popperInstance) {
instance.popperInstance.update();
}
}
prevRefRect = currentRefRect;
prevPopRect = currentPopRect;
if (instance.state.isMounted) {
requestAnimationFrame(updatePosition);
}
}
return {
onMount: function onMount() {
if (instance.props.sticky) {
updatePosition();
}
}
};
}
};
function areRectsDifferent(rectA, rectB) {
if (rectA && rectB) {
return rectA.top !== rectB.top || rectA.right !== rectB.right || rectA.bottom !== rectB.bottom || rectA.left !== rectB.left;
}
return true;
}
tippy.setDefaultProps({
render: render
});
exports.animateFill = animateFill;
exports.createSingleton = createSingleton;
exports.default = tippy;
exports.delegate = delegate;
exports.followCursor = followCursor;
exports.hideAll = hideAll;
exports.inlinePositioning = inlinePositioning;
exports.roundArrow = ROUND_ARROW;
exports.sticky = sticky;
}).call(this)}).call(this,require('_process'))
},{"@popperjs/core":1,"_process":187}],290:[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":60}],291:[function(require,module,exports){
(function (process){(function (){
/*! torrent-discovery. MIT License. WebTorrent LLC <https://webtorrent.io/opensource> */
const debug = require('debug')('torrent-discovery')
const DHT = require('bittorrent-dht/client') // empty object in browser
const EventEmitter = require('events').EventEmitter
const parallel = require('run-parallel')
const Tracker = require('bittorrent-tracker/client')
const LSD = require('bittorrent-lsd')
class Discovery extends EventEmitter {
constructor (opts) {
super()
if (!opts.peerId) throw new Error('Option `peerId` is required')
if (!opts.infoHash) throw new Error('Option `infoHash` is required')
if (!process.browser && !opts.port) throw new Error('Option `port` is required')
this.peerId = typeof opts.peerId === 'string'
? opts.peerId
: opts.peerId.toString('hex')
this.infoHash = typeof opts.infoHash === 'string'
? opts.infoHash.toLowerCase()
: opts.infoHash.toString('hex')
this._port = opts.port // torrent port
this._userAgent = opts.userAgent // User-Agent header for http requests
this.destroyed = false
this._announce = opts.announce || []
this._intervalMs = opts.intervalMs || (15 * 60 * 1000)
this._trackerOpts = null
this._dhtAnnouncing = false
this._dhtTimeout = false
this._internalDHT = false // is the DHT created internally?
this._onWarning = err => {
this.emit('warning', err)
}
this._onError = err => {
this.emit('error', err)
}
this._onDHTPeer = (peer, infoHash) => {
if (infoHash.toString('hex') !== this.infoHash) return
this.emit('peer', `${peer.host}:${peer.port}`, 'dht')
}
this._onTrackerPeer = peer => {
this.emit('peer', peer, 'tracker')
}
this._onTrackerAnnounce = () => {
this.emit('trackerAnnounce')
}
this._onLSDPeer = (peer, infoHash) => {
this.emit('peer', peer, 'lsd')
}
const createDHT = (port, opts) => {
const dht = new DHT(opts)
dht.on('warning', this._onWarning)
dht.on('error', this._onError)
dht.listen(port)
this._internalDHT = true
return dht
}
if (opts.tracker === false) {
this.tracker = null
} else if (opts.tracker && typeof opts.tracker === 'object') {
this._trackerOpts = Object.assign({}, opts.tracker)
this.tracker = this._createTracker()
} else {
this.tracker = this._createTracker()
}
if (opts.dht === false || typeof DHT !== 'function') {
this.dht = null
} else if (opts.dht && typeof opts.dht.addNode === 'function') {
this.dht = opts.dht
} else if (opts.dht && typeof opts.dht === 'object') {
this.dht = createDHT(opts.dhtPort, opts.dht)
} else {
this.dht = createDHT(opts.dhtPort)
}
if (this.dht) {
this.dht.on('peer', this._onDHTPeer)
this._dhtAnnounce()
}
if (opts.lsd === false || typeof LSD !== 'function') {
this.lsd = null
} else {
this.lsd = this._createLSD()
}
}
updatePort (port) {
if (port === this._port) return
this._port = port
if (this.dht) this._dhtAnnounce()
if (this.tracker) {
this.tracker.stop()
this.tracker.destroy(() => {
this.tracker = this._createTracker()
})
}
}
complete (opts) {
if (this.tracker) {
this.tracker.complete(opts)
}
}
destroy (cb) {
if (this.destroyed) return
this.destroyed = true
clearTimeout(this._dhtTimeout)
const tasks = []
if (this.tracker) {
this.tracker.stop()
this.tracker.removeListener('warning', this._onWarning)
this.tracker.removeListener('error', this._onError)
this.tracker.removeListener('peer', this._onTrackerPeer)
this.tracker.removeListener('update', this._onTrackerAnnounce)
tasks.push(cb => {
this.tracker.destroy(cb)
})
}
if (this.dht) {
this.dht.removeListener('peer', this._onDHTPeer)
}
if (this._internalDHT) {
this.dht.removeListener('warning', this._onWarning)
this.dht.removeListener('error', this._onError)
tasks.push(cb => {
this.dht.destroy(cb)
})
}
if (this.lsd) {
this.lsd.removeListener('warning', this._onWarning)
this.lsd.removeListener('error', this._onError)
this.lsd.removeListener('peer', this._onLSDPeer)
tasks.push(cb => {
this.lsd.destroy(cb)
})
}
parallel(tasks, cb)
// cleanup
this.dht = null
this.tracker = null
this.lsd = null
this._announce = null
}
_createTracker () {
const opts = Object.assign({}, this._trackerOpts, {
infoHash: this.infoHash,
announce: this._announce,
peerId: this.peerId,
port: this._port,
userAgent: this._userAgent
})
const tracker = new Tracker(opts)
tracker.on('warning', this._onWarning)
tracker.on('error', this._onError)
tracker.on('peer', this._onTrackerPeer)
tracker.on('update', this._onTrackerAnnounce)
tracker.setInterval(this._intervalMs)
tracker.start()
return tracker
}
_dhtAnnounce () {
if (this._dhtAnnouncing) return
debug('dht announce')
this._dhtAnnouncing = true
clearTimeout(this._dhtTimeout)
this.dht.announce(this.infoHash, this._port, err => {
this._dhtAnnouncing = false
debug('dht announce complete')
if (err) this.emit('warning', err)
this.emit('dhtAnnounce')
if (!this.destroyed) {
this._dhtTimeout = setTimeout(() => {
this._dhtAnnounce()
}, this._intervalMs + Math.floor(Math.random() * this._intervalMs / 5))
if (this._dhtTimeout.unref) this._dhtTimeout.unref()
}
})
}
_createLSD () {
const opts = Object.assign({}, {
infoHash: this.infoHash,
peerId: this.peerId,
port: this._port
})
const lsd = new LSD(opts)
lsd.on('warning', this._onWarning)
lsd.on('error', this._onError)
lsd.on('peer', this._onLSDPeer)
lsd.start()
return lsd
}
}
module.exports = Discovery
}).call(this)}).call(this,require('_process'))
},{"_process":187,"bittorrent-dht/client":55,"bittorrent-lsd":55,"bittorrent-tracker/client":31,"debug":292,"events":98,"run-parallel":218}],292:[function(require,module,exports){
arguments[4][13][0].apply(exports,arguments)
},{"./common":293,"_process":187,"dup":13}],293:[function(require,module,exports){
arguments[4][14][0].apply(exports,arguments)
},{"dup":14,"ms":294}],294:[function(require,module,exports){
arguments[4][15][0].apply(exports,arguments)
},{"dup":15}],295:[function(require,module,exports){
(function (Buffer){(function (){
const BLOCK_LENGTH = 1 << 14
class Piece {
constructor (length) {
this.length = length
this.missing = length
this.sources = null
this._chunks = Math.ceil(length / BLOCK_LENGTH)
this._remainder = (length % BLOCK_LENGTH) || BLOCK_LENGTH
this._buffered = 0
this._buffer = null
this._cancellations = null
this._reservations = 0
this._flushed = false
}
chunkLength (i) {
return i === this._chunks - 1 ? this._remainder : BLOCK_LENGTH
}
chunkLengthRemaining (i) {
return this.length - (i * BLOCK_LENGTH)
}
chunkOffset (i) {
return i * BLOCK_LENGTH
}
reserve () {
if (!this.init()) return -1
if (this._cancellations.length) return this._cancellations.pop()
if (this._reservations < this._chunks) return this._reservations++
return -1
}
reserveRemaining () {
if (!this.init()) return -1
if (this._reservations < this._chunks) {
const min = this._reservations
this._reservations = this._chunks
return min
}
return -1
}
cancel (i) {
if (!this.init()) return
this._cancellations.push(i)
}
cancelRemaining (i) {
if (!this.init()) return
this._reservations = i
}
get (i) {
if (!this.init()) return null
return this._buffer[i]
}
set (i, data, source) {
if (!this.init()) return false
const len = data.length
const blocks = Math.ceil(len / BLOCK_LENGTH)
for (let j = 0; j < blocks; j++) {
if (!this._buffer[i + j]) {
const offset = j * BLOCK_LENGTH
const splitData = data.slice(offset, offset + BLOCK_LENGTH)
this._buffered++
this._buffer[i + j] = splitData
this.missing -= splitData.length
if (!this.sources.includes(source)) {
this.sources.push(source)
}
}
}
return this._buffered === this._chunks
}
flush () {
if (!this._buffer || this._chunks !== this._buffered) return null
const buffer = Buffer.concat(this._buffer, this.length)
this._buffer = null
this._cancellations = null
this.sources = null
this._flushed = true
return buffer
}
init () {
if (this._flushed) return false
if (this._buffer) return true
this._buffer = new Array(this._chunks)
this._cancellations = []
this.sources = []
return true
}
}
Object.defineProperty(Piece, 'BLOCK_LENGTH', { value: BLOCK_LENGTH })
module.exports = Piece
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60}],296:[function(require,module,exports){
(function (Buffer){(function (){
/**
* Convert a typed array to a Buffer without a copy
*
* Author: Feross Aboukhadijeh <https://feross.org>
* License: MIT
*
* `npm install typedarray-to-buffer`
*/
var isTypedArray = require('is-typedarray').strict
module.exports = function typedarrayToBuffer (arr) {
if (isTypedArray(arr)) {
// To avoid a copy, use the typed array's underlying ArrayBuffer to back new Buffer
var buf = Buffer.from(arr.buffer)
if (arr.byteLength !== arr.buffer.byteLength) {
// Respect the "view", i.e. byteOffset and byteLength, without doing a copy
buf = buf.slice(arr.byteOffset, arr.byteOffset + arr.byteLength)
}
return buf
} else {
// Pass through all other types to `Buffer.from`
return Buffer.from(arr)
}
}
}).call(this)}).call(this,require("buffer").Buffer)
},{"buffer":60,"is-typedarray":122}],297:[function(require,module,exports){
var bufferAlloc = require('buffer-alloc')
var UINT_32_MAX = Math.pow(2, 32)
exports.encodingLength = function () {
return 8
}
exports.encode = function (num, buf, offset) {
if (!buf) buf = bufferAlloc(8)
if (!offset) offset = 0
var top = Math.floor(num / UINT_32_MAX)
var rem = num - top * UINT_32_MAX
buf.writeUInt32BE(top, offset)
buf.writeUInt32BE(rem, offset + 4)
return buf
}
exports.decode = function (buf, offset) {
if (!offset) offset = 0
var top = buf.readUInt32BE(offset)
var rem = buf.readUInt32BE(offset + 4)
return top * UINT_32_MAX + rem
}
exports.encode.bytes = 8
exports.decode.bytes = 8
},{"buffer-alloc":58}],298:[function(require,module,exports){
module.exports = remove
function remove (arr, i) {
if (i >= arr.length || i < 0) return
var last = arr.pop()
if (i < arr.length) {
var tmp = arr[i]
arr[i] = last
return tmp
}
return last
}
},{}],299:[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":300,"punycode":189,"querystring":192}],300:[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;
}
};
},{}],301:[function(require,module,exports){
(function (Buffer){(function (){
/*! ut_metadata. MIT License. WebTorrent LLC <https://webtorrent.io/opensource> */
const { EventEmitter } = require('events')
const bencode = require('bencode')
const BitField = require('bitfield').default
const debug = require('debug')('ut_metadata')
const sha1 = require('simple-sha1')
const MAX_METADATA_SIZE = 1E7 // 10 MB
const BITFIELD_GROW = 1E3
const PIECE_LENGTH = 1 << 14 // 16 KiB
module.exports = metadata => {
class utMetadata extends EventEmitter {
constructor (wire) {
super()
this._wire = wire
this._fetching = false
this._metadataComplete = false
this._metadataSize = null
// how many reject messages to tolerate before quitting
this._remainingRejects = null
// The largest torrent file that I know of is ~1-2MB, which is ~100
// pieces. Therefore, cap the bitfield to 10x that (1000 pieces) so a
// malicious peer can't make it grow to fill all memory.
this._bitfield = new BitField(0, { grow: BITFIELD_GROW })
if (Buffer.isBuffer(metadata)) {
this.setMetadata(metadata)
}
}
onHandshake (infoHash, peerId, extensions) {
this._infoHash = infoHash
}
onExtendedHandshake (handshake) {
if (!handshake.m || !handshake.m.ut_metadata) {
return this.emit('warning', new Error('Peer does not support ut_metadata'))
}
if (!handshake.metadata_size) {
return this.emit('warning', new Error('Peer does not have metadata'))
}
if (typeof handshake.metadata_size !== 'number' ||
MAX_METADATA_SIZE < handshake.metadata_size ||
handshake.metadata_size <= 0) {
return this.emit('warning', new Error('Peer gave invalid metadata size'))
}
this._metadataSize = handshake.metadata_size
this._numPieces = Math.ceil(this._metadataSize / PIECE_LENGTH)
this._remainingRejects = this._numPieces * 2
this._requestPieces()
}
onMessage (buf) {
let dict
let trailer
try {
const str = buf.toString()
const trailerIndex = str.indexOf('ee') + 2
dict = bencode.decode(str.substring(0, trailerIndex))
trailer = buf.slice(trailerIndex)
} catch (err) {
// drop invalid messages
return
}
switch (dict.msg_type) {
case 0:
// ut_metadata request (from peer)
// example: { 'msg_type': 0, 'piece': 0 }
this._onRequest(dict.piece)
break
case 1:
// ut_metadata data (in response to our request)
// example: { 'msg_type': 1, 'piece': 0, 'total_size': 3425 }
this._onData(dict.piece, trailer, dict.total_size)
break
case 2:
// ut_metadata reject (peer doesn't have piece we requested)
// { 'msg_type': 2, 'piece': 0 }
this._onReject(dict.piece)
break
}
}
/**
* Ask the peer to send metadata.
* @public
*/
fetch () {
if (this._metadataComplete) {
return
}
this._fetching = true
if (this._metadataSize) {
this._requestPieces()
}
}
/**
* Stop asking the peer to send metadata.
* @public
*/
cancel () {
this._fetching = false
}
setMetadata (metadata) {
if (this._metadataComplete) return true
debug('set metadata')
// if full torrent dictionary was passed in, pull out just `info` key
try {
const info = bencode.decode(metadata).info
if (info) {
metadata = bencode.encode(info)
}
} catch (err) {}
// check hash
if (this._infoHash && this._infoHash !== sha1.sync(metadata)) {
return false
}
this.cancel()
this.metadata = metadata
this._metadataComplete = true
this._metadataSize = this.metadata.length
this._wire.extendedHandshake.metadata_size = this._metadataSize
this.emit('metadata', bencode.encode({
info: bencode.decode(this.metadata)
}))
return true
}
_send (dict, trailer) {
let buf = bencode.encode(dict)
if (Buffer.isBuffer(trailer)) {
buf = Buffer.concat([buf, trailer])
}
this._wire.extended('ut_metadata', buf)
}
_request (piece) {
this._send({ msg_type: 0, piece })
}
_data (piece, buf, totalSize) {
const msg = { msg_type: 1, piece }
if (typeof totalSize === 'number') {
msg.total_size = totalSize
}
this._send(msg, buf)
}
_reject (piece) {
this._send({ msg_type: 2, piece })
}
_onRequest (piece) {
if (!this._metadataComplete) {
this._reject(piece)
return
}
const start = piece * PIECE_LENGTH
let end = start + PIECE_LENGTH
if (end > this._metadataSize) {
end = this._metadataSize
}
const buf = this.metadata.slice(start, end)
this._data(piece, buf, this._metadataSize)
}
_onData (piece, buf, totalSize) {
if (buf.length > PIECE_LENGTH || !this._fetching) {
return
}
buf.copy(this.metadata, piece * PIECE_LENGTH)
this._bitfield.set(piece)
this._checkDone()
}
_onReject (piece) {
if (this._remainingRejects > 0 && this._fetching) {
// If we haven't been rejected too much,
// then try to request the piece again
this._request(piece)
this._remainingRejects -= 1
} else {
this.emit('warning', new Error('Peer sent "reject" too much'))
}
}
_requestPieces () {
if (!this._fetching) return
this.metadata = Buffer.alloc(this._metadataSize)
for (let piece = 0; piece < this._numPieces; piece++) {
this._request(piece)
}
}
_checkDone () {
let done = true
for (let piece = 0; piece < this._numPieces; piece++) {
if (!this._bitfield.get(piece)) {
done = false
break
}
}
if (!done) return
// attempt to set metadata -- may fail sha1 check
const success = this.setMetadata(this.metadata)
if (!success) {
this._failedMetadata()
}
}
_failedMetadata () {
// reset bitfield & try again
this._bitfield = new BitField(0, { grow: BITFIELD_GROW })
this._remainingRejects -= this._numPieces
if (this._remainingRejects > 0) {
this._requestPieces()
} else {
this.emit('warning', new Error('Peer sent invalid metadata'))
}
}
}
// Name of the bittorrent-protocol extension
utMetadata.prototype.name = 'ut_metadata'
return utMetadata
}
}).call(this)}).call(this,require("buffer").Buffer)
},{"bencode":7,"bitfield":302,"buffer":60,"debug":303,"events":98,"simple-sha1":242}],302:[function(require,module,exports){
arguments[4][12][0].apply(exports,arguments)
},{"dup":12}],303:[function(require,module,exports){
arguments[4][13][0].apply(exports,arguments)
},{"./common":304,"_process":187,"dup":13}],304:[function(require,module,exports){
arguments[4][14][0].apply(exports,arguments)
},{"dup":14,"ms":305}],305:[function(require,module,exports){
arguments[4][15][0].apply(exports,arguments)
},{"dup":15}],306:[function(require,module,exports){
(function (global){(function (){
/**
* 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)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],307:[function(require,module,exports){
(function (Buffer){(function (){
const bs = require('binary-search')
const EventEmitter = require('events')
const mp4 = require('mp4-stream')
const Box = require('mp4-box-encoding')
const RangeSliceStream = require('range-slice-stream')
// if we want to ignore more than this many bytes, request a new stream.
// if we want to ignore fewer, just skip them.
const FIND_MOOV_SEEK_SIZE = 4096
class MP4Remuxer extends EventEmitter {
constructor (file) {
super()
this._tracks = []
this._file = file
this._decoder = null
this._findMoov(0)
}
_findMoov (offset) {
if (this._decoder) {
this._decoder.destroy()
}
let toSkip = 0
this._decoder = mp4.decode()
const fileStream = this._file.createReadStream({
start: offset
})
fileStream.pipe(this._decoder)
const boxHandler = headers => {
if (headers.type === 'moov') {
this._decoder.removeListener('box', boxHandler)
this._decoder.decode(moov => {
fileStream.destroy()
try {
this._processMoov(moov)
} catch (err) {
err.message = `Cannot parse mp4 file: ${err.message}`
this.emit('error', err)
}
})
} else if (headers.length < FIND_MOOV_SEEK_SIZE) {
toSkip += headers.length
this._decoder.ignore()
} else {
this._decoder.removeListener('box', boxHandler)
toSkip += headers.length
fileStream.destroy()
this._decoder.destroy()
this._findMoov(offset + toSkip)
}
}
this._decoder.on('box', boxHandler)
}
_processMoov (moov) {
const traks = moov.traks
this._tracks = []
this._hasVideo = false
this._hasAudio = false
for (let i = 0; i < traks.length; i++) {
const trak = traks[i]
const stbl = trak.mdia.minf.stbl
const stsdEntry = stbl.stsd.entries[0]
const handlerType = trak.mdia.hdlr.handlerType
let codec
let mime
if (handlerType === 'vide' && stsdEntry.type === 'avc1') {
if (this._hasVideo) {
continue
}
this._hasVideo = true
codec = 'avc1'
if (stsdEntry.avcC) {
codec += `.${stsdEntry.avcC.mimeCodec}`
}
mime = `video/mp4; codecs="${codec}"`
} else if (handlerType === 'soun' && stsdEntry.type === 'mp4a') {
if (this._hasAudio) {
continue
}
this._hasAudio = true
codec = 'mp4a'
if (stsdEntry.esds && stsdEntry.esds.mimeCodec) {
codec += `.${stsdEntry.esds.mimeCodec}`
}
mime = `audio/mp4; codecs="${codec}"`
} else {
continue
}
const samples = []
let sample = 0
// Chunk/position data
let sampleInChunk = 0
let chunk = 0
let offsetInChunk = 0
let sampleToChunkIndex = 0
// Time data
let dts = 0
const decodingTimeEntry = new RunLengthIndex(stbl.stts.entries)
let presentationOffsetEntry = null
if (stbl.ctts) {
presentationOffsetEntry = new RunLengthIndex(stbl.ctts.entries)
}
// Sync table index
let syncSampleIndex = 0
while (true) {
var currChunkEntry = stbl.stsc.entries[sampleToChunkIndex]
// Compute size
const size = stbl.stsz.entries[sample]
// Compute time data
const duration = decodingTimeEntry.value.duration
const presentationOffset = presentationOffsetEntry ? presentationOffsetEntry.value.compositionOffset : 0
// Compute sync
let sync = true
if (stbl.stss) {
sync = stbl.stss.entries[syncSampleIndex] === sample + 1
}
// Create new sample entry
const chunkOffsetTable = stbl.stco || stbl.co64
samples.push({
size,
duration,
dts,
presentationOffset,
sync,
offset: offsetInChunk + chunkOffsetTable.entries[chunk]
})
// Go to next sample
sample++
if (sample >= stbl.stsz.entries.length) {
break
}
// Move position/chunk
sampleInChunk++
offsetInChunk += size
if (sampleInChunk >= currChunkEntry.samplesPerChunk) {
// Move to new chunk
sampleInChunk = 0
offsetInChunk = 0
chunk++
// Move sample to chunk box index
const nextChunkEntry = stbl.stsc.entries[sampleToChunkIndex + 1]
if (nextChunkEntry && chunk + 1 >= nextChunkEntry.firstChunk) {
sampleToChunkIndex++
}
}
// Move time forward
dts += duration
decodingTimeEntry.inc()
presentationOffsetEntry && presentationOffsetEntry.inc()
// Move sync table index
if (sync) {
syncSampleIndex++
}
}
trak.mdia.mdhd.duration = 0
trak.tkhd.duration = 0
const defaultSampleDescriptionIndex = currChunkEntry.sampleDescriptionId
const trackMoov = {
type: 'moov',
mvhd: moov.mvhd,
traks: [{
tkhd: trak.tkhd,
mdia: {
mdhd: trak.mdia.mdhd,
hdlr: trak.mdia.hdlr,
elng: trak.mdia.elng,
minf: {
vmhd: trak.mdia.minf.vmhd,
smhd: trak.mdia.minf.smhd,
dinf: trak.mdia.minf.dinf,
stbl: {
stsd: stbl.stsd,
stts: empty(),
ctts: empty(),
stsc: empty(),
stsz: empty(),
stco: empty(),
stss: empty()
}
}
}
}],
mvex: {
mehd: {
fragmentDuration: moov.mvhd.duration
},
trexs: [{
trackId: trak.tkhd.trackId,
defaultSampleDescriptionIndex,
defaultSampleDuration: 0,
defaultSampleSize: 0,
defaultSampleFlags: 0
}]
}
}
this._tracks.push({
fragmentSequence: 1,
trackId: trak.tkhd.trackId,
timeScale: trak.mdia.mdhd.timeScale,
samples,
currSample: null,
currTime: null,
moov: trackMoov,
mime
})
}
if (this._tracks.length === 0) {
this.emit('error', new Error('no playable tracks'))
return
}
// Must be set last since this is used above
moov.mvhd.duration = 0
this._ftyp = {
type: 'ftyp',
brand: 'iso5',
brandVersion: 0,
compatibleBrands: [
'iso5'
]
}
const ftypBuf = Box.encode(this._ftyp)
const data = this._tracks.map(track => {
const moovBuf = Box.encode(track.moov)
return {
mime: track.mime,
init: Buffer.concat([ftypBuf, moovBuf])
}
})
this.emit('ready', data)
}
seek (time) {
if (!this._tracks) {
throw new Error('Not ready yet; wait for \'ready\' event')
}
if (this._fileStream) {
this._fileStream.destroy()
this._fileStream = null
}
let startOffset = -1
this._tracks.map((track, i) => {
// find the keyframe before the time
// stream from there
if (track.outStream) {
track.outStream.destroy()
}
if (track.inStream) {
track.inStream.destroy()
track.inStream = null
}
const outStream = track.outStream = mp4.encode()
const fragment = this._generateFragment(i, time)
if (!fragment) {
return outStream.finalize()
}
if (startOffset === -1 || fragment.ranges[0].start < startOffset) {
startOffset = fragment.ranges[0].start
}
const writeFragment = (frag) => {
if (outStream.destroyed) return
outStream.box(frag.moof, err => {
if (err) return this.emit('error', err)
if (outStream.destroyed) return
const slicedStream = track.inStream.slice(frag.ranges)
slicedStream.pipe(outStream.mediaData(frag.length, err => {
if (err) return this.emit('error', err)
if (outStream.destroyed) return
const nextFrag = this._generateFragment(i)
if (!nextFrag) {
return outStream.finalize()
}
writeFragment(nextFrag)
}))
})
}
writeFragment(fragment)
})
if (startOffset >= 0) {
const fileStream = this._fileStream = this._file.createReadStream({
start: startOffset
})
this._tracks.forEach(track => {
track.inStream = new RangeSliceStream(startOffset, {
// Allow up to a 10MB offset between audio and video,
// which should be fine for any reasonable interleaving
// interval and bitrate
highWaterMark: 10000000
})
fileStream.pipe(track.inStream)
})
}
return this._tracks.map(track => {
return track.outStream
})
}
_findSampleBefore (trackInd, time) {
const track = this._tracks[trackInd]
const scaledTime = Math.floor(track.timeScale * time)
let sample = bs(track.samples, scaledTime, (sample, t) => {
const pts = sample.dts + sample.presentationOffset// - track.editShift
return pts - t
})
if (sample === -1) {
sample = 0
} else if (sample < 0) {
sample = -sample - 2
}
// sample is now the last sample with dts <= time
// Find the preceeding sync sample
while (!track.samples[sample].sync) {
sample--
}
return sample
}
_generateFragment (track, time) {
/*
1. Find correct sample
2. Process backward until sync sample found
3. Process forward until next sync sample after MIN_FRAGMENT_DURATION found
*/
const currTrack = this._tracks[track]
let firstSample
if (time !== undefined) {
firstSample = this._findSampleBefore(track, time)
} else {
firstSample = currTrack.currSample
}
if (firstSample >= currTrack.samples.length) { return null }
const startDts = currTrack.samples[firstSample].dts
let totalLen = 0
const ranges = []
for (var currSample = firstSample; currSample < currTrack.samples.length; currSample++) {
const sample = currTrack.samples[currSample]
if (sample.sync && sample.dts - startDts >= currTrack.timeScale * MIN_FRAGMENT_DURATION) {
break // This is a reasonable place to end the fragment
}
totalLen += sample.size
const currRange = ranges.length - 1
if (currRange < 0 || ranges[currRange].end !== sample.offset) {
// Push a new range
ranges.push({
start: sample.offset,
end: sample.offset + sample.size
})
} else {
ranges[currRange].end += sample.size
}
}
currTrack.currSample = currSample
return {
moof: this._generateMoof(track, firstSample, currSample),
ranges,
length: totalLen
}
}
_generateMoof (track, firstSample, lastSample) {
const currTrack = this._tracks[track]
const entries = []
let trunVersion = 0
for (let j = firstSample; j < lastSample; j++) {
const currSample = currTrack.samples[j]
if (currSample.presentationOffset < 0) { trunVersion = 1 }
entries.push({
sampleDuration: currSample.duration,
sampleSize: currSample.size,
sampleFlags: currSample.sync ? 0x2000000 : 0x1010000,
sampleCompositionTimeOffset: currSample.presentationOffset
})
}
const moof = {
type: 'moof',
mfhd: {
sequenceNumber: currTrack.fragmentSequence++
},
trafs: [{
tfhd: {
flags: 0x20000, // default-base-is-moof
trackId: currTrack.trackId
},
tfdt: {
baseMediaDecodeTime: currTrack.samples[firstSample].dts
},
trun: {
flags: 0xf01,
dataOffset: 8, // The moof size has to be added to this later as well
entries,
version: trunVersion
}
}]
}
// Update the offset
moof.trafs[0].trun.dataOffset += Box.encodingLength(moof)
return moof
}
}
class RunLengthIndex {
constructor (entries, countName) {
this._entries = entries
this._countName = countName || 'count'
this._index = 0
this._offset = 0
this.value = this._entries[0]
}
inc () {
this._offset++
if (this._offset >= this._entries[this._index][this._countName]) {
this._index++
this._offset = 0
}
this.value = this._entries[this._index]
}
}
function empty () {
return {
version: 0,
flags: 0,
entries: []
}
}
const MIN_FRAGMENT_DURATION = 1 // second
module.exports = MP4Remuxer
}).call(this)}).call(this,require("buffer").Buffer)
},{"binary-search":9,"buffer":60,"events":98,"mp4-box-encoding":147,"mp4-stream":150,"range-slice-stream":196}],308:[function(require,module,exports){
const MediaElementWrapper = require('mediasource')
const pump = require('pump')
const MP4Remuxer = require('./mp4-remuxer')
function VideoStream (file, mediaElem, opts = {}) {
if (!(this instanceof VideoStream)) {
console.warn("Don't invoke VideoStream without the 'new' keyword.")
return new VideoStream(file, mediaElem, opts)
}
this.detailedError = null
this._elem = mediaElem
this._elemWrapper = new MediaElementWrapper(mediaElem)
this._waitingFired = false
this._trackMeta = null
this._file = file
this._tracks = null
if (this._elem.preload !== 'none') {
this._createMuxer()
}
this._onError = () => {
this.detailedError = this._elemWrapper.detailedError
this.destroy() // don't pass err though so the user doesn't need to listen for errors
}
this._onWaiting = () => {
this._waitingFired = true
if (!this._muxer) {
this._createMuxer()
} else if (this._tracks) {
this._pump()
}
}
if (mediaElem.autoplay) { mediaElem.preload = 'auto' }
mediaElem.addEventListener('waiting', this._onWaiting)
mediaElem.addEventListener('error', this._onError)
}
VideoStream.prototype = {
_createMuxer () {
this._muxer = new MP4Remuxer(this._file)
this._muxer.on('ready', data => {
this._tracks = data.map(trackData => {
const mediaSource = this._elemWrapper.createWriteStream(trackData.mime)
mediaSource.on('error', err => {
this._elemWrapper.error(err)
})
const track = {
muxed: null,
mediaSource,
initFlushed: false,
onInitFlushed: null
}
mediaSource.write(trackData.init, err => {
track.initFlushed = true
if (track.onInitFlushed) {
track.onInitFlushed(err)
}
})
return track
})
if (this._waitingFired || this._elem.preload === 'auto') {
this._pump()
}
})
this._muxer.on('error', err => {
this._elemWrapper.error(err)
})
},
_pump () {
const muxed = this._muxer.seek(this._elem.currentTime, !this._tracks)
this._tracks.forEach((track, i) => {
const pumpTrack = () => {
if (track.muxed) {
track.muxed.destroy()
track.mediaSource = this._elemWrapper.createWriteStream(track.mediaSource)
track.mediaSource.on('error', err => {
this._elemWrapper.error(err)
})
}
track.muxed = muxed[i]
pump(track.muxed, track.mediaSource)
}
if (!track.initFlushed) {
track.onInitFlushed = err => {
if (err) {
this._elemWrapper.error(err)
return
}
pumpTrack()
}
} else {
pumpTrack()
}
})
},
destroy () {
if (this.destroyed) {
return
}
this.destroyed = true
this._elem.removeEventListener('waiting', this._onWaiting)
this._elem.removeEventListener('error', this._onError)
if (this._tracks) {
this._tracks.forEach(track => {
if (track.muxed) {
track.muxed.destroy()
}
})
}
this._elem.src = ''
}
}
module.exports = VideoStream
},{"./mp4-remuxer":307,"mediasource":125,"pump":188}],309:[function(require,module,exports){
(function (process,global,Buffer){(function (){
/*! webtorrent. MIT License. WebTorrent LLC <https://webtorrent.io/opensource> */
/* global FileList */
const { EventEmitter } = require('events')
const concat = require('simple-concat')
const createTorrent = require('create-torrent')
const debug = require('debug')('webtorrent')
const DHT = require('bittorrent-dht/client') // browser exclude
const loadIPSet = require('load-ip-set') // browser exclude
const parallel = require('run-parallel')
const parseTorrent = require('parse-torrent')
const path = require('path')
const Peer = require('simple-peer')
const randombytes = require('randombytes')
const speedometer = require('speedometer')
const ConnPool = require('./lib/conn-pool') // browser exclude
const Torrent = require('./lib/torrent')
const VERSION = require('./package.json').version
/**
* Version number in Azureus-style. Generated from major and minor semver version.
* For example:
* '0.16.1' -> '0016'
* '1.2.5' -> '0102'
*/
const VERSION_STR = VERSION
.replace(/\d*./g, v => `0${v % 100}`.slice(-2))
.slice(0, 4)
/**
* Version prefix string (used in peer ID). WebTorrent uses the Azureus-style
* encoding: '-', two characters for client id ('WW'), four ascii digits for version
* number, '-', followed by random numbers.
* For example:
* '-WW0102-'...
*/
const VERSION_PREFIX = `-WW${VERSION_STR}-`
/**
* WebTorrent Client
* @param {Object=} opts
*/
class WebTorrent extends EventEmitter {
constructor (opts = {}) {
super()
if (typeof opts.peerId === 'string') {
this.peerId = opts.peerId
} else if (Buffer.isBuffer(opts.peerId)) {
this.peerId = opts.peerId.toString('hex')
} else {
this.peerId = Buffer.from(VERSION_PREFIX + randombytes(9).toString('base64')).toString('hex')
}
this.peerIdBuffer = Buffer.from(this.peerId, 'hex')
if (typeof opts.nodeId === 'string') {
this.nodeId = opts.nodeId
} else if (Buffer.isBuffer(opts.nodeId)) {
this.nodeId = opts.nodeId.toString('hex')
} else {
this.nodeId = randombytes(20).toString('hex')
}
this.nodeIdBuffer = Buffer.from(this.nodeId, 'hex')
this._debugId = this.peerId.toString('hex').substring(0, 7)
this.destroyed = false
this.listening = false
this.torrentPort = opts.torrentPort || 0
this.dhtPort = opts.dhtPort || 0
this.tracker = opts.tracker !== undefined ? opts.tracker : {}
this.torrents = []
this.maxConns = Number(opts.maxConns) || 55
this.utp = opts.utp === true
this._debug(
'new webtorrent (peerId %s, nodeId %s, port %s)',
this.peerId, this.nodeId, this.torrentPort
)
if (this.tracker) {
if (typeof this.tracker !== 'object') this.tracker = {}
if (opts.rtcConfig) {
// TODO: remove in v1
console.warn('WebTorrent: opts.rtcConfig is deprecated. Use opts.tracker.rtcConfig instead')
this.tracker.rtcConfig = opts.rtcConfig
}
if (opts.wrtc) {
// TODO: remove in v1
console.warn('WebTorrent: opts.wrtc is deprecated. Use opts.tracker.wrtc instead')
this.tracker.wrtc = opts.wrtc
}
if (global.WRTC && !this.tracker.wrtc) {
this.tracker.wrtc = global.WRTC
}
}
if (typeof ConnPool === 'function') {
this._connPool = new ConnPool(this)
} else {
process.nextTick(() => {
this._onListening()
})
}
// stats
this._downloadSpeed = speedometer()
this._uploadSpeed = speedometer()
if (opts.dht !== false && typeof DHT === 'function' /* browser exclude */) {
// use a single DHT instance for all torrents, so the routing table can be reused
this.dht = new DHT(Object.assign({}, { nodeId: this.nodeId }, opts.dht))
this.dht.once('error', err => {
this._destroy(err)
})
this.dht.once('listening', () => {
const address = this.dht.address()
if (address) this.dhtPort = address.port
})
// Ignore warning when there are > 10 torrents in the client
this.dht.setMaxListeners(0)
this.dht.listen(this.dhtPort)
} else {
this.dht = false
}
// Enable or disable BEP19 (Web Seeds). Enabled by default:
this.enableWebSeeds = opts.webSeeds !== false
const ready = () => {
if (this.destroyed) return
this.ready = true
this.emit('ready')
}
if (typeof loadIPSet === 'function' && opts.blocklist != null) {
loadIPSet(opts.blocklist, {
headers: {
'user-agent': `WebTorrent/${VERSION} (https://webtorrent.io)`
}
}, (err, ipSet) => {
if (err) return this.error(`Failed to load blocklist: ${err.message}`)
this.blocked = ipSet
ready()
})
} else {
process.nextTick(ready)
}
}
get downloadSpeed () { return this._downloadSpeed() }
get uploadSpeed () { return this._uploadSpeed() }
get progress () {
const torrents = this.torrents.filter(torrent => torrent.progress !== 1)
const downloaded = torrents.reduce((total, torrent) => total + torrent.downloaded, 0)
const length = torrents.reduce((total, torrent) => total + (torrent.length || 0), 0) || 1
return downloaded / length
}
get ratio () {
const uploaded = this.torrents.reduce((total, torrent) => total + torrent.uploaded, 0)
const received = this.torrents.reduce((total, torrent) => total + torrent.received, 0) || 1
return uploaded / received
}
/**
* Returns the torrent with the given `torrentId`. Convenience method. Easier than
* searching through the `client.torrents` array. Returns `null` if no matching torrent
* found.
*
* @param {string|Buffer|Object|Torrent} torrentId
* @return {Torrent|null}
*/
get (torrentId) {
if (torrentId instanceof Torrent) {
if (this.torrents.includes(torrentId)) return torrentId
} else {
let parsed
try { parsed = parseTorrent(torrentId) } catch (err) {}
if (!parsed) return null
if (!parsed.infoHash) throw new Error('Invalid torrent identifier')
for (const torrent of this.torrents) {
if (torrent.infoHash === parsed.infoHash) return torrent
}
}
return null
}
// TODO: remove in v1
download (torrentId, opts, ontorrent) {
console.warn('WebTorrent: client.download() is deprecated. Use client.add() instead')
return this.add(torrentId, opts, ontorrent)
}
/**
* Start downloading a new torrent. Aliased as `client.download`.
* @param {string|Buffer|Object} torrentId
* @param {Object} opts torrent-specific options
* @param {function=} ontorrent called when the torrent is ready (has metadata)
*/
add (torrentId, opts = {}, ontorrent = () => {}) {
if (this.destroyed) throw new Error('client is destroyed')
if (typeof opts === 'function') [opts, ontorrent] = [{}, opts]
const onInfoHash = () => {
if (this.destroyed) return
for (const t of this.torrents) {
if (t.infoHash === torrent.infoHash && t !== torrent) {
torrent._destroy(new Error(`Cannot add duplicate torrent ${torrent.infoHash}`))
return
}
}
}
const onReady = () => {
if (this.destroyed) return
ontorrent(torrent)
this.emit('torrent', torrent)
}
function onClose () {
torrent.removeListener('_infoHash', onInfoHash)
torrent.removeListener('ready', onReady)
torrent.removeListener('close', onClose)
}
this._debug('add')
opts = opts ? Object.assign({}, opts) : {}
const torrent = new Torrent(torrentId, this, opts)
this.torrents.push(torrent)
torrent.once('_infoHash', onInfoHash)
torrent.once('ready', onReady)
torrent.once('close', onClose)
return torrent
}
/**
* Start seeding a new file/folder.
* @param {string|File|FileList|Buffer|Array.<string|File|Buffer>} input
* @param {Object=} opts
* @param {function=} onseed called when torrent is seeding
*/
seed (input, opts, onseed) {
if (this.destroyed) throw new Error('client is destroyed')
if (typeof opts === 'function') [opts, onseed] = [{}, opts]
this._debug('seed')
opts = opts ? Object.assign({}, opts) : {}
// no need to verify the hashes we create
opts.skipVerify = true
const isFilePath = typeof input === 'string'
// When seeding from fs path, initialize store from that path to avoid a copy
if (isFilePath) opts.path = path.dirname(input)
if (!opts.createdBy) opts.createdBy = `WebTorrent/${VERSION_STR}`
const onTorrent = torrent => {
const tasks = [
cb => {
// when a filesystem path is specified, files are already in the FS store
if (isFilePath) return cb()
torrent.load(streams, cb)
}
]
if (this.dht) {
tasks.push(cb => {
torrent.once('dhtAnnounce', cb)
})
}
parallel(tasks, err => {
if (this.destroyed) return
if (err) return torrent._destroy(err)
_onseed(torrent)
})
}
const _onseed = torrent => {
this._debug('on seed')
if (typeof onseed === 'function') onseed(torrent)
torrent.emit('seed')
this.emit('seed', torrent)
}
const torrent = this.add(null, opts, onTorrent)
let streams
if (isFileList(input)) input = Array.from(input)
else if (!Array.isArray(input)) input = [input]
parallel(input.map(item => cb => {
if (isReadable(item)) concat(item, cb)
else cb(null, item)
}), (err, input) => {
if (this.destroyed) return
if (err) return torrent._destroy(err)
createTorrent.parseInput(input, opts, (err, files) => {
if (this.destroyed) return
if (err) return torrent._destroy(err)
streams = files.map(file => file.getStream)
createTorrent(input, opts, (err, torrentBuf) => {
if (this.destroyed) return
if (err) return torrent._destroy(err)
const existingTorrent = this.get(torrentBuf)
if (existingTorrent) {
torrent._destroy(new Error(`Cannot add duplicate torrent ${existingTorrent.infoHash}`))
} else {
torrent._onTorrentId(torrentBuf)
}
})
})
})
return torrent
}
/**
* Remove a torrent from the client.
* @param {string|Buffer|Torrent} torrentId
* @param {function} cb
*/
remove (torrentId, opts, cb) {
if (typeof opts === 'function') return this.remove(torrentId, null, opts)
this._debug('remove')
const torrent = this.get(torrentId)
if (!torrent) throw new Error(`No torrent with id ${torrentId}`)
this._remove(torrentId, opts, cb)
}
_remove (torrentId, opts, cb) {
if (typeof opts === 'function') return this._remove(torrentId, null, opts)
const torrent = this.get(torrentId)
if (!torrent) return
this.torrents.splice(this.torrents.indexOf(torrent), 1)
torrent.destroy(opts, cb)
}
address () {
if (!this.listening) return null
return this._connPool
? this._connPool.tcpServer.address()
: { address: '0.0.0.0', family: 'IPv4', port: 0 }
}
/**
* Destroy the client, including all torrents and connections to peers.
* @param {function} cb
*/
destroy (cb) {
if (this.destroyed) throw new Error('client already destroyed')
this._destroy(null, cb)
}
_destroy (err, cb) {
this._debug('client destroy')
this.destroyed = true
const tasks = this.torrents.map(torrent => cb => {
torrent.destroy(cb)
})
if (this._connPool) {
tasks.push(cb => {
this._connPool.destroy(cb)
})
}
if (this.dht) {
tasks.push(cb => {
this.dht.destroy(cb)
})
}
parallel(tasks, cb)
if (err) this.emit('error', err)
this.torrents = []
this._connPool = null
this.dht = null
}
_onListening () {
this._debug('listening')
this.listening = true
if (this._connPool) {
// Sometimes server.address() returns `null` in Docker.
const address = this._connPool.tcpServer.address()
if (address) this.torrentPort = address.port
}
this.emit('listening')
}
_debug () {
const args = [].slice.call(arguments)
args[0] = `[${this._debugId}] ${args[0]}`
debug(...args)
}
}
WebTorrent.WEBRTC_SUPPORT = Peer.WEBRTC_SUPPORT
WebTorrent.VERSION = VERSION
/**
* Check if `obj` is a node Readable stream
* @param {*} obj
* @return {boolean}
*/
function isReadable (obj) {
return typeof obj === 'object' && obj != null && typeof obj.pipe === 'function'
}
/**
* Check if `obj` is a W3C `FileList` object
* @param {*} obj
* @return {boolean}
*/
function isFileList (obj) {
return typeof FileList !== 'undefined' && obj instanceof FileList
}
module.exports = WebTorrent
}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
},{"./lib/conn-pool":55,"./lib/torrent":314,"./package.json":334,"_process":187,"bittorrent-dht/client":55,"buffer":60,"create-torrent":80,"debug":316,"events":98,"load-ip-set":55,"parse-torrent":184,"path":185,"randombytes":195,"run-parallel":218,"simple-concat":221,"simple-peer":223,"speedometer":263}],310:[function(require,module,exports){
const debug = require('debug')('webtorrent:file-stream')
const stream = require('readable-stream')
/**
* Readable stream of a torrent file
*
* @param {File} file
* @param {Object} opts
* @param {number} opts.start stream slice of file, starting from this byte (inclusive)
* @param {number} opts.end stream slice of file, ending with this byte (inclusive)
*/
class FileStream extends stream.Readable {
constructor (file, opts) {
super(opts)
this.destroyed = false
this._torrent = file._torrent
const start = (opts && opts.start) || 0
const end = (opts && opts.end && opts.end < file.length)
? opts.end
: file.length - 1
const pieceLength = file._torrent.pieceLength
this._startPiece = (start + file.offset) / pieceLength | 0
this._endPiece = (end + file.offset) / pieceLength | 0
this._piece = this._startPiece
this._offset = (start + file.offset) - (this._startPiece * pieceLength)
this._missing = end - start + 1
this._reading = false
this._notifying = false
this._criticalLength = Math.min((1024 * 1024 / pieceLength) | 0, 2)
}
_read () {
if (this._reading) return
this._reading = true
this._notify()
}
_notify () {
if (!this._reading || this._missing === 0) return
if (!this._torrent.bitfield.get(this._piece)) {
return this._torrent.critical(this._piece, this._piece + this._criticalLength)
}
if (this._notifying) return
this._notifying = true
if (this._torrent.destroyed) return this._destroy(new Error('Torrent removed'))
const p = this._piece
this._torrent.store.get(p, (err, buffer) => {
this._notifying = false
if (this.destroyed) return
debug('read %s (length %s) (err %s)', p, buffer.length, err && err.message)
if (err) return this._destroy(err)
if (this._offset) {
buffer = buffer.slice(this._offset)
this._offset = 0
}
if (this._missing < buffer.length) {
buffer = buffer.slice(0, this._missing)
}
this._missing -= buffer.length
debug('pushing buffer of length %s', buffer.length)
this._reading = false
this.push(buffer)
if (this._missing === 0) this.push(null)
})
this._piece += 1
}
destroy (onclose) {
this._destroy(null, onclose)
}
_destroy (err, onclose) {
if (this.destroyed) return
this.destroyed = true
if (!this._torrent.destroyed) {
this._torrent.deselect(this._startPiece, this._endPiece, true)
}
if (err) this.emit('error', err)
this.emit('close')
if (onclose) onclose()
}
}
module.exports = FileStream
},{"debug":316,"readable-stream":333}],311:[function(require,module,exports){
(function (process){(function (){
const { EventEmitter } = require('events')
const { PassThrough } = require('readable-stream')
const eos = require('end-of-stream')
const path = require('path')
const render = require('render-media')
const streamToBlob = require('stream-to-blob')
const streamToBlobURL = require('stream-to-blob-url')
const streamToBuffer = require('stream-with-known-length-to-buffer')
const FileStream = require('./file-stream')
class File extends EventEmitter {
constructor (torrent, file) {
super()
this._torrent = torrent
this._destroyed = false
this.name = file.name
this.path = file.path
this.length = file.length
this.offset = file.offset
this.done = false
const start = file.offset
const end = start + file.length - 1
this._startPiece = start / this._torrent.pieceLength | 0
this._endPiece = end / this._torrent.pieceLength | 0
if (this.length === 0) {
this.done = true
this.emit('done')
}
}
get downloaded () {
if (!this._torrent.bitfield) return 0
const { pieces, bitfield, pieceLength } = this._torrent
const { _startPiece: start, _endPiece: end } = this
const piece = pieces[start]
// First piece may have an offset, e.g. irrelevant bytes from the end of
// the previous file
const irrelevantFirstPieceBytes = this.offset % pieceLength
let downloaded = bitfield.get(start)
? pieceLength - irrelevantFirstPieceBytes
: Math.max(pieceLength - irrelevantFirstPieceBytes - piece.missing, 0)
for (let index = start + 1; index <= end; ++index) {
if (bitfield.get(index)) {
// verified data
downloaded += pieceLength
} else {
// "in progress" data
const piece = pieces[index]
downloaded += pieceLength - piece.missing
}
}
// We don't know the end offset, so return this.length if it's oversized.
// e.g. One small file can fit in the middle of a piece.
return Math.min(downloaded, this.length)
}
get progress () {
return this.length ? this.downloaded / this.length : 0
}
select (priority) {
if (this.length === 0) return
this._torrent.select(this._startPiece, this._endPiece, priority)
}
deselect () {
if (this.length === 0) return
this._torrent.deselect(this._startPiece, this._endPiece, false)
}
createReadStream (opts) {
if (this.length === 0) {
const empty = new PassThrough()
process.nextTick(() => {
empty.end()
})
return empty
}
const fileStream = new FileStream(this, opts)
this._torrent.select(fileStream._startPiece, fileStream._endPiece, true, () => {
fileStream._notify()
})
eos(fileStream, () => {
if (this._destroyed) return
if (!this._torrent.destroyed) {
this._torrent.deselect(fileStream._startPiece, fileStream._endPiece, true)
}
})
return fileStream
}
getBuffer (cb) {
streamToBuffer(this.createReadStream(), this.length, cb)
}
getBlob (cb) {
if (typeof window === 'undefined') throw new Error('browser-only method')
streamToBlob(this.createReadStream(), this._getMimeType())
.then(
blob => cb(null, blob),
err => cb(err)
)
}
getBlobURL (cb) {
if (typeof window === 'undefined') throw new Error('browser-only method')
streamToBlobURL(this.createReadStream(), this._getMimeType())
.then(
blobUrl => cb(null, blobUrl),
err => cb(err)
)
}
appendTo (elem, opts, cb) {
if (typeof window === 'undefined') throw new Error('browser-only method')
render.append(this, elem, opts, cb)
}
renderTo (elem, opts, cb) {
if (typeof window === 'undefined') throw new Error('browser-only method')
render.render(this, elem, opts, cb)
}
_getMimeType () {
return render.mime[path.extname(this.name).toLowerCase()]
}
_destroy () {
this._destroyed = true
this._torrent = null
}
}
module.exports = File
}).call(this)}).call(this,require('_process'))
},{"./file-stream":310,"_process":187,"end-of-stream":96,"events":98,"path":185,"readable-stream":333,"render-media":212,"stream-to-blob":284,"stream-to-blob-url":283,"stream-with-known-length-to-buffer":285}],312:[function(require,module,exports){
const arrayRemove = require('unordered-array-remove')
const debug = require('debug')('webtorrent:peer')
const Wire = require('bittorrent-protocol')
const WebConn = require('./webconn')
const CONNECT_TIMEOUT_TCP = 5000
const CONNECT_TIMEOUT_UTP = 5000
const CONNECT_TIMEOUT_WEBRTC = 25000
const HANDSHAKE_TIMEOUT = 25000
/**
* WebRTC peer connections start out connected, because WebRTC peers require an
* "introduction" (i.e. WebRTC signaling), and there's no equivalent to an IP address
* that lets you refer to a WebRTC endpoint.
*/
exports.createWebRTCPeer = (conn, swarm) => {
const peer = new Peer(conn.id, 'webrtc')
peer.conn = conn
peer.swarm = swarm
if (peer.conn.connected) {
peer.onConnect()
} else {
peer.conn.once('connect', () => { peer.onConnect() })
peer.conn.once('error', err => { peer.destroy(err) })
peer.startConnectTimeout()
}
return peer
}
/**
* Incoming TCP peers start out connected, because the remote peer connected to the
* listening port of the TCP server. Until the remote peer sends a handshake, we don't
* know what swarm the connection is intended for.
*/
exports.createTCPIncomingPeer = conn => {
return _createIncomingPeer(conn, 'tcpIncoming')
}
/**
* Incoming uTP peers start out connected, because the remote peer connected to the
* listening port of the uTP server. Until the remote peer sends a handshake, we don't
* know what swarm the connection is intended for.
*/
exports.createUTPIncomingPeer = conn => {
return _createIncomingPeer(conn, 'utpIncoming')
}
/**
* Outgoing TCP peers start out with just an IP address. At some point (when there is an
* available connection), the client can attempt to connect to the address.
*/
exports.createTCPOutgoingPeer = (addr, swarm) => {
return _createOutgoingPeer(addr, swarm, 'tcpOutgoing')
}
/**
* Outgoing uTP peers start out with just an IP address. At some point (when there is an
* available connection), the client can attempt to connect to the address.
*/
exports.createUTPOutgoingPeer = (addr, swarm) => {
return _createOutgoingPeer(addr, swarm, 'utpOutgoing')
}
const _createIncomingPeer = (conn, type) => {
const addr = `${conn.remoteAddress}:${conn.remotePort}`
const peer = new Peer(addr, type)
peer.conn = conn
peer.addr = addr
peer.onConnect()
return peer
}
const _createOutgoingPeer = (addr, swarm, type) => {
const peer = new Peer(addr, type)
peer.addr = addr
peer.swarm = swarm
return peer
}
/**
* Peer that represents a Web Seed (BEP17 / BEP19).
*/
exports.createWebSeedPeer = (url, swarm) => {
const peer = new Peer(url, 'webSeed')
peer.swarm = swarm
peer.conn = new WebConn(url, swarm)
peer.onConnect()
return peer
}
/**
* Peer. Represents a peer in the torrent swarm.
*
* @param {string} id "ip:port" string, peer id (for WebRTC peers), or url (for Web Seeds)
* @param {string} type the type of the peer
*/
class Peer {
constructor (id, type) {
this.id = id
this.type = type
debug('new %s Peer %s', type, id)
this.addr = null
this.conn = null
this.swarm = null
this.wire = null
this.connected = false
this.destroyed = false
this.timeout = null // handshake timeout
this.retries = 0 // outgoing TCP connection retry count
this.sentHandshake = false
}
/**
* Called once the peer is connected (i.e. fired 'connect' event)
* @param {Socket} conn
*/
onConnect () {
if (this.destroyed) return
this.connected = true
debug('Peer %s connected', this.id)
clearTimeout(this.connectTimeout)
const conn = this.conn
conn.once('end', () => {
this.destroy()
})
conn.once('close', () => {
this.destroy()
})
conn.once('finish', () => {
this.destroy()
})
conn.once('error', err => {
this.destroy(err)
})
const wire = this.wire = new Wire()
wire.type = this.type
wire.once('end', () => {
this.destroy()
})
wire.once('close', () => {
this.destroy()
})
wire.once('finish', () => {
this.destroy()
})
wire.once('error', err => {
this.destroy(err)
})
wire.once('handshake', (infoHash, peerId) => {
this.onHandshake(infoHash, peerId)
})
this.startHandshakeTimeout()
conn.pipe(wire).pipe(conn)
if (this.swarm && !this.sentHandshake) this.handshake()
}
/**
* Called when handshake is received from remote peer.
* @param {string} infoHash
* @param {string} peerId
*/
onHandshake (infoHash, peerId) {
if (!this.swarm) return // `this.swarm` not set yet, so do nothing
if (this.destroyed) return
if (this.swarm.destroyed) {
return this.destroy(new Error('swarm already destroyed'))
}
if (infoHash !== this.swarm.infoHash) {
return this.destroy(new Error('unexpected handshake info hash for this swarm'))
}
if (peerId === this.swarm.peerId) {
return this.destroy(new Error('refusing to connect to ourselves'))
}
debug('Peer %s got handshake %s', this.id, infoHash)
clearTimeout(this.handshakeTimeout)
this.retries = 0
let addr = this.addr
if (!addr && this.conn.remoteAddress && this.conn.remotePort) {
addr = `${this.conn.remoteAddress}:${this.conn.remotePort}`
}
this.swarm._onWire(this.wire, addr)
// swarm could be destroyed in user's 'wire' event handler
if (!this.swarm || this.swarm.destroyed) return
if (!this.sentHandshake) this.handshake()
}
handshake () {
const opts = {
dht: this.swarm.private ? false : !!this.swarm.client.dht
}
this.wire.handshake(this.swarm.infoHash, this.swarm.client.peerId, opts)
this.sentHandshake = true
}
startConnectTimeout () {
clearTimeout(this.connectTimeout)
const connectTimeoutValues = {
webrtc: CONNECT_TIMEOUT_WEBRTC,
tcpOutgoing: CONNECT_TIMEOUT_TCP,
utpOutgoing: CONNECT_TIMEOUT_UTP
}
this.connectTimeout = setTimeout(() => {
this.destroy(new Error('connect timeout'))
}, connectTimeoutValues[this.type])
if (this.connectTimeout.unref) this.connectTimeout.unref()
}
startHandshakeTimeout () {
clearTimeout(this.handshakeTimeout)
this.handshakeTimeout = setTimeout(() => {
this.destroy(new Error('handshake timeout'))
}, HANDSHAKE_TIMEOUT)
if (this.handshakeTimeout.unref) this.handshakeTimeout.unref()
}
destroy (err) {
if (this.destroyed) return
this.destroyed = true
this.connected = false
debug('destroy %s %s (error: %s)', this.type, this.id, err && (err.message || err))
clearTimeout(this.connectTimeout)
clearTimeout(this.handshakeTimeout)
const swarm = this.swarm
const conn = this.conn
const wire = this.wire
this.swarm = null
this.conn = null
this.wire = null
if (swarm && wire) {
arrayRemove(swarm.wires, swarm.wires.indexOf(wire))
}
if (conn) {
conn.on('error', () => {})
conn.destroy()
}
if (wire) wire.destroy()
if (swarm) swarm.removePeer(this.id)
}
}
},{"./webconn":315,"bittorrent-protocol":11,"debug":316,"unordered-array-remove":298}],313:[function(require,module,exports){
/**
* Mapping of torrent pieces to their respective availability in the torrent swarm. Used
* by the torrent manager for implementing the rarest piece first selection strategy.
*/
class RarityMap {
constructor (torrent) {
this._torrent = torrent
this._numPieces = torrent.pieces.length
this._pieces = new Array(this._numPieces)
this._onWire = wire => {
this.recalculate()
this._initWire(wire)
}
this._onWireHave = index => {
this._pieces[index] += 1
}
this._onWireBitfield = () => {
this.recalculate()
}
this._torrent.wires.forEach(wire => {
this._initWire(wire)
})
this._torrent.on('wire', this._onWire)
this.recalculate()
}
/**
* Get the index of the rarest piece. Optionally, pass a filter function to exclude
* certain pieces (for instance, those that we already have).
*
* @param {function} pieceFilterFunc
* @return {number} index of rarest piece, or -1
*/
getRarestPiece (pieceFilterFunc) {
let candidates = []
let min = Infinity
for (let i = 0; i < this._numPieces; ++i) {
if (pieceFilterFunc && !pieceFilterFunc(i)) continue
const availability = this._pieces[i]
if (availability === min) {
candidates.push(i)
} else if (availability < min) {
candidates = [i]
min = availability
}
}
if (candidates.length) {
// if there are multiple pieces with the same availability, choose one randomly
return candidates[Math.random() * candidates.length | 0]
} else {
return -1
}
}
destroy () {
this._torrent.removeListener('wire', this._onWire)
this._torrent.wires.forEach(wire => {
this._cleanupWireEvents(wire)
})
this._torrent = null
this._pieces = null
this._onWire = null
this._onWireHave = null
this._onWireBitfield = null
}
_initWire (wire) {
wire._onClose = () => {
this._cleanupWireEvents(wire)
for (let i = 0; i < this._numPieces; ++i) {
this._pieces[i] -= wire.peerPieces.get(i)
}
}
wire.on('have', this._onWireHave)
wire.on('bitfield', this._onWireBitfield)
wire.once('close', wire._onClose)
}
/**
* Recalculates piece availability across all peers in the torrent.
*/
recalculate () {
this._pieces.fill(0)
for (const wire of this._torrent.wires) {
for (let i = 0; i < this._numPieces; ++i) {
this._pieces[i] += wire.peerPieces.get(i)
}
}
}
_cleanupWireEvents (wire) {
wire.removeListener('have', this._onWireHave)
wire.removeListener('bitfield', this._onWireBitfield)
if (wire._onClose) wire.removeListener('close', wire._onClose)
wire._onClose = null
}
}
module.exports = RarityMap
},{}],314:[function(require,module,exports){
(function (process,global){(function (){
/* global Blob */
const addrToIPPort = require('addr-to-ip-port')
const BitField = require('bitfield')
const ChunkStoreWriteStream = require('chunk-store-stream/write')
const debug = require('debug')('webtorrent:torrent')
const Discovery = require('torrent-discovery')
const EventEmitter = require('events').EventEmitter
const fs = require('fs')
const FSChunkStore = require('fs-chunk-store') // browser: `memory-chunk-store`
const get = require('simple-get')
const ImmediateChunkStore = require('immediate-chunk-store')
const MultiStream = require('multistream')
const net = require('net') // browser exclude
const os = require('os') // browser exclude
const parallel = require('run-parallel')
const parallelLimit = require('run-parallel-limit')
const parseTorrent = require('parse-torrent')
const path = require('path')
const Piece = require('torrent-piece')
const pump = require('pump')
const randomIterate = require('random-iterate')
const sha1 = require('simple-sha1')
const speedometer = require('speedometer')
const utMetadata = require('ut_metadata')
const utPex = require('ut_pex') // browser exclude
const utp = require('utp-native') // browser exclude
const File = require('./file')
const Peer = require('./peer')
const RarityMap = require('./rarity-map')
const Server = require('./server') // browser exclude
const MAX_BLOCK_LENGTH = 128 * 1024
const PIECE_TIMEOUT = 30000
const CHOKE_TIMEOUT = 5000
const SPEED_THRESHOLD = 3 * Piece.BLOCK_LENGTH
const PIPELINE_MIN_DURATION = 0.5
const PIPELINE_MAX_DURATION = 1
const RECHOKE_INTERVAL = 10000 // 10 seconds
const RECHOKE_OPTIMISTIC_DURATION = 2 // 30 seconds
// IndexedDB chunk stores used in the browser benefit from maximum concurrency
const FILESYSTEM_CONCURRENCY = process.browser ? Infinity : 2
const RECONNECT_WAIT = [1000, 5000, 15000]
const VERSION = require('../package.json').version
const USER_AGENT = `WebTorrent/${VERSION} (https://webtorrent.io)`
let TMP
try {
TMP = path.join(fs.statSync('/tmp') && '/tmp', 'webtorrent')
} catch (err) {
TMP = path.join(typeof os.tmpdir === 'function' ? os.tmpdir() : '/', 'webtorrent')
}
class Torrent extends EventEmitter {
constructor (torrentId, client, opts) {
super()
this._debugId = 'unknown infohash'
this.client = client
this.announce = opts.announce
this.urlList = opts.urlList
this.path = opts.path
this.skipVerify = !!opts.skipVerify
this._store = opts.store || FSChunkStore
this._getAnnounceOpts = opts.getAnnounceOpts
// if defined, `opts.private` overrides default privacy of torrent
if (typeof opts.private === 'boolean') this.private = opts.private
this.strategy = opts.strategy || 'sequential'
this.maxWebConns = opts.maxWebConns || 4
this._rechokeNumSlots = (opts.uploads === false || opts.uploads === 0)
? 0
: (+opts.uploads || 10)
this._rechokeOptimisticWire = null
this._rechokeOptimisticTime = 0
this._rechokeIntervalId = null
this.ready = false
this.destroyed = false
this.paused = false
this.done = false
this.metadata = null
this.store = null
this.files = []
this.pieces = []
this._amInterested = false
this._selections = []
this._critical = []
this.wires = [] // open wires (added *after* handshake)
this._queue = [] // queue of outgoing tcp peers to connect to
this._peers = {} // connected peers (addr/peerId -> Peer)
this._peersLength = 0 // number of elements in `this._peers` (cache, for perf)
// stats
this.received = 0
this.uploaded = 0
this._downloadSpeed = speedometer()
this._uploadSpeed = speedometer()
// for cleanup
this._servers = []
this._xsRequests = []
// TODO: remove this and expose a hook instead
// optimization: don't recheck every file if it hasn't changed
this._fileModtimes = opts.fileModtimes
if (torrentId !== null) this._onTorrentId(torrentId)
this._debug('new torrent')
}
get timeRemaining () {
if (this.done) return 0
if (this.downloadSpeed === 0) return Infinity
return ((this.length - this.downloaded) / this.downloadSpeed) * 1000
}
get downloaded () {
if (!this.bitfield) return 0
let downloaded = 0
for (let index = 0, len = this.pieces.length; index < len; ++index) {
if (this.bitfield.get(index)) { // verified data
downloaded += (index === len - 1) ? this.lastPieceLength : this.pieceLength
} else { // "in progress" data
const piece = this.pieces[index]
downloaded += (piece.length - piece.missing)
}
}
return downloaded
}
// TODO: re-enable this. The number of missing pieces. Used to implement 'end game' mode.
// Object.defineProperty(Storage.prototype, 'numMissing', {
// get: function () {
// var self = this
// var numMissing = self.pieces.length
// for (var index = 0, len = self.pieces.length; index < len; index++) {
// numMissing -= self.bitfield.get(index)
// }
// return numMissing
// }
// })
get downloadSpeed () { return this._downloadSpeed() }
get uploadSpeed () { return this._uploadSpeed() }
get progress () { return this.length ? this.downloaded / this.length : 0 }
get ratio () { return this.uploaded / (this.received || this.length) }
get numPeers () { return this.wires.length }
get torrentFileBlobURL () {
if (typeof window === 'undefined') throw new Error('browser-only property')
if (!this.torrentFile) return null
return URL.createObjectURL(
new Blob([this.torrentFile], { type: 'application/x-bittorrent' })
)
}
get _numQueued () {
return this._queue.length + (this._peersLength - this._numConns)
}
get _numConns () {
let numConns = 0
for (const id in this._peers) {
if (this._peers[id].connected) numConns += 1
}
return numConns
}
// TODO: remove in v1
get swarm () {
console.warn('WebTorrent: `torrent.swarm` is deprecated. Use `torrent` directly instead.')
return this
}
_onTorrentId (torrentId) {
if (this.destroyed) return
let parsedTorrent
try { parsedTorrent = parseTorrent(torrentId) } catch (err) {}
if (parsedTorrent) {
// Attempt to set infoHash property synchronously
this.infoHash = parsedTorrent.infoHash
this._debugId = parsedTorrent.infoHash.toString('hex').substring(0, 7)
process.nextTick(() => {
if (this.destroyed) return
this._onParsedTorrent(parsedTorrent)
})
} else {
// If torrentId failed to parse, it could be in a form that requires an async
// operation, i.e. http/https link, filesystem path, or Blob.
parseTorrent.remote(torrentId, (err, parsedTorrent) => {
if (this.destroyed) return
if (err) return this._destroy(err)
this._onParsedTorrent(parsedTorrent)
})
}
}
_onParsedTorrent (parsedTorrent) {
if (this.destroyed) return
this._processParsedTorrent(parsedTorrent)
if (!this.infoHash) {
return this._destroy(new Error('Malformed torrent data: No info hash'))
}
if (!this.path) this.path = path.join(TMP, this.infoHash)
this._rechokeIntervalId = setInterval(() => {
this._rechoke()
}, RECHOKE_INTERVAL)
if (this._rechokeIntervalId.unref) this._rechokeIntervalId.unref()
// Private 'infoHash' event allows client.add to check for duplicate torrents and
// destroy them before the normal 'infoHash' event is emitted. Prevents user
// applications from needing to deal with duplicate 'infoHash' events.
this.emit('_infoHash', this.infoHash)
if (this.destroyed) return
this.emit('infoHash', this.infoHash)
if (this.destroyed) return // user might destroy torrent in event handler
if (this.client.listening) {
this._onListening()
} else {
this.client.once('listening', () => {
this._onListening()
})
}
}
_processParsedTorrent (parsedTorrent) {
this._debugId = parsedTorrent.infoHash.toString('hex').substring(0, 7)
if (typeof this.private !== 'undefined') {
// `private` option overrides default, only if it's defined
parsedTorrent.private = this.private
}
if (this.announce) {
// Allow specifying trackers via `opts` parameter
parsedTorrent.announce = parsedTorrent.announce.concat(this.announce)
}
if (this.client.tracker && global.WEBTORRENT_ANNOUNCE && !parsedTorrent.private) {
// So `webtorrent-hybrid` can force specific trackers to be used
parsedTorrent.announce = parsedTorrent.announce.concat(global.WEBTORRENT_ANNOUNCE)
}
if (this.urlList) {
// Allow specifying web seeds via `opts` parameter
parsedTorrent.urlList = parsedTorrent.urlList.concat(this.urlList)
}
// remove duplicates by converting to Set and back
parsedTorrent.announce = Array.from(new Set(parsedTorrent.announce))
parsedTorrent.urlList = Array.from(new Set(parsedTorrent.urlList))
Object.assign(this, parsedTorrent)
this.magnetURI = parseTorrent.toMagnetURI(parsedTorrent)
this.torrentFile = parseTorrent.toTorrentFile(parsedTorrent)
}
_onListening () {
if (this.destroyed) return
if (this.info) {
// if full metadata was included in initial torrent id, use it immediately. Otherwise,
// wait for torrent-discovery to find peers and ut_metadata to get the metadata.
this._onMetadata(this)
} else {
if (this.xs) this._getMetadataFromServer()
this._startDiscovery()
}
}
_startDiscovery () {
if (this.discovery || this.destroyed) return
let trackerOpts = this.client.tracker
if (trackerOpts) {
trackerOpts = Object.assign({}, this.client.tracker, {
getAnnounceOpts: () => {
const opts = {
uploaded: this.uploaded,
downloaded: this.downloaded,
left: Math.max(this.length - this.downloaded, 0)
}
if (this.client.tracker.getAnnounceOpts) {
Object.assign(opts, this.client.tracker.getAnnounceOpts())
}
if (this._getAnnounceOpts) {
// TODO: consider deprecating this, as it's redundant with the former case
Object.assign(opts, this._getAnnounceOpts())
}
return opts
}
})
}
// add BEP09 peer-address
if (this.peerAddresses) {
this.peerAddresses.forEach(peer => this.addPeer(peer))
}
// begin discovering peers via DHT and trackers
this.discovery = new Discovery({
infoHash: this.infoHash,
announce: this.announce,
peerId: this.client.peerId,
dht: !this.private && this.client.dht,
tracker: trackerOpts,
port: this.client.torrentPort,
userAgent: USER_AGENT
})
this.discovery.on('error', (err) => {
this._destroy(err)
})
this.discovery.on('peer', (peer) => {
// Don't create new outgoing TCP connections when torrent is done
if (typeof peer === 'string' && this.done) return
this.addPeer(peer)
})
this.discovery.on('trackerAnnounce', () => {
this.emit('trackerAnnounce')
if (this.numPeers === 0) this.emit('noPeers', 'tracker')
})
this.discovery.on('dhtAnnounce', () => {
this.emit('dhtAnnounce')
if (this.numPeers === 0) this.emit('noPeers', 'dht')
})
this.discovery.on('warning', (err) => {
this.emit('warning', err)
})
}
_getMetadataFromServer () {
// to allow function hoisting
const self = this
const urls = Array.isArray(this.xs) ? this.xs : [this.xs]
const tasks = urls.map(url => cb => {
getMetadataFromURL(url, cb)
})
parallel(tasks)
function getMetadataFromURL (url, cb) {
if (url.indexOf('http://') !== 0 && url.indexOf('https://') !== 0) {
self.emit('warning', new Error(`skipping non-http xs param: ${url}`))
return cb(null)
}
const opts = {
url,
method: 'GET',
headers: {
'user-agent': USER_AGENT
}
}
let req
try {
req = get.concat(opts, onResponse)
} catch (err) {
self.emit('warning', new Error(`skipping invalid url xs param: ${url}`))
return cb(null)
}
self._xsRequests.push(req)
function onResponse (err, res, torrent) {
if (self.destroyed) return cb(null)
if (self.metadata) return cb(null)
if (err) {
self.emit('warning', new Error(`http error from xs param: ${url}`))
return cb(null)
}
if (res.statusCode !== 200) {
self.emit('warning', new Error(`non-200 status code ${res.statusCode} from xs param: ${url}`))
return cb(null)
}
let parsedTorrent
try {
parsedTorrent = parseTorrent(torrent)
} catch (err) {}
if (!parsedTorrent) {
self.emit('warning', new Error(`got invalid torrent file from xs param: ${url}`))
return cb(null)
}
if (parsedTorrent.infoHash !== self.infoHash) {
self.emit('warning', new Error(`got torrent file with incorrect info hash from xs param: ${url}`))
return cb(null)
}
self._onMetadata(parsedTorrent)
cb(null)
}
}
}
/**
* Called when the full torrent metadata is received.
*/
_onMetadata (metadata) {
if (this.metadata || this.destroyed) return
this._debug('got metadata')
this._xsRequests.forEach(req => {
req.abort()
})
this._xsRequests = []
let parsedTorrent
if (metadata && metadata.infoHash) {
// `metadata` is a parsed torrent (from parse-torrent module)
parsedTorrent = metadata
} else {
try {
parsedTorrent = parseTorrent(metadata)
} catch (err) {
return this._destroy(err)
}
}
this._processParsedTorrent(parsedTorrent)
this.metadata = this.torrentFile
// add web seed urls (BEP19)
if (this.client.enableWebSeeds) {
this.urlList.forEach(url => {
this.addWebSeed(url)
})
}
this._rarityMap = new RarityMap(this)
this.store = new ImmediateChunkStore(
new this._store(this.pieceLength, {
torrent: {
infoHash: this.infoHash
},
files: this.files.map(file => ({
path: path.join(this.path, file.path),
length: file.length,
offset: file.offset
})),
length: this.length,
name: this.infoHash
})
)
this.files = this.files.map(file => new File(this, file))
// Select only specified files (BEP53) http://www.bittorrent.org/beps/bep_0053.html
if (this.so) {
this.files.forEach((v, i) => {
if (this.so.includes(i)) {
this.files[i].select()
} else {
this.files[i].deselect()
}
})
} else {
// start off selecting the entire torrent with low priority
if (this.pieces.length !== 0) {
this.select(0, this.pieces.length - 1, false)
}
}
this._hashes = this.pieces
this.pieces = this.pieces.map((hash, i) => {
const pieceLength = (i === this.pieces.length - 1)
? this.lastPieceLength
: this.pieceLength
return new Piece(pieceLength)
})
this._reservations = this.pieces.map(() => [])
this.bitfield = new BitField(this.pieces.length)
this.wires.forEach(wire => {
// If we didn't have the metadata at the time ut_metadata was initialized for this
// wire, we still want to make it available to the peer in case they request it.
if (wire.ut_metadata) wire.ut_metadata.setMetadata(this.metadata)
this._onWireWithMetadata(wire)
})
// Emit 'metadata' before 'ready' and 'done'
this.emit('metadata')
// User might destroy torrent in response to 'metadata' event
if (this.destroyed) return
if (this.skipVerify) {
// Skip verifying exisitng data and just assume it's correct
this._markAllVerified()
this._onStore()
} else {
const onPiecesVerified = (err) => {
if (err) return this._destroy(err)
this._debug('done verifying')
this._onStore()
}
this._debug('verifying existing torrent data')
if (this._fileModtimes && this._store === FSChunkStore) {
// don't verify if the files haven't been modified since we last checked
this.getFileModtimes((err, fileModtimes) => {
if (err) return this._destroy(err)
const unchanged = this.files.map((_, index) => fileModtimes[index] === this._fileModtimes[index]).every(x => x)
if (unchanged) {
this._markAllVerified()
this._onStore()
} else {
this._verifyPieces(onPiecesVerified)
}
})
} else {
this._verifyPieces(onPiecesVerified)
}
}
}
/*
* TODO: remove this
* Gets the last modified time of every file on disk for this torrent.
* Only valid in Node, not in the browser.
*/
getFileModtimes (cb) {
const ret = []
parallelLimit(this.files.map((file, index) => cb => {
fs.stat(path.join(this.path, file.path), (err, stat) => {
if (err && err.code !== 'ENOENT') return cb(err)
ret[index] = stat && stat.mtime.getTime()
cb(null)
})
}), FILESYSTEM_CONCURRENCY, err => {
this._debug('done getting file modtimes')
cb(err, ret)
})
}
_verifyPieces (cb) {
parallelLimit(this.pieces.map((piece, index) => cb => {
if (this.destroyed) return cb(new Error('torrent is destroyed'))
this.store.get(index, (err, buf) => {
if (this.destroyed) return cb(new Error('torrent is destroyed'))
if (err) return process.nextTick(cb, null) // ignore error
sha1(buf, hash => {
if (this.destroyed) return cb(new Error('torrent is destroyed'))
if (hash === this._hashes[index]) {
if (!this.pieces[index]) return cb(null)
this._debug('piece verified %s', index)
this._markVerified(index)
} else {
this._debug('piece invalid %s', index)
}
cb(null)
})
})
}), FILESYSTEM_CONCURRENCY, cb)
}
rescanFiles (cb) {
if (this.destroyed) throw new Error('torrent is destroyed')
if (!cb) cb = noop
this._verifyPieces((err) => {
if (err) {
this._destroy(err)
return cb(err)
}
this._checkDone()
cb(null)
})
}
_markAllVerified () {
for (let index = 0; index < this.pieces.length; index++) {
this._markVerified(index)
}
}
_markVerified (index) {
this.pieces[index] = null
this._reservations[index] = null
this.bitfield.set(index, true)
}
/**
* Called when the metadata, listening server, and underlying chunk store is initialized.
*/
_onStore () {
if (this.destroyed) return
this._debug('on store')
// Start discovery before emitting 'ready'
this._startDiscovery()
this.ready = true
this.emit('ready')
// Files may start out done if the file was already in the store
this._checkDone()
// In case any selections were made before torrent was ready
this._updateSelections()
}
destroy (opts, cb) {
if (typeof opts === 'function') return this.destroy(null, opts)
this._destroy(null, opts, cb)
}
_destroy (err, opts, cb) {
if (typeof opts === 'function') return this._destroy(err, null, opts)
if (this.destroyed) return
this.destroyed = true
this._debug('destroy')
this.client._remove(this)
clearInterval(this._rechokeIntervalId)
this._xsRequests.forEach(req => {
req.abort()
})
if (this._rarityMap) {
this._rarityMap.destroy()
}
for (const id in this._peers) {
this.removePeer(id)
}
this.files.forEach(file => {
if (file instanceof File) file._destroy()
})
const tasks = this._servers.map(server => cb => {
server.destroy(cb)
})
if (this.discovery) {
tasks.push(cb => {
this.discovery.destroy(cb)
})
}
if (this.store) {
tasks.push(cb => {
if (opts && opts.destroyStore) {
this.store.destroy(cb)
} else {
this.store.close(cb)
}
})
}
parallel(tasks, cb)
if (err) {
// Torrent errors are emitted at `torrent.on('error')`. If there are no 'error'
// event handlers on the torrent instance, then the error will be emitted at
// `client.on('error')`. This prevents throwing an uncaught exception
// (unhandled 'error' event), but it makes it impossible to distinguish client
// errors versus torrent errors. Torrent errors are not fatal, and the client
// is still usable afterwards. Therefore, always listen for errors in both
// places (`client.on('error')` and `torrent.on('error')`).
if (this.listenerCount('error') === 0) {
this.client.emit('error', err)
} else {
this.emit('error', err)
}
}
this.emit('close')
this.client = null
this.files = []
this.discovery = null
this.store = null
this._rarityMap = null
this._peers = null
this._servers = null
this._xsRequests = null
}
addPeer (peer) {
if (this.destroyed) throw new Error('torrent is destroyed')
if (!this.infoHash) throw new Error('addPeer() must not be called before the `infoHash` event')
if (this.client.blocked) {
let host
if (typeof peer === 'string') {
let parts
try {
parts = addrToIPPort(peer)
} catch (e) {
this._debug('ignoring peer: invalid %s', peer)
this.emit('invalidPeer', peer)
return false
}
host = parts[0]
} else if (typeof peer.remoteAddress === 'string') {
host = peer.remoteAddress
}
if (host && this.client.blocked.contains(host)) {
this._debug('ignoring peer: blocked %s', peer)
if (typeof peer !== 'string') peer.destroy()
this.emit('blockedPeer', peer)
return false
}
}
// if the utp connection fails to connect, then it is replaced with a tcp connection to the same ip:port
const wasAdded = !!this._addPeer(peer, this.client.utp ? 'utp' : 'tcp')
if (wasAdded) {
this.emit('peer', peer)
} else {
this.emit('invalidPeer', peer)
}
return wasAdded
}
_addPeer (peer, type) {
if (this.destroyed) {
if (typeof peer !== 'string') peer.destroy()
return null
}
if (typeof peer === 'string' && !this._validAddr(peer)) {
this._debug('ignoring peer: invalid %s', peer)
return null
}
const id = (peer && peer.id) || peer
if (this._peers[id]) {
this._debug('ignoring peer: duplicate (%s)', id)
if (typeof peer !== 'string') peer.destroy()
return null
}
if (this.paused) {
this._debug('ignoring peer: torrent is paused')
if (typeof peer !== 'string') peer.destroy()
return null
}
this._debug('add peer %s', id)
let newPeer
if (typeof peer === 'string') {
// `peer` is an addr ("ip:port" string)
newPeer = type === 'utp' ? Peer.createUTPOutgoingPeer(peer, this) : Peer.createTCPOutgoingPeer(peer, this)
} else {
// `peer` is a WebRTC connection (simple-peer)
newPeer = Peer.createWebRTCPeer(peer, this)
}
this._peers[newPeer.id] = newPeer
this._peersLength += 1
if (typeof peer === 'string') {
// `peer` is an addr ("ip:port" string)
this._queue.push(newPeer)
this._drain()
}
return newPeer
}
addWebSeed (url) {
if (this.destroyed) throw new Error('torrent is destroyed')
if (!/^https?:\/\/.+/.test(url)) {
this.emit('warning', new Error(`ignoring invalid web seed: ${url}`))
this.emit('invalidPeer', url)
return
}
if (this._peers[url]) {
this.emit('warning', new Error(`ignoring duplicate web seed: ${url}`))
this.emit('invalidPeer', url)
return
}
this._debug('add web seed %s', url)
const newPeer = Peer.createWebSeedPeer(url, this)
this._peers[newPeer.id] = newPeer
this._peersLength += 1
this.emit('peer', url)
}
/**
* Called whenever a new incoming TCP peer connects to this torrent swarm. Called with a
* peer that has already sent a handshake.
*/
_addIncomingPeer (peer) {
if (this.destroyed) return peer.destroy(new Error('torrent is destroyed'))
if (this.paused) return peer.destroy(new Error('torrent is paused'))
this._debug('add incoming peer %s', peer.id)
this._peers[peer.id] = peer
this._peersLength += 1
}
removePeer (peer) {
const id = (peer && peer.id) || peer
peer = this._peers[id]
if (!peer) return
this._debug('removePeer %s', id)
delete this._peers[id]
this._peersLength -= 1
peer.destroy()
// If torrent swarm was at capacity before, try to open a new connection now
this._drain()
}
select (start, end, priority, notify) {
if (this.destroyed) throw new Error('torrent is destroyed')
if (start < 0 || end < start || this.pieces.length <= end) {
throw new Error(`invalid selection ${start} : ${end}`)
}
priority = Number(priority) || 0
this._debug('select %s-%s (priority %s)', start, end, priority)
this._selections.push({
from: start,
to: end,
offset: 0,
priority,
notify: notify || noop
})
this._selections.sort((a, b) => b.priority - a.priority)
this._updateSelections()
}
deselect (start, end, priority) {
if (this.destroyed) throw new Error('torrent is destroyed')
priority = Number(priority) || 0
this._debug('deselect %s-%s (priority %s)', start, end, priority)
for (let i = 0; i < this._selections.length; ++i) {
const s = this._selections[i]
if (s.from === start && s.to === end && s.priority === priority) {
this._selections.splice(i, 1)
break
}
}
this._updateSelections()
}
critical (start, end) {
if (this.destroyed) throw new Error('torrent is destroyed')
this._debug('critical %s-%s', start, end)
for (let i = start; i <= end; ++i) {
this._critical[i] = true
}
this._updateSelections()
}
_onWire (wire, addr) {
this._debug('got wire %s (%s)', wire._debugId, addr || 'Unknown')
wire.on('download', downloaded => {
if (this.destroyed) return
this.received += downloaded
this._downloadSpeed(downloaded)
this.client._downloadSpeed(downloaded)
this.emit('download', downloaded)
if (this.destroyed) return
this.client.emit('download', downloaded)
})
wire.on('upload', uploaded => {
if (this.destroyed) return
this.uploaded += uploaded
this._uploadSpeed(uploaded)
this.client._uploadSpeed(uploaded)
this.emit('upload', uploaded)
if (this.destroyed) return
this.client.emit('upload', uploaded)
})
this.wires.push(wire)
if (addr) {
// Sometimes RTCPeerConnection.getStats() doesn't return an ip:port for peers
const parts = addrToIPPort(addr)
wire.remoteAddress = parts[0]
wire.remotePort = parts[1]
}
// When peer sends PORT message, add that DHT node to routing table
if (this.client.dht && this.client.dht.listening) {
wire.on('port', port => {
if (this.destroyed || this.client.dht.destroyed) {
return
}
if (!wire.remoteAddress) {
return this._debug('ignoring PORT from peer with no address')
}
if (port === 0 || port > 65536) {
return this._debug('ignoring invalid PORT from peer')
}
this._debug('port: %s (from %s)', port, addr)
this.client.dht.addNode({ host: wire.remoteAddress, port })
})
}
wire.on('timeout', () => {
this._debug('wire timeout (%s)', addr)
// TODO: this might be destroying wires too eagerly
wire.destroy()
})
// Timeout for piece requests to this peer
wire.setTimeout(PIECE_TIMEOUT, true)
// Send KEEP-ALIVE (every 60s) so peers will not disconnect the wire
wire.setKeepAlive(true)
// use ut_metadata extension
wire.use(utMetadata(this.metadata))
wire.ut_metadata.on('warning', err => {
this._debug('ut_metadata warning: %s', err.message)
})
if (!this.metadata) {
wire.ut_metadata.on('metadata', metadata => {
this._debug('got metadata via ut_metadata')
this._onMetadata(metadata)
})
wire.ut_metadata.fetch()
}
// use ut_pex extension if the torrent is not flagged as private
if (typeof utPex === 'function' && !this.private) {
wire.use(utPex())
wire.ut_pex.on('peer', peer => {
// Only add potential new peers when we're not seeding
if (this.done) return
this._debug('ut_pex: got peer: %s (from %s)', peer, addr)
this.addPeer(peer)
})
wire.ut_pex.on('dropped', peer => {
// the remote peer believes a given peer has been dropped from the torrent swarm.
// if we're not currently connected to it, then remove it from the queue.
const peerObj = this._peers[peer]
if (peerObj && !peerObj.connected) {
this._debug('ut_pex: dropped peer: %s (from %s)', peer, addr)
this.removePeer(peer)
}
})
wire.once('close', () => {
// Stop sending updates to remote peer
wire.ut_pex.reset()
})
}
// Hook to allow user-defined `bittorrent-protocol` extensions
// More info: https://github.com/webtorrent/bittorrent-protocol#extension-api
this.emit('wire', wire, addr)
if (this.metadata) {
process.nextTick(() => {
// This allows wire.handshake() to be called (by Peer.onHandshake) before any
// messages get sent on the wire
this._onWireWithMetadata(wire)
})
}
}
_onWireWithMetadata (wire) {
let timeoutId = null
const onChokeTimeout = () => {
if (this.destroyed || wire.destroyed) return
if (this._numQueued > 2 * (this._numConns - this.numPeers) &&
wire.amInterested) {
wire.destroy()
} else {
timeoutId = setTimeout(onChokeTimeout, CHOKE_TIMEOUT)
if (timeoutId.unref) timeoutId.unref()
}
}
let i
const updateSeedStatus = () => {
if (wire.peerPieces.buffer.length !== this.bitfield.buffer.length) return
for (i = 0; i < this.pieces.length; ++i) {
if (!wire.peerPieces.get(i)) return
}
wire.isSeeder = true
wire.choke() // always choke seeders
}
wire.on('bitfield', () => {
updateSeedStatus()
this._update()
this._updateWireInterest(wire)
})
wire.on('have', () => {
updateSeedStatus()
this._update()
this._updateWireInterest(wire)
})
wire.once('interested', () => {
wire.unchoke()
})
wire.once('close', () => {
clearTimeout(timeoutId)
})
wire.on('choke', () => {
clearTimeout(timeoutId)
timeoutId = setTimeout(onChokeTimeout, CHOKE_TIMEOUT)
if (timeoutId.unref) timeoutId.unref()
})
wire.on('unchoke', () => {
clearTimeout(timeoutId)
this._update()
})
wire.on('request', (index, offset, length, cb) => {
if (length > MAX_BLOCK_LENGTH) {
// Per spec, disconnect from peers that request >128KB
return wire.destroy()
}
if (this.pieces[index]) return
this.store.get(index, { offset, length }, cb)
})
wire.bitfield(this.bitfield) // always send bitfield (required)
// initialize interest in case bitfield message was already received before above handler was registered
this._updateWireInterest(wire)
// Send PORT message to peers that support DHT
if (wire.peerExtensions.dht && this.client.dht && this.client.dht.listening) {
wire.port(this.client.dht.address().port)
}
if (wire.type !== 'webSeed') { // do not choke on webseeds
timeoutId = setTimeout(onChokeTimeout, CHOKE_TIMEOUT)
if (timeoutId.unref) timeoutId.unref()
}
wire.isSeeder = false
updateSeedStatus()
}
/**
* Called on selection changes.
*/
_updateSelections () {
if (!this.ready || this.destroyed) return
process.nextTick(() => {
this._gcSelections()
})
this._updateInterest()
this._update()
}
/**
* Garbage collect selections with respect to the store's current state.
*/
_gcSelections () {
for (let i = 0; i < this._selections.length; ++i) {
const s = this._selections[i]
const oldOffset = s.offset
// check for newly downloaded pieces in selection
while (this.bitfield.get(s.from + s.offset) && s.from + s.offset < s.to) {
s.offset += 1
}
if (oldOffset !== s.offset) s.notify()
if (s.to !== s.from + s.offset) continue
if (!this.bitfield.get(s.from + s.offset)) continue
this._selections.splice(i, 1) // remove fully downloaded selection
i -= 1 // decrement i to offset splice
s.notify()
this._updateInterest()
}
if (!this._selections.length) this.emit('idle')
}
/**
* Update interested status for all peers.
*/
_updateInterest () {
const prev = this._amInterested
this._amInterested = !!this._selections.length
this.wires.forEach(wire => this._updateWireInterest(wire))
if (prev === this._amInterested) return
if (this._amInterested) this.emit('interested')
else this.emit('uninterested')
}
_updateWireInterest (wire) {
let interested = false
for (let index = 0; index < this.pieces.length; ++index) {
if (this.pieces[index] && wire.peerPieces.get(index)) {
interested = true
break
}
}
if (interested) wire.interested()
else wire.uninterested()
}
/**
* Heartbeat to update all peers and their requests.
*/
_update () {
if (this.destroyed) return
// update wires in random order for better request distribution
const ite = randomIterate(this.wires)
let wire
while ((wire = ite())) {
this._updateWireWrapper(wire)
}
}
_updateWireWrapper (wire) {
const self = this
if (typeof window !== 'undefined' && typeof window.requestIdleCallback === 'function') {
window.requestIdleCallback(function () { self._updateWire(wire) }, { timeout: 250 })
} else {
self._updateWire(wire)
}
}
/**
* Attempts to update a peer's requests
*/
_updateWire (wire) {
// to allow function hoisting
const self = this
if (wire.peerChoking) return
if (!wire.downloaded) return validateWire()
const minOutstandingRequests = getBlockPipelineLength(wire, PIPELINE_MIN_DURATION)
if (wire.requests.length >= minOutstandingRequests) return
const maxOutstandingRequests = getBlockPipelineLength(wire, PIPELINE_MAX_DURATION)
trySelectWire(false) || trySelectWire(true)
function genPieceFilterFunc (start, end, tried, rank) {
return i => i >= start && i <= end && !(i in tried) && wire.peerPieces.get(i) && (!rank || rank(i))
}
// TODO: Do we need both validateWire and trySelectWire?
function validateWire () {
if (wire.requests.length) return
let i = self._selections.length
while (i--) {
const next = self._selections[i]
let piece
if (self.strategy === 'rarest') {
const start = next.from + next.offset
const end = next.to
const len = end - start + 1
const tried = {}
let tries = 0
const filter = genPieceFilterFunc(start, end, tried)
while (tries < len) {
piece = self._rarityMap.getRarestPiece(filter)
if (piece < 0) break
if (self._request(wire, piece, false)) return
tried[piece] = true
tries += 1
}
} else {
for (piece = next.to; piece >= next.from + next.offset; --piece) {
if (!wire.peerPieces.get(piece)) continue
if (self._request(wire, piece, false)) return
}
}
}
// TODO: wire failed to validate as useful; should we close it?
// probably not, since 'have' and 'bitfield' messages might be coming
}
function speedRanker () {
const speed = wire.downloadSpeed() || 1
if (speed > SPEED_THRESHOLD) return () => true
const secs = Math.max(1, wire.requests.length) * Piece.BLOCK_LENGTH / speed
let tries = 10
let ptr = 0
return index => {
if (!tries || self.bitfield.get(index)) return true
let missing = self.pieces[index].missing
for (; ptr < self.wires.length; ptr++) {
const otherWire = self.wires[ptr]
const otherSpeed = otherWire.downloadSpeed()
if (otherSpeed < SPEED_THRESHOLD) continue
if (otherSpeed <= speed) continue
if (!otherWire.peerPieces.get(index)) continue
if ((missing -= otherSpeed * secs) > 0) continue
tries--
return false
}
return true
}
}
function shufflePriority (i) {
let last = i
for (let j = i; j < self._selections.length && self._selections[j].priority; j++) {
last = j
}
const tmp = self._selections[i]
self._selections[i] = self._selections[last]
self._selections[last] = tmp
}
function trySelectWire (hotswap) {
if (wire.requests.length >= maxOutstandingRequests) return true
const rank = speedRanker()
for (let i = 0; i < self._selections.length; i++) {
const next = self._selections[i]
let piece
if (self.strategy === 'rarest') {
const start = next.from + next.offset
const end = next.to
const len = end - start + 1
const tried = {}
let tries = 0
const filter = genPieceFilterFunc(start, end, tried, rank)
while (tries < len) {
piece = self._rarityMap.getRarestPiece(filter)
if (piece < 0) break
while (self._request(wire, piece, self._critical[piece] || hotswap)) {
// body intentionally empty
// request all non-reserved blocks in this piece
}
if (wire.requests.length < maxOutstandingRequests) {
tried[piece] = true
tries++
continue
}
if (next.priority) shufflePriority(i)
return true
}
} else {
for (piece = next.from + next.offset; piece <= next.to; piece++) {
if (!wire.peerPieces.get(piece) || !rank(piece)) continue
while (self._request(wire, piece, self._critical[piece] || hotswap)) {
// body intentionally empty
// request all non-reserved blocks in piece
}
if (wire.requests.length < maxOutstandingRequests) continue
if (next.priority) shufflePriority(i)
return true
}
}
}
return false
}
}
/**
* Called periodically to update the choked status of all peers, handling optimistic
* unchoking as described in BEP3.
*/
_rechoke () {
if (!this.ready) return
// wires in increasing order of quality (pop() gives next best peer)
const wireStack =
this.wires
.map(wire => ({ wire, random: Math.random() })) // insert a random seed for randomizing the sort
.sort((objA, objB) => {
const wireA = objA.wire
const wireB = objB.wire
// prefer peers that send us data faster
if (wireA.downloadSpeed() !== wireB.downloadSpeed()) {
return wireA.downloadSpeed() - wireB.downloadSpeed()
}
// then prefer peers that can download data from us faster
if (wireA.uploadSpeed() !== wireB.uploadSpeed()) {
return wireA.uploadSpeed() - wireB.uploadSpeed()
}
// then prefer already unchoked peers (to minimize fibrillation)
if (wireA.amChoking !== wireB.amChoking) {
return wireA.amChoking ? -1 : 1 // choking < unchoked
}
// otherwise random order
return objA.random - objB.random
})
.map(obj => obj.wire) // return array of wires (remove random seed)
if (this._rechokeOptimisticTime <= 0) {
// clear old optimistic peer, so it can be rechoked normally and then replaced
this._rechokeOptimisticWire = null
} else {
this._rechokeOptimisticTime -= 1
}
let numInterestedUnchoked = 0
// leave one rechoke slot open for optimistic unchoking
while (wireStack.length > 0 && numInterestedUnchoked < this._rechokeNumSlots - 1) {
const wire = wireStack.pop() // next best quality peer
if (wire.isSeeder || wire === this._rechokeOptimisticWire) {
continue
}
wire.unchoke()
// only stop unchoking once we fill the slots with interested peers that will actually download
if (wire.peerInterested) {
numInterestedUnchoked++
}
}
// fill optimistic unchoke slot if empty
if (this._rechokeOptimisticWire === null && this._rechokeNumSlots > 0) {
// don't optimistically unchoke uninterested peers
const remaining = wireStack.filter(wire => wire.peerInterested)
if (remaining.length > 0) {
// select random remaining (not yet unchoked) peer
const newOptimisticPeer = remaining[randomInt(remaining.length)]
newOptimisticPeer.unchoke()
this._rechokeOptimisticWire = newOptimisticPeer
this._rechokeOptimisticTime = RECHOKE_OPTIMISTIC_DURATION
}
}
// choke the rest
wireStack
.filter(wire => wire !== this._rechokeOptimisticWire) // except the optimistically unchoked peer
.forEach(wire => wire.choke())
}
/**
* Attempts to cancel a slow block request from another wire such that the
* given wire may effectively swap out the request for one of its own.
*/
_hotswap (wire, index) {
const speed = wire.downloadSpeed()
if (speed < Piece.BLOCK_LENGTH) return false
if (!this._reservations[index]) return false
const r = this._reservations[index]
if (!r) {
return false
}
let minSpeed = Infinity
let minWire
let i
for (i = 0; i < r.length; i++) {
const otherWire = r[i]
if (!otherWire || otherWire === wire) continue
const otherSpeed = otherWire.downloadSpeed()
if (otherSpeed >= SPEED_THRESHOLD) continue
if (2 * otherSpeed > speed || otherSpeed > minSpeed) continue
minWire = otherWire
minSpeed = otherSpeed
}
if (!minWire) return false
for (i = 0; i < r.length; i++) {
if (r[i] === minWire) r[i] = null
}
for (i = 0; i < minWire.requests.length; i++) {
const req = minWire.requests[i]
if (req.piece !== index) continue
this.pieces[index].cancel((req.offset / Piece.BLOCK_LENGTH) | 0)
}
this.emit('hotswap', minWire, wire, index)
return true
}
/**
* Attempts to request a block from the given wire.
*/
_request (wire, index, hotswap) {
const self = this
const numRequests = wire.requests.length
const isWebSeed = wire.type === 'webSeed'
if (self.bitfield.get(index)) return false
const maxOutstandingRequests = isWebSeed
? Math.min(
getPiecePipelineLength(wire, PIPELINE_MAX_DURATION, self.pieceLength),
self.maxWebConns
)
: getBlockPipelineLength(wire, PIPELINE_MAX_DURATION)
if (numRequests >= maxOutstandingRequests) return false
// var endGame = (wire.requests.length === 0 && self.store.numMissing < 30)
const piece = self.pieces[index]
let reservation = isWebSeed ? piece.reserveRemaining() : piece.reserve()
if (reservation === -1 && hotswap && self._hotswap(wire, index)) {
reservation = isWebSeed ? piece.reserveRemaining() : piece.reserve()
}
if (reservation === -1) return false
let r = self._reservations[index]
if (!r) r = self._reservations[index] = []
let i = r.indexOf(null)
if (i === -1) i = r.length
r[i] = wire
const chunkOffset = piece.chunkOffset(reservation)
const chunkLength = isWebSeed ? piece.chunkLengthRemaining(reservation) : piece.chunkLength(reservation)
wire.request(index, chunkOffset, chunkLength, function onChunk (err, chunk) {
if (self.destroyed) return
// TODO: what is this for?
if (!self.ready) return self.once('ready', () => { onChunk(err, chunk) })
if (r[i] === wire) r[i] = null
if (piece !== self.pieces[index]) return onUpdateTick()
if (err) {
self._debug(
'error getting piece %s (offset: %s length: %s) from %s: %s',
index, chunkOffset, chunkLength, `${wire.remoteAddress}:${wire.remotePort}`,
err.message
)
isWebSeed ? piece.cancelRemaining(reservation) : piece.cancel(reservation)
onUpdateTick()
return
}
self._debug(
'got piece %s (offset: %s length: %s) from %s',
index, chunkOffset, chunkLength, `${wire.remoteAddress}:${wire.remotePort}`
)
if (!piece.set(reservation, chunk, wire)) return onUpdateTick()
const buf = piece.flush()
// TODO: might need to set self.pieces[index] = null here since sha1 is async
sha1(buf, hash => {
if (self.destroyed) return
if (hash === self._hashes[index]) {
if (!self.pieces[index]) return
self._debug('piece verified %s', index)
self.pieces[index] = null
self._reservations[index] = null
self.bitfield.set(index, true)
self.store.put(index, buf)
self.wires.forEach(wire => {
wire.have(index)
})
// We also check `self.destroyed` since `torrent.destroy()` could have been
// called in the `torrent.on('done')` handler, triggered by `_checkDone()`.
if (self._checkDone() && !self.destroyed) self.discovery.complete()
} else {
self.pieces[index] = new Piece(piece.length)
self.emit('warning', new Error(`Piece ${index} failed verification`))
}
onUpdateTick()
})
})
function onUpdateTick () {
process.nextTick(() => { self._update() })
}
return true
}
_checkDone () {
if (this.destroyed) return
// are any new files done?
this.files.forEach(file => {
if (file.done) return
for (let i = file._startPiece; i <= file._endPiece; ++i) {
if (!this.bitfield.get(i)) return
}
file.done = true
file.emit('done')
this._debug(`file done: ${file.name}`)
})
// is the torrent done? (if all current selections are satisfied, or there are
// no selections, then torrent is done)
let done = true
for (let i = 0; i < this._selections.length; i++) {
const selection = this._selections[i]
for (let piece = selection.from; piece <= selection.to; piece++) {
if (!this.bitfield.get(piece)) {
done = false
break
}
}
if (!done) break
}
if (!this.done && done) {
this.done = true
this._debug(`torrent done: ${this.infoHash}`)
this.emit('done')
}
this._gcSelections()
return done
}
load (streams, cb) {
if (this.destroyed) throw new Error('torrent is destroyed')
if (!this.ready) return this.once('ready', () => { this.load(streams, cb) })
if (!Array.isArray(streams)) streams = [streams]
if (!cb) cb = noop
const readable = new MultiStream(streams)
const writable = new ChunkStoreWriteStream(this.store, this.pieceLength)
pump(readable, writable, err => {
if (err) return cb(err)
this._markAllVerified()
this._checkDone()
cb(null)
})
}
createServer (requestListener) {
if (typeof Server !== 'function') throw new Error('node.js-only method')
if (this.destroyed) throw new Error('torrent is destroyed')
const server = new Server(this, requestListener)
this._servers.push(server)
return server
}
pause () {
if (this.destroyed) return
this._debug('pause')
this.paused = true
}
resume () {
if (this.destroyed) return
this._debug('resume')
this.paused = false
this._drain()
}
_debug () {
const args = [].slice.call(arguments)
args[0] = `[${this.client ? this.client._debugId : 'No Client'}] [${this._debugId}] ${args[0]}`
debug(...args)
}
/**
* Pop a peer off the FIFO queue and connect to it. When _drain() gets called,
* the queue will usually have only one peer in it, except when there are too
* many peers (over `this.maxConns`) in which case they will just sit in the
* queue until another connection closes.
*/
_drain () {
this._debug('_drain numConns %s maxConns %s', this._numConns, this.client.maxConns)
if (typeof net.connect !== 'function' || this.destroyed || this.paused ||
this._numConns >= this.client.maxConns) {
return
}
this._debug('drain (%s queued, %s/%s peers)', this._numQueued, this.numPeers, this.client.maxConns)
const peer = this._queue.shift()
if (!peer) return // queue could be empty
this._debug('%s connect attempt to %s', peer.type, peer.addr)
const parts = addrToIPPort(peer.addr)
const opts = {
host: parts[0],
port: parts[1]
}
if (peer.type === 'utpOutgoing') {
peer.conn = utp.connect(opts.port, opts.host)
} else {
peer.conn = net.connect(opts)
}
const conn = peer.conn
conn.once('connect', () => { peer.onConnect() })
conn.once('error', err => { peer.destroy(err) })
peer.startConnectTimeout()
// When connection closes, attempt reconnect after timeout (with exponential backoff)
conn.on('close', () => {
if (this.destroyed) return
if (peer.retries >= RECONNECT_WAIT.length) {
if (this.client.utp) {
const newPeer = this._addPeer(peer.addr, 'tcp')
if (newPeer) newPeer.retries = 0
} else {
this._debug(
'conn %s closed: will not re-add (max %s attempts)',
peer.addr, RECONNECT_WAIT.length
)
}
return
}
const ms = RECONNECT_WAIT[peer.retries]
this._debug(
'conn %s closed: will re-add to queue in %sms (attempt %s)',
peer.addr, ms, peer.retries + 1
)
const reconnectTimeout = setTimeout(() => {
if (this.destroyed) return
const newPeer = this._addPeer(peer.addr, this.client.utp ? 'utp' : 'tcp')
if (newPeer) newPeer.retries = peer.retries + 1
}, ms)
if (reconnectTimeout.unref) reconnectTimeout.unref()
})
}
/**
* Returns `true` if string is valid IPv4/6 address.
* @param {string} addr
* @return {boolean}
*/
_validAddr (addr) {
let parts
try {
parts = addrToIPPort(addr)
} catch (e) {
return false
}
const host = parts[0]
const port = parts[1]
return port > 0 && port < 65535 &&
!(host === '127.0.0.1' && port === this.client.torrentPort)
}
}
function getBlockPipelineLength (wire, duration) {
return 2 + Math.ceil(duration * wire.downloadSpeed() / Piece.BLOCK_LENGTH)
}
function getPiecePipelineLength (wire, duration, pieceLength) {
return 1 + Math.ceil(duration * wire.downloadSpeed() / pieceLength)
}
/**
* Returns a random integer in [0,high)
*/
function randomInt (high) {
return Math.random() * high | 0
}
function noop () {}
module.exports = Torrent
}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../package.json":334,"./file":311,"./peer":312,"./rarity-map":313,"./server":55,"_process":187,"addr-to-ip-port":3,"bitfield":10,"chunk-store-stream/write":78,"debug":316,"events":98,"fs":56,"fs-chunk-store":141,"immediate-chunk-store":118,"multistream":166,"net":55,"os":55,"parse-torrent":184,"path":185,"pump":188,"random-iterate":194,"run-parallel":218,"run-parallel-limit":217,"simple-get":222,"simple-sha1":242,"speedometer":263,"torrent-discovery":291,"torrent-piece":295,"ut_metadata":301,"ut_pex":55,"utp-native":55}],315:[function(require,module,exports){
(function (Buffer){(function (){
const BitField = require('bitfield')
const debug = require('debug')('webtorrent:webconn')
const get = require('simple-get')
const sha1 = require('simple-sha1')
const Wire = require('bittorrent-protocol')
const VERSION = require('../package.json').version
/**
* Converts requests for torrent blocks into http range requests.
* @param {string} url web seed url
* @param {Object} torrent
*/
class WebConn extends Wire {
constructor (url, torrent) {
super()
this.url = url
this.webPeerId = sha1.sync(url)
this._torrent = torrent
this._init()
}
_init () {
this.setKeepAlive(true)
this.once('handshake', (infoHash, peerId) => {
if (this.destroyed) return
this.handshake(infoHash, this.webPeerId)
const numPieces = this._torrent.pieces.length
const bitfield = new BitField(numPieces)
for (let i = 0; i <= numPieces; i++) {
bitfield.set(i, true)
}
this.bitfield(bitfield)
})
this.once('interested', () => {
debug('interested')
this.unchoke()
})
this.on('uninterested', () => { debug('uninterested') })
this.on('choke', () => { debug('choke') })
this.on('unchoke', () => { debug('unchoke') })
this.on('bitfield', () => { debug('bitfield') })
this.on('request', (pieceIndex, offset, length, callback) => {
debug('request pieceIndex=%d offset=%d length=%d', pieceIndex, offset, length)
this.httpRequest(pieceIndex, offset, length, callback)
})
}
httpRequest (pieceIndex, offset, length, cb) {
const pieceOffset = pieceIndex * this._torrent.pieceLength
const rangeStart = pieceOffset + offset /* offset within whole torrent */
const rangeEnd = rangeStart + length - 1
// Web seed URL format:
// For single-file torrents, make HTTP range requests directly to the web seed URL
// For multi-file torrents, add the torrent folder and file name to the URL
const files = this._torrent.files
let requests
if (files.length <= 1) {
requests = [{
url: this.url,
start: rangeStart,
end: rangeEnd
}]
} else {
const requestedFiles = files.filter(file => {
return file.offset <= rangeEnd && (file.offset + file.length) > rangeStart
})
if (requestedFiles.length < 1) {
return cb(new Error('Could not find file corresponnding to web seed range request'))
}
requests = requestedFiles.map(requestedFile => {
const fileEnd = requestedFile.offset + requestedFile.length - 1
const url = this.url +
(this.url[this.url.length - 1] === '/' ? '' : '/') +
requestedFile.path
return {
url,
fileOffsetInRange: Math.max(requestedFile.offset - rangeStart, 0),
start: Math.max(rangeStart - requestedFile.offset, 0),
end: Math.min(fileEnd, rangeEnd - requestedFile.offset)
}
})
}
// Now make all the HTTP requests we need in order to load this piece
// Usually that's one requests, but sometimes it will be multiple
// Send requests in parallel and wait for them all to come back
let numRequestsSucceeded = 0
let hasError = false
let ret
if (requests.length > 1) {
ret = Buffer.alloc(length)
}
requests.forEach(request => {
const url = request.url
const start = request.start
const end = request.end
debug(
'Requesting url=%s pieceIndex=%d offset=%d length=%d start=%d end=%d',
url, pieceIndex, offset, length, start, end
)
const opts = {
url,
method: 'GET',
headers: {
'user-agent': `WebTorrent/${VERSION} (https://webtorrent.io)`,
range: `bytes=${start}-${end}`
}
}
function onResponse (res, data) {
if (res.statusCode < 200 || res.statusCode >= 300) {
hasError = true
return cb(new Error(`Unexpected HTTP status code ${res.statusCode}`))
}
debug('Got data of length %d', data.length)
if (requests.length === 1) {
// Common case: fetch piece in a single HTTP request, return directly
cb(null, data)
} else {
// Rare case: reconstruct multiple HTTP requests across 2+ files into one
// piece buffer
data.copy(ret, request.fileOffsetInRange)
if (++numRequestsSucceeded === requests.length) {
cb(null, ret)
}
}
}
get.concat(opts, (err, res, data) => {
if (hasError) return
if (err) {
// Browsers allow HTTP redirects for simple cross-origin
// requests but not for requests that require preflight.
// Use a simple request to unravel any redirects and get the
// final URL. Retry the original request with the new URL if
// it's different.
//
// This test is imperfect but it's simple and good for common
// cases. It catches all cross-origin cases but matches a few
// same-origin cases too.
if (typeof window === 'undefined' || url.startsWith(`${window.location.origin}/`)) {
hasError = true
return cb(err)
}
return get.head(url, (errHead, res) => {
if (hasError) return
if (errHead) {
hasError = true
return cb(errHead)
}
if (res.statusCode < 200 || res.statusCode >= 300) {
hasError = true
return cb(new Error(`Unexpected HTTP status code ${res.statusCode}`))
}
if (res.url === url) {
hasError = true
return cb(err)
}
opts.url = res.url
get.concat(opts, (err, res, data) => {
if (hasError) return
if (err) {
hasError = true
return cb(err)
}
onResponse(res, data)
})
})
}
onResponse(res, data)
})
})
}
destroy () {
super.destroy()
this._torrent = null
}
}
module.exports = WebConn
}).call(this)}).call(this,require("buffer").Buffer)
},{"../package.json":334,"bitfield":10,"bittorrent-protocol":11,"buffer":60,"debug":316,"simple-get":222,"simple-sha1":242}],316:[function(require,module,exports){
arguments[4][13][0].apply(exports,arguments)
},{"./common":317,"_process":187,"dup":13}],317:[function(require,module,exports){
arguments[4][14][0].apply(exports,arguments)
},{"dup":14,"ms":318}],318:[function(require,module,exports){
arguments[4][15][0].apply(exports,arguments)
},{"dup":15}],319:[function(require,module,exports){
arguments[4][16][0].apply(exports,arguments)
},{"dup":16}],320:[function(require,module,exports){
arguments[4][17][0].apply(exports,arguments)
},{"./_stream_readable":322,"./_stream_writable":324,"_process":187,"dup":17,"inherits":119}],321:[function(require,module,exports){
arguments[4][18][0].apply(exports,arguments)
},{"./_stream_transform":323,"dup":18,"inherits":119}],322:[function(require,module,exports){
arguments[4][19][0].apply(exports,arguments)
},{"../errors":319,"./_stream_duplex":320,"./internal/streams/async_iterator":325,"./internal/streams/buffer_list":326,"./internal/streams/destroy":327,"./internal/streams/from":329,"./internal/streams/state":331,"./internal/streams/stream":332,"_process":187,"buffer":60,"dup":19,"events":98,"inherits":119,"string_decoder/":286,"util":55}],323:[function(require,module,exports){
arguments[4][20][0].apply(exports,arguments)
},{"../errors":319,"./_stream_duplex":320,"dup":20,"inherits":119}],324:[function(require,module,exports){
arguments[4][21][0].apply(exports,arguments)
},{"../errors":319,"./_stream_duplex":320,"./internal/streams/destroy":327,"./internal/streams/state":331,"./internal/streams/stream":332,"_process":187,"buffer":60,"dup":21,"inherits":119,"util-deprecate":306}],325:[function(require,module,exports){
arguments[4][22][0].apply(exports,arguments)
},{"./end-of-stream":328,"_process":187,"dup":22}],326:[function(require,module,exports){
arguments[4][23][0].apply(exports,arguments)
},{"buffer":60,"dup":23,"util":55}],327:[function(require,module,exports){
arguments[4][24][0].apply(exports,arguments)
},{"_process":187,"dup":24}],328:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"../../../errors":319,"dup":25}],329:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26}],330:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"../../../errors":319,"./end-of-stream":328,"dup":27}],331:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"../../../errors":319,"dup":28}],332:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29,"events":98}],333:[function(require,module,exports){
arguments[4][30][0].apply(exports,arguments)
},{"./lib/_stream_duplex.js":320,"./lib/_stream_passthrough.js":321,"./lib/_stream_readable.js":322,"./lib/_stream_transform.js":323,"./lib/_stream_writable.js":324,"./lib/internal/streams/end-of-stream.js":328,"./lib/internal/streams/pipeline.js":330,"dup":30}],334:[function(require,module,exports){
module.exports={
"version": "0.110.1"
}
},{}],335:[function(require,module,exports){
// Returns a wrapper function that returns a wrapped callback
// The wrapper function should do some stuff, and return a
// presumably different callback function.
// This makes sure that own properties are retained, so that
// decorations and such are not lost along the way.
module.exports = wrappy
function wrappy (fn, cb) {
if (fn && cb) return wrappy(fn)(cb)
if (typeof fn !== 'function')
throw new TypeError('need wrapper function')
Object.keys(fn).forEach(function (k) {
wrapper[k] = fn[k]
})
return wrapper
function wrapper() {
var args = new Array(arguments.length)
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i]
}
var ret = fn.apply(this, args)
var cb = args[args.length-1]
if (typeof ret === 'function' && ret !== cb) {
Object.keys(cb).forEach(function (k) {
ret[k] = cb[k]
})
}
return ret
}
}
},{}],336:[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
}
},{}],337:[function(require,module,exports){
const clipboard = require('clipboard');
const parser = require('parse-torrent');
const Buffer = require('Buffer');
const bytes = require('bytes');
const mime = require('mime-types');
const WebTorrent = require('webtorrent');
const tippy = require('tippy.js').default;
var properties = document.getElementById('properties');
var originalSourceIcon = document.getElementById('originalSourceIcon');
var source;
var sourceTooltip = tippy(originalSourceIcon, {"theme": "torrent-parts", "animation": "shift-away-subtle"});
var name = document.getElementById('name');
var reset = document.getElementById('reset');
var created = document.getElementById('created');
var createdBy = document.getElementById('createdBy');
var comment = document.getElementById('comment');
var hash = document.getElementById('hash');
var addTrackers = document.getElementById('addTrackers');
var addTracker = document.getElementById('addTracker');
var removeTrackers = document.getElementById('removeTrackers');
var announce = document.getElementById('announce');
var urlList = document.getElementById('urlList');
var addWebseed = document.getElementById('addWebseed');
var removeWebseeds = document.getElementById('removeWebseeds');
var files = document.getElementById('filesBody');
var getFiles = document.getElementById('getFiles');
var copyURL = document.getElementById('copyURL');
var copyMagnet = document.getElementById('copyMagnet');
var downloadTorrent = document.getElementById('downloadTorrent');
var copyURLTooltip = tippy(copyURL, {"theme": "torrent-parts", "animation": "shift-away-subtle", "content": "Copy torrent.parts link to clipboard"});
var copyMagnetTooltip = tippy(copyMagnet, {"theme": "torrent-parts", "animation": "shift-away-subtle", "content": "Copy Magnet link to clipboard"});
var downloadTorrentTooltip = tippy(downloadTorrent, {"theme": "torrent-parts", "animation": "shift-away-subtle", "content": "Download Torrent file"});
var parsed;
var client = new WebTorrent();
var notyf = new Notyf({
"duration": 8000,
"dismissible": true,
"ripple": false,
"position": {
"x": "right",
"y": "top",
},
"types": [
{
"type": "success",
"background": "#46835C",
"icon": false
},
{
"type": "error",
"background": "#A60A0A",
"icon": false
}
]
});
function placeDownloadTooltips(e) {
if (window.innerWidth > 1080) {
copyURLTooltip.setProps({"placement": "right"});
copyMagnetTooltip.setProps({"placement": "right"});
downloadTorrentTooltip.setProps({"placement": "right"});
} else {
copyURLTooltip.setProps({"placement": "top"});
copyMagnetTooltip.setProps({"placement": "top"});
downloadTorrentTooltip.setProps({"placement": "top"});
}
}
window.addEventListener('resize', placeDownloadTooltips);
placeDownloadTooltips();
document.addEventListener('DOMContentLoaded', start);
function start() {
document.getElementById('magnet').addEventListener('keyup', function(event) {
event.preventDefault();
if (event.key === "Enter") {
source = "magnet";
originalSourceIcon.innerHTML = '<span class="fad fa-magnet fa-fw"></span>';
sourceTooltip.setContent("Currently loaded information sourced from Magnet URL");
parse(magnet.value);
}
});
document.getElementById('torrent').addEventListener('change', function(event) {
event.preventDefault();
event.target.files[0].arrayBuffer().then(function(arrayBuffer) {
source = "torrent-file";
originalSourceIcon.innerHTML = '<span class="fad fa-file-alt fa-fw"></span>';
sourceTooltip.setContent("Currently loaded information sourced from Torrent file");
parse(Buffer.from(arrayBuffer));
});
});
let copyurl = new clipboard('#copyURL');
copyurl.on('success', function(e) {
notyf.success('Copied site URL to clipboard!');
console.info(e);
gtag('event', 'share', {
"method": "Copy URL",
"content_id": e.text,
});
});
copyurl.on('failure', function(e) {
notyf.error('Problem copying to clipboard');
console.warn(e);
});
let copymagnet = new clipboard('#copyMagnet');
copymagnet.on('success', function(e) {
notyf.success('Copied Magnet URL to clipboard!');
gtag('event', 'share', {
"method": "Copy Magnet",
"content_id": e.text,
});
});
copymagnet.on('failure', function(e) {
notyf.error('Problem copying to clipboard');
console.warn(e);
});
name.addEventListener('input', propertyChange);
name.addEventListener('change', propertyChange);
name.addEventListener('reset', propertyChange);
name.addEventListener('paste', propertyChange);
reset.addEventListener('click', resetProperties);
comment.addEventListener('input', propertyChange);
comment.addEventListener('change', propertyChange);
comment.addEventListener('reset', propertyChange);
comment.addEventListener('paste', propertyChange);
addTrackers.addEventListener('click', addCurrentTrackers);
addTracker.addEventListener('click', addRow);
removeTrackers.addEventListener('click', () => removeAllRows('announce'));
addWebseed.addEventListener('click', addRow);
removeWebseeds.addEventListener('click', () => removeAllRows('urlList'));
getFiles.addEventListener('click', getFilesFromPeers);
tippy('[data-tippy-content]', {"theme": "torrent-parts", "animation": "shift-away-subtle"}); // all element-defined tooltips
sourceTooltip.disable();
if (window.location.hash) {
source = "shared-url";
originalSourceIcon.innerHTML = '<span class="fad fa-link fa-fw"></span>';
sourceTooltip.setContent("Currently loaded information sourced from shared torrent.parts link");
parse(window.location.hash.split('#')[1]);
}
}
function parse(toLoad) {
resetProperties();
try {
console.info("Attempting parse");
parsed = parser(toLoad);
display();
if (parsed.xs) {
console.info("Magnet includes xs, attempting remote parse");
parseRemote(parsed.xs);
}
}
catch(e) { // maybe they put a URL to a torrent file in the magnet box?
console.warn(e);
if (source == "magnet") {
console.info("Attempting remote parse");
parseRemote(toLoad);
} else { // probably not. Just a bad file.
notyf.error('Problem parsing input. Is this a .torrent file?');
console.error('Problem parsing input');
}
}
}
function parseRemote(toLoad) {
parser.remote(toLoad, function(err, result) {
if (err) {
notyf.error('Problem remotely fetching file or parsing result');
console.warn(err);
resetProperties();
return;
}
source = "remote-torrent-file";
originalSourceIcon.innerHTML = '<span class="fad fa-file-alt fa-fw"></span>';
sourceTooltip.setContent("Currently loaded information sourced from remotely fetched Torrent file");
parsed = result;
display();
});
}
function display() {
console.log(parsed);
hash.value = parsed.infoHash;
name.value = parsed.name ? parsed.name : "";
if (parsed.created) {
created.value = parsed.created.toISOString().slice(0, 19);
created.type = "datetime-local";
} else {
created.type = "text";
}
createdBy.value = parsed.createdBy ? "by " + parsed.createdBy : "";
comment.value = parsed.comment ? parsed.comment : "";
announce.innerHTML = "";
if (parsed.announce && parsed.announce.length) {
for (let i = 0; i < parsed.announce.length; i++) {
let row = document.createElement('div');
row.className = 'announce';
row.dataset.index = i;
let tracker = document.createElement('input');
tracker.type = 'text';
tracker.value = parsed.announce[i];
tracker.dataset.index = i;
tracker.dataset.group = 'announce';
tracker.setAttribute('aria-label', 'Tracker URL #' + i);
tracker.addEventListener('input', propertyChange);
row.appendChild(tracker);
let remove = document.createElement('a');
remove.className = 'remove';
remove.dataset.index = i;
remove.innerHTML = '<span class="far fa-trash"></span>';
remove.addEventListener('click', removeRow);
row.appendChild(remove);
announce.appendChild(row);
}
// } else {
// announce.innerHTML = "<em>No trackers specified in the URL/File provided</em>";
}
urlList.innerHTML = "";
if (parsed.urlList && parsed.urlList.length) {
for (let i = 0; i < parsed.urlList.length; i++) {
let row = document.createElement('div');
row.className = 'urlList';
row.dataset.index = i;
let webseed = document.createElement('input');
webseed.type = 'text';
webseed.value = parsed.urlList[i];
webseed.dataset.index = i;
webseed.dataset.group = 'urlList';
webseed.setAttribute('aria-label', 'Webseed URL #' + i);
webseed.addEventListener('input', propertyChange);
row.appendChild(webseed);
let remove = document.createElement('a');
remove.className = 'remove';
remove.dataset.index = i;
remove.innerHTML = '<span class="far fa-trash"></span>';
remove.addEventListener('click', removeRow);
row.appendChild(remove);
urlList.appendChild(row);
}
// } else {
// urlList.innerHTML = "<em>No webseed URLs in the URL/File provided</em>";
}
files.innerHTML = "";
if (parsed.files && parsed.files.length) {
getFiles.style.display = "none";
for (let file of parsed.files) {
let icon = getFontAwesomeIconForMimetype(mime.lookup(file.name));
files.appendChild(createFileRow(icon, file.name, file.length));
}
files.appendChild(createFileRow('folder-tree', '', parsed.length));
downloadTorrent.addEventListener('click', saveTorrent);
downloadTorrent.disabled = false;
} else {
if (client.torrents.length > 0) {
getFiles.style.display = "none";
files.innerHTML = '<input type="text" placeholder="Attempting fetching of files from Webtorrent..." aria-label="Attempting fetching of files from Webtorrent..." disabled>';
} else {
getFiles.style.display = "block";
files.innerHTML = '<input type="text" placeholder="Not included in the URL/File provided" aria-label="Files information not included in the URL/File provided" disabled>';
}
downloadTorrent.removeEventListener('click', saveTorrent);
downloadTorrent.disabled = true;
}
copyURL.setAttribute('data-clipboard-text', window.location.origin + "#" + parser.toMagnetURI(parsed));
copyMagnet.setAttribute('data-clipboard-text', parser.toMagnetURI(parsed));
properties.style.display = 'flex';
window.location.hash = parser.toMagnetURI(parsed);
if (parsed.name) {
document.title = "Torrent Parts | " + parsed.name;
} else {
document.title = "Torrent Parts | Inspect and edit what's in your Torrent file or Magnet link";
}
sourceTooltip.enable();
gtag('event', 'view_item', {
items: [{
"item_id": parsed.infoHash,
"item_name": parsed.name,
"item_category": source
}]
});
}
function createFileRow(icon, name, size) {
let row = document.createElement('tr');
let iconcell = document.createElement('td');
iconcell.innerHTML = '<span class="far fa-' + icon + '"></span>';
row.appendChild(iconcell);
let namecell = document.createElement('td');
namecell.innerHTML = name;
row.appendChild(namecell);
let totalcell = document.createElement('td');
totalcell.innerHTML = bytes.format(size, {"decimalPlaces": 1, "unitSeparator": " "});
row.appendChild(totalcell);
return row;
}
function getFontAwesomeIconForMimetype(mimetype) {
if (!mimetype) return 'file';
switch (true) {
case mimetype.includes("msword"):
case mimetype.includes("wordprocessingml"):
case mimetype.includes("opendocument.text"):
case mimetype.includes("abiword"):
return 'file-word';
case mimetype.includes("ms-excel"):
case mimetype.includes("spreadsheet"):
return 'file-powerpoint';
case mimetype.includes("powerpoint"):
case mimetype.includes("presentation"):
return 'file-powerpoint';
case mimetype.includes("7z-"):
case mimetype.includes("iso9660"):
case mimetype.includes("zip"):
case mimetype.includes("octet-stream"):
return 'file-archive';
case mimetype.includes("csv"):
return 'file-csv';
case mimetype.includes("pdf"):
return 'file-pdf';
case mimetype.includes("font"):
return 'file-contract';
case mimetype.includes("text"):
case mimetype.includes("subrip"):
case mimetype.includes("vtt"):
return 'file-alt';
case mimetype.includes("audio"):
return 'file-audio';
case mimetype.includes("image"):
return 'file-image';
case mimetype.includes("video"):
return 'file-video';
default:
return 'file';
}
}
function propertyChange(e) {
if (this.dataset.group) {
parsed[this.dataset.group][this.dataset.index] = this.value ? this.value : "";
} else {
parsed[this.id] = this.value ? this.value : "";
}
window.location.hash = parser.toMagnetURI(parsed);
updateModified();
}
function resetProperties() {
document.getElementById('magnet').value = "";
document.getElementById('torrent').value = "";
properties.style.display = 'none';
name.value = "";
created.value = "";
createdBy.value = "";
comment.value = "";
hash.value = "";
announce.innerHTML = "";
urlList.innerHTML = "";
client.torrents.forEach(torrent => torrent.destroy());
getFiles.style.display = "block";
files.innerHTML = "";
window.location.hash = "";
copyURL.setAttribute('data-clipboard-text', "");
copyMagnet.setAttribute('data-clipboard-text', "");
document.title = "Torrent Parts | Inspect and edit what's in your Torrent file or Magnet link";
sourceTooltip.disable();
gtag('event', 'reset');
}
async function addCurrentTrackers() {
addTrackers.className = 'disabled';
addTrackers.innerHTML = 'Adding...';
try {
let response = await fetch("https://newtrackon.com/api/100"); // get trackers with 100% uptime
let trackers = await response.text();
parsed.announce = parsed.announce.concat(trackers.split('\n\n'));
parsed.announce.push("http://bt1.archive.org:6969/announce");
parsed.announce.push("http://bt2.archive.org:6969/announce");
parsed.announce = parsed.announce.filter((v,i) => v && parsed.announce.indexOf(v) === i); // remove duplicates and empties
notyf.success('Added known working trackers from newTrackon');
updateModified();
}
catch(e) {
notyf.error('Problem fetching trackers from newTrackon');
console.warn(e);
}
addTrackers.className = '';
addTrackers.innerHTML = 'Add Known Working Trackers';
display();
gtag('event', 'add_trackers');
}
function addRow() {
parsed[this.dataset.type].unshift("");
display();
}
function removeRow() {
parsed[this.parentElement.className].splice(this.parentElement.dataset.index, 1);
display();
}
function removeAllRows(type) {
parsed[type] = [];
updateModified();
display();
}
function updateModified() {
parsed.created = new Date();
parsed.createdBy = "Torrent Parts <https://torrent.parts/>";
if (parsed.created) {
created.value = parsed.created.toISOString().slice(0, 19);
created.type = "datetime-local";
} else {
created.type = "text";
}
createdBy.value = parsed.createdBy ? "by " + parsed.createdBy : "";
}
function getFilesFromPeers() {
console.info("Attempting fetching files from Webtorrent...");
getFiles.style.display = "none";
parsed.announce.push("wss://tracker.webtorrent.io");
parsed.announce.push("wss://tracker.openwebtorrent.com");
parsed.announce.push("wss://tracker.btorrent.xyz");
parsed.announce.push("wss://tracker.fastcast.nz");
parsed.announce = parsed.announce.filter((v,i) => v && parsed.announce.indexOf(v) === i); // remove duplicates and empties
client.add(parser.toMagnetURI(parsed), (torrent) => {
parsed.info = Object.assign({}, torrent.info); // clone object
parsed.files = torrent.files;
parsed.infoBuffer = torrent.infoBuffer;
parsed.length = torrent.length;
parsed.lastPieceLength = torrent.lastPieceLength;
updateModified();
display();
notyf.success('Fetched file details from Webtorrent peers');
torrent.destroy();
});
display();
gtag('event', 'attempt_webtorrent_fetch');
}
// https://stackoverflow.com/a/36899900/2700296
function saveTorrent() {
let data = parser.toTorrentFile(parsed);
if (data !== null && navigator.msSaveBlob)
return navigator.msSaveBlob(new Blob([data], { "type": "application/x-bittorrent" }), parsed.name + '.torrent');
let a = document.createElement('a');
a.style.display = 'none';
let url = window.URL.createObjectURL(new Blob([data], { "type": "application/x-bittorrent" }));
a.setAttribute("href", url);
a.setAttribute("download", parsed.name + '.torrent');
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
a.remove();
gtag('event', 'share', {
"method": "Torrent Download",
"content_id": parsed.name
});
}
},{"Buffer":2,"bytes":62,"clipboard":79,"mime-types":144,"parse-torrent":184,"tippy.js":289,"webtorrent":309}]},{},[337]);