mirror of
https://github.com/leoherzog/TorrentParts.git
synced 2026-01-24 04:08:04 -08:00
38932 lines
1.0 MiB
38932 lines
1.0 MiB
(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.9.2 - 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
|
||
};
|
||
}
|
||
|
||
function getWindow(node) {
|
||
if (node == null) {
|
||
return window;
|
||
}
|
||
|
||
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
|
||
};
|
||
}
|
||
|
||
function isElement(node) {
|
||
var OwnElement = getWindow(node).Element;
|
||
return node instanceof OwnElement || node instanceof Element;
|
||
}
|
||
|
||
function isHTMLElement(node) {
|
||
var OwnElement = getWindow(node).HTMLElement;
|
||
return node instanceof OwnElement || node instanceof HTMLElement;
|
||
}
|
||
|
||
function isShadowRoot(node) {
|
||
// IE 11 has no ShadowRoot
|
||
if (typeof ShadowRoot === 'undefined') {
|
||
return false;
|
||
}
|
||
|
||
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[incompatible-return]: assume body is always available
|
||
return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]
|
||
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
|
||
};
|
||
}
|
||
|
||
// means it doesn't take into account transforms.
|
||
|
||
function getLayoutRect(element) {
|
||
var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.
|
||
// Fixes https://github.com/popperjs/popper-core/issues/1223
|
||
|
||
var width = element.offsetWidth;
|
||
var height = element.offsetHeight;
|
||
|
||
if (Math.abs(clientRect.width - width) <= 1) {
|
||
width = clientRect.width;
|
||
}
|
||
|
||
if (Math.abs(clientRect.height - height) <= 1) {
|
||
height = clientRect.height;
|
||
}
|
||
|
||
return {
|
||
x: element.offsetLeft,
|
||
y: element.offsetTop,
|
||
width: width,
|
||
height: height
|
||
};
|
||
}
|
||
|
||
function getParentNode(element) {
|
||
if (getNodeName(element) === 'html') {
|
||
return element;
|
||
}
|
||
|
||
return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle
|
||
// $FlowFixMe[incompatible-return]
|
||
// $FlowFixMe[prop-missing]
|
||
element.assignedSlot || // step into the shadow DOM of the parent of a slotted node
|
||
element.parentNode || ( // DOM Element detected
|
||
isShadowRoot(element) ? element.host : null) || // ShadowRoot detected
|
||
// $FlowFixMe[incompatible-call]: HTMLElement is a Node
|
||
getDocumentElement(element) // fallback
|
||
|
||
);
|
||
}
|
||
|
||
function getScrollParent(node) {
|
||
if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {
|
||
// $FlowFixMe[incompatible-return]: 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) {
|
||
var _element$ownerDocumen;
|
||
|
||
if (list === void 0) {
|
||
list = [];
|
||
}
|
||
|
||
var scrollParent = getScrollParent(element);
|
||
var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.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[incompatible-call]: 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;
|
||
}
|
||
|
||
return element.offsetParent;
|
||
} // `.offsetParent` reports `null` for fixed elements, while absolute elements
|
||
// return the containing block
|
||
|
||
|
||
function getContainingBlock(element) {
|
||
var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') !== -1;
|
||
var isIE = navigator.userAgent.indexOf('Trident') !== -1;
|
||
|
||
if (isIE && isHTMLElement(element)) {
|
||
// In IE 9, 10 and 11 fixed elements containing block is always established by the viewport
|
||
var elementCss = getComputedStyle(element);
|
||
|
||
if (elementCss.position === 'fixed') {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
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.
|
||
// https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
|
||
|
||
if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {
|
||
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) === 'html' || 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({}, existing, current, {
|
||
options: Object.assign({}, existing.options, current.options),
|
||
data: 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
|
||
};
|
||
}
|
||
|
||
var max = Math.max;
|
||
var min = Math.min;
|
||
var round = Math.round;
|
||
|
||
// of the `<html>` and `<body>` rect bounds if horizontally scrollable
|
||
|
||
function getDocumentRect(element) {
|
||
var _element$ownerDocumen;
|
||
|
||
var html = getDocumentElement(element);
|
||
var winScroll = getWindowScroll(element);
|
||
var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;
|
||
var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);
|
||
var height = 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 += 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[prop-missing]: 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({}, 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[incompatible-return]: 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 = max(rect.top, accRect.top);
|
||
accRect.right = min(rect.right, accRect.right);
|
||
accRect.bottom = min(rect.bottom, accRect.bottom);
|
||
accRect.left = 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] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);
|
||
break;
|
||
|
||
case end:
|
||
offsets[mainAxis] = offsets[mainAxis] + (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({}, 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({}, 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({}, 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({}, 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$2(_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$2,
|
||
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 roundOffsetsByDPR(_ref) {
|
||
var x = _ref.x,
|
||
y = _ref.y;
|
||
var win = window;
|
||
var dpr = win.devicePixelRatio || 1;
|
||
return {
|
||
x: round(round(x * dpr) / dpr) || 0,
|
||
y: round(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,
|
||
roundOffsets = _ref2.roundOffsets;
|
||
|
||
var _ref3 = roundOffsets === true ? roundOffsetsByDPR(offsets) : typeof roundOffsets === 'function' ? roundOffsets(offsets) : offsets,
|
||
_ref3$x = _ref3.x,
|
||
x = _ref3$x === void 0 ? 0 : _ref3$x,
|
||
_ref3$y = _ref3.y,
|
||
y = _ref3$y === void 0 ? 0 : _ref3$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);
|
||
var heightProp = 'clientHeight';
|
||
var widthProp = 'clientWidth';
|
||
|
||
if (offsetParent === getWindow(popper)) {
|
||
offsetParent = getDocumentElement(popper);
|
||
|
||
if (getComputedStyle(offsetParent).position !== 'static') {
|
||
heightProp = 'scrollHeight';
|
||
widthProp = 'scrollWidth';
|
||
}
|
||
} // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it
|
||
|
||
|
||
offsetParent = offsetParent;
|
||
|
||
if (placement === top) {
|
||
sideY = bottom; // $FlowFixMe[prop-missing]
|
||
|
||
y -= offsetParent[heightProp] - popperRect.height;
|
||
y *= gpuAcceleration ? 1 : -1;
|
||
}
|
||
|
||
if (placement === left) {
|
||
sideX = right; // $FlowFixMe[prop-missing]
|
||
|
||
x -= offsetParent[widthProp] - popperRect.width;
|
||
x *= gpuAcceleration ? 1 : -1;
|
||
}
|
||
}
|
||
|
||
var commonStyles = Object.assign({
|
||
position: position
|
||
}, adaptive && unsetSides);
|
||
|
||
if (gpuAcceleration) {
|
||
var _Object$assign;
|
||
|
||
return 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({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2));
|
||
}
|
||
|
||
function computeStyles(_ref4) {
|
||
var state = _ref4.state,
|
||
options = _ref4.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,
|
||
_options$roundOffsets = options.roundOffsets,
|
||
roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;
|
||
|
||
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({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {
|
||
offsets: state.modifiersData.popperOffsets,
|
||
position: state.options.strategy,
|
||
adaptive: adaptive,
|
||
roundOffsets: roundOffsets
|
||
})));
|
||
}
|
||
|
||
if (state.modifiersData.arrow != null) {
|
||
state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {
|
||
offsets: state.modifiersData.arrow,
|
||
position: 'absolute',
|
||
adaptive: false,
|
||
roundOffsets: roundOffsets
|
||
})));
|
||
}
|
||
|
||
state.attributes.popper = 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[cannot-write]
|
||
|
||
|
||
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);
|
||
state.styles = initialStyles;
|
||
|
||
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;
|
||
}
|
||
|
||
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({}, 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$1 = {
|
||
left: 'right',
|
||
right: 'left',
|
||
bottom: 'top',
|
||
top: 'bottom'
|
||
};
|
||
function getOppositePlacement(placement) {
|
||
return placement.replace(/left|right|bottom|top/g, function (matched) {
|
||
return hash$1[matched];
|
||
});
|
||
}
|
||
|
||
var hash = {
|
||
start: 'end',
|
||
end: 'start'
|
||
};
|
||
function getOppositeVariationPlacement(placement) {
|
||
return placement.replace(/start|end/g, function (matched) {
|
||
return hash[matched];
|
||
});
|
||
}
|
||
|
||
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;
|
||
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[incompatible-type]: 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$1, value, max$1) {
|
||
return max(min$1, min(value, max$1));
|
||
}
|
||
|
||
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({}, state.rects, {
|
||
placement: state.placement
|
||
})) : tetherOffset;
|
||
var data = {
|
||
x: 0,
|
||
y: 0
|
||
};
|
||
|
||
if (!popperOffsets) {
|
||
return;
|
||
}
|
||
|
||
if (checkMainAxis || checkAltAxis) {
|
||
var mainSide = mainAxis === 'y' ? top : left;
|
||
var altSide = mainAxis === 'y' ? bottom : right;
|
||
var len = mainAxis === 'y' ? 'height' : 'width';
|
||
var offset = popperOffsets[mainAxis];
|
||
var min$1 = popperOffsets[mainAxis] + overflow[mainSide];
|
||
var max$1 = 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;
|
||
|
||
if (checkMainAxis) {
|
||
var preventedOffset = within(tether ? min(min$1, tetherMin) : min$1, offset, tether ? max(max$1, tetherMax) : max$1);
|
||
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(tether ? min(_min, tetherMin) : _min, _offset, tether ? max(_max, tetherMax) : _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']
|
||
};
|
||
|
||
var toPaddingObject = function toPaddingObject(padding, state) {
|
||
padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {
|
||
placement: state.placement
|
||
})) : padding;
|
||
return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));
|
||
};
|
||
|
||
function arrow(_ref) {
|
||
var _state$modifiersData$;
|
||
|
||
var state = _ref.state,
|
||
name = _ref.name,
|
||
options = _ref.options;
|
||
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 = toPaddingObject(options.padding, state);
|
||
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(_ref2) {
|
||
var state = _ref2.state,
|
||
options = _ref2.options;
|
||
var _options$element = options.element,
|
||
arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;
|
||
|
||
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;
|
||
} // eslint-disable-next-line import/no-unused-modules
|
||
|
||
|
||
var arrow$1 = {
|
||
name: 'arrow',
|
||
enabled: true,
|
||
phase: 'main',
|
||
fn: arrow,
|
||
effect: effect,
|
||
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({}, 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$1 = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1];
|
||
var createPopper$1 = /*#__PURE__*/popperGenerator({
|
||
defaultModifiers: defaultModifiers$1
|
||
}); // eslint-disable-next-line import/no-unused-modules
|
||
|
||
var defaultModifiers = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1, offset$1, flip$1, preventOverflow$1, arrow$1, hide$1];
|
||
var createPopper = /*#__PURE__*/popperGenerator({
|
||
defaultModifiers: defaultModifiers
|
||
}); // eslint-disable-next-line import/no-unused-modules
|
||
|
||
exports.applyStyles = applyStyles$1;
|
||
exports.arrow = arrow$1;
|
||
exports.computeStyles = computeStyles$1;
|
||
exports.createPopper = createPopper;
|
||
exports.createPopperLite = createPopper$1;
|
||
exports.defaultModifiers = defaultModifiers;
|
||
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":186}],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":57}],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":219}],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":219}],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._timeoutExpiresAt = null
|
||
|
||
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._timeoutMs = ms
|
||
this._timeoutUnref = !!unref
|
||
this._resetTimeout(true)
|
||
}
|
||
|
||
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))
|
||
if (!this._timeout) {
|
||
this._resetTimeout(true)
|
||
}
|
||
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._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._resetTimeout(!this.peerChoking && !this._finished)
|
||
|
||
request.callback(err, buffer)
|
||
}
|
||
|
||
_resetTimeout (setAgain) {
|
||
if (!setAgain || !this._timeoutMs || !this.requests.length) {
|
||
clearTimeout(this._timeout)
|
||
this._timeout = null
|
||
this._timeoutExpiresAt = null
|
||
return
|
||
}
|
||
|
||
const timeoutExpiresAt = Date.now() + this._timeoutMs
|
||
|
||
if (this._timeout) {
|
||
// If existing expiration is already within 5% of correct, it's close enough
|
||
if (timeoutExpiresAt - this._timeoutExpiresAt < this._timeoutMs * 0.05) {
|
||
return
|
||
}
|
||
clearTimeout(this._timeout)
|
||
}
|
||
|
||
this._timeoutExpiresAt = timeoutExpiresAt
|
||
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":57,"debug":13,"randombytes":194,"readable-stream":30,"speedometer":262,"unordered-array-remove":297}],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();
|
||
exports.destroy = (() => {
|
||
let warned = false;
|
||
|
||
return () => {
|
||
if (!warned) {
|
||
warned = true;
|
||
console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
|
||
}
|
||
};
|
||
})();
|
||
|
||
/**
|
||
* 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":186}],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');
|
||
createDebug.destroy = destroy;
|
||
|
||
Object.keys(env).forEach(key => {
|
||
createDebug[key] = env[key];
|
||
});
|
||
|
||
/**
|
||
* 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;
|
||
let enableOverride = null;
|
||
|
||
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 '%';
|
||
}
|
||
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.useColors = createDebug.useColors();
|
||
debug.color = createDebug.selectColor(namespace);
|
||
debug.extend = extend;
|
||
debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.
|
||
|
||
Object.defineProperty(debug, 'enabled', {
|
||
enumerable: true,
|
||
configurable: false,
|
||
get: () => enableOverride === null ? createDebug.enabled(namespace) : enableOverride,
|
||
set: v => {
|
||
enableOverride = v;
|
||
}
|
||
});
|
||
|
||
// Env-specific initialization logic for debug instances
|
||
if (typeof createDebug.init === 'function') {
|
||
createDebug.init(debug);
|
||
}
|
||
|
||
return debug;
|
||
}
|
||
|
||
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 + '$'));
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 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;
|
||
}
|
||
|
||
/**
|
||
* XXX DO NOT USE. This is a temporary stub function.
|
||
* XXX It WILL be removed in the next major release.
|
||
*/
|
||
function destroy() {
|
||
console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
|
||
}
|
||
|
||
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":186,"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":186,"buffer":57,"events":98,"inherits":119,"string_decoder/":285,"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":186,"buffer":57,"inherits":119,"util-deprecate":305}],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":186}],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":57,"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":186}],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 queueMicrotask = require('queue-microtask')
|
||
|
||
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 => {
|
||
queueMicrotask(() => {
|
||
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":186,"buffer":57,"debug":35,"events":98,"once":182,"queue-microtask":192,"run-parallel":217,"simple-peer":222}],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, 5)
|
||
|
||
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)
|
||
|
||
let timeout
|
||
|
||
// 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.
|
||
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)
|
||
})
|
||
this.client.emit('peer', peer)
|
||
peer.signal(data.offer)
|
||
}
|
||
|
||
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)
|
||
this.client.emit('peer', peer)
|
||
peer.signal(data.answer)
|
||
|
||
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":194,"simple-peer":222,"simple-websocket":243}],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')
|
||
}
|
||
|
||
const config = require('./common-node')
|
||
Object.assign(exports, config)
|
||
|
||
}).call(this)}).call(this,require("buffer").Buffer)
|
||
},{"./common-node":55,"buffer":57}],35:[function(require,module,exports){
|
||
arguments[4][13][0].apply(exports,arguments)
|
||
},{"./common":36,"_process":186,"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":57}],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) {
|
||
this._bufferedBytes -= this.size
|
||
|
||
// Assemble the buffers that will compose the final block
|
||
const blockBufs = []
|
||
let blockBufsBytes = 0
|
||
while (blockBufsBytes < this.size) {
|
||
const b = this._buffered.shift()
|
||
|
||
if (blockBufsBytes + b.length <= this.size) {
|
||
blockBufs.push(b)
|
||
blockBufsBytes += b.length
|
||
} else {
|
||
// If the last buffer is larger than needed for the block, just
|
||
// use the needed part
|
||
const neededSize = this.size - blockBufsBytes
|
||
blockBufs.push(b.slice(0, neededSize))
|
||
blockBufsBytes += neededSize
|
||
this._buffered.unshift(b.slice(neededSize))
|
||
}
|
||
}
|
||
|
||
// Then concat just those buffers, leaving the rest untouched in _buffered
|
||
this.push(Buffer.concat(blockBufs, this.size))
|
||
}
|
||
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":57,"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":186,"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":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"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":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],46:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":49,"_process":186,"dup":22}],47:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],48:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"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 (){
|
||
/*!
|
||
* 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":57,"ieee754":117}],58:[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":57}],59:[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":57,"buffer-alloc-unsafe":58,"buffer-fill":60}],60:[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":57}],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":186,"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":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"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":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],69:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":72,"_process":186,"dup":22}],70:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],71:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"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')
|
||
|
||
const zeroPadding = opts.zeroPadding === undefined ? false : opts.zeroPadding
|
||
this._blockstream = new BlockStream(chunkLength, { ...opts, zeroPadding })
|
||
this._outstandingPuts = 0
|
||
this._storeMaxOutstandingPuts = opts.storeMaxOutstandingPuts || 16
|
||
|
||
let index = 0
|
||
const onData = chunk => {
|
||
if (this.destroyed) return
|
||
|
||
this._outstandingPuts += 1
|
||
if (this._outstandingPuts >= this._storeMaxOutstandingPuts) {
|
||
this._blockstream.pause()
|
||
}
|
||
store.put(index, chunk, (err) => {
|
||
if (err) return this.destroy(err)
|
||
this._outstandingPuts -= 1
|
||
if (this._outstandingPuts < this._storeMaxOutstandingPuts) {
|
||
this._blockstream.resume()
|
||
}
|
||
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.8
|
||
* 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() { // webpackBootstrap
|
||
/******/ var __webpack_modules__ = ({
|
||
|
||
/***/ 134:
|
||
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
// EXPORTS
|
||
__webpack_require__.d(__webpack_exports__, {
|
||
"default": function() { return /* binding */ clipboard; }
|
||
});
|
||
|
||
// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js
|
||
var tiny_emitter = __webpack_require__(279);
|
||
var tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);
|
||
// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js
|
||
var listen = __webpack_require__(370);
|
||
var listen_default = /*#__PURE__*/__webpack_require__.n(listen);
|
||
// EXTERNAL MODULE: ./node_modules/select/src/select.js
|
||
var src_select = __webpack_require__(817);
|
||
var select_default = /*#__PURE__*/__webpack_require__.n(src_select);
|
||
;// CONCATENATED MODULE: ./src/clipboard-action.js
|
||
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(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; }
|
||
|
||
|
||
/**
|
||
* Inner class which performs selection from either `text` or `target`
|
||
* properties and then executes copy or cut operations.
|
||
*/
|
||
|
||
var ClipboardAction = /*#__PURE__*/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,
|
||
*/
|
||
|
||
}, {
|
||
key: "createFakeElement",
|
||
value: function createFakeElement() {
|
||
var isRTL = document.documentElement.getAttribute('dir') === 'rtl';
|
||
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 = "".concat(yPosition, "px");
|
||
this.fakeElem.setAttribute('readonly', '');
|
||
this.fakeElem.value = this.text;
|
||
return this.fakeElem;
|
||
}
|
||
/**
|
||
* Get's the value of fakeElem,
|
||
* and makes a selection on it.
|
||
*/
|
||
|
||
}, {
|
||
key: "selectFake",
|
||
value: function selectFake() {
|
||
var _this = this;
|
||
|
||
var fakeElem = this.createFakeElement();
|
||
|
||
this.fakeHandlerCallback = function () {
|
||
return _this.removeFake();
|
||
};
|
||
|
||
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;
|
||
this.container.appendChild(fakeElem);
|
||
this.selectedText = select_default()(fakeElem);
|
||
this.copyText();
|
||
this.removeFake();
|
||
}
|
||
/**
|
||
* 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;
|
||
|
||
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) === '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 = (ClipboardAction);
|
||
;// CONCATENATED MODULE: ./src/clipboard.js
|
||
function clipboard_typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return clipboard_typeof(obj); }
|
||
|
||
function clipboard_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||
|
||
function clipboard_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 clipboard_createClass(Constructor, protoProps, staticProps) { if (protoProps) clipboard_defineProperties(Constructor.prototype, protoProps); if (staticProps) clipboard_defineProperties(Constructor, staticProps); return Constructor; }
|
||
|
||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
|
||
|
||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
|
||
|
||
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
|
||
|
||
function _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
|
||
|
||
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
|
||
|
||
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
|
||
|
||
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
|
||
|
||
|
||
|
||
|
||
/**
|
||
* Helper function to retrieve attribute value.
|
||
* @param {String} suffix
|
||
* @param {Element} element
|
||
*/
|
||
|
||
function getAttributeValue(suffix, element) {
|
||
var attribute = "data-clipboard-".concat(suffix);
|
||
|
||
if (!element.hasAttribute(attribute)) {
|
||
return;
|
||
}
|
||
|
||
return element.getAttribute(attribute);
|
||
}
|
||
/**
|
||
* Base class which takes one or more elements, adds event listeners to them,
|
||
* and instantiates a new `ClipboardAction` on each click.
|
||
*/
|
||
|
||
|
||
var Clipboard = /*#__PURE__*/function (_Emitter) {
|
||
_inherits(Clipboard, _Emitter);
|
||
|
||
var _super = _createSuper(Clipboard);
|
||
|
||
/**
|
||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
|
||
* @param {Object} options
|
||
*/
|
||
function Clipboard(trigger, options) {
|
||
var _this;
|
||
|
||
clipboard_classCallCheck(this, Clipboard);
|
||
|
||
_this = _super.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()));
|
||
|
||
/* harmony default export */ var clipboard = (Clipboard);
|
||
|
||
/***/ }),
|
||
|
||
/***/ 828:
|
||
/***/ (function(module) {
|
||
|
||
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;
|
||
|
||
|
||
/***/ }),
|
||
|
||
/***/ 438:
|
||
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
||
|
||
var closest = __webpack_require__(828);
|
||
|
||
/**
|
||
* 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;
|
||
|
||
|
||
/***/ }),
|
||
|
||
/***/ 879:
|
||
/***/ (function(__unused_webpack_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]';
|
||
};
|
||
|
||
|
||
/***/ }),
|
||
|
||
/***/ 370:
|
||
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
||
|
||
var is = __webpack_require__(879);
|
||
var delegate = __webpack_require__(438);
|
||
|
||
/**
|
||
* 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;
|
||
|
||
|
||
/***/ }),
|
||
|
||
/***/ 817:
|
||
/***/ (function(module) {
|
||
|
||
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;
|
||
|
||
|
||
/***/ }),
|
||
|
||
/***/ 279:
|
||
/***/ (function(module) {
|
||
|
||
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;
|
||
|
||
|
||
/***/ })
|
||
|
||
/******/ });
|
||
/************************************************************************/
|
||
/******/ // The module cache
|
||
/******/ var __webpack_module_cache__ = {};
|
||
/******/
|
||
/******/ // The require function
|
||
/******/ function __webpack_require__(moduleId) {
|
||
/******/ // Check if module is in cache
|
||
/******/ if(__webpack_module_cache__[moduleId]) {
|
||
/******/ return __webpack_module_cache__[moduleId].exports;
|
||
/******/ }
|
||
/******/ // Create a new module (and put it into the cache)
|
||
/******/ var module = __webpack_module_cache__[moduleId] = {
|
||
/******/ // no module.id needed
|
||
/******/ // no module.loaded needed
|
||
/******/ exports: {}
|
||
/******/ };
|
||
/******/
|
||
/******/ // Execute the module function
|
||
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
||
/******/
|
||
/******/ // Return the exports of the module
|
||
/******/ return module.exports;
|
||
/******/ }
|
||
/******/
|
||
/************************************************************************/
|
||
/******/ /* webpack/runtime/compat get default export */
|
||
/******/ !function() {
|
||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||
/******/ __webpack_require__.n = function(module) {
|
||
/******/ var getter = module && module.__esModule ?
|
||
/******/ function() { return module['default']; } :
|
||
/******/ function() { return module; };
|
||
/******/ __webpack_require__.d(getter, { a: getter });
|
||
/******/ return getter;
|
||
/******/ };
|
||
/******/ }();
|
||
/******/
|
||
/******/ /* webpack/runtime/define property getters */
|
||
/******/ !function() {
|
||
/******/ // define getter functions for harmony exports
|
||
/******/ __webpack_require__.d = function(exports, definition) {
|
||
/******/ for(var key in definition) {
|
||
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||
/******/ }
|
||
/******/ }
|
||
/******/ };
|
||
/******/ }();
|
||
/******/
|
||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||
/******/ !function() {
|
||
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
|
||
/******/ }();
|
||
/******/
|
||
/************************************************************************/
|
||
/******/ // module exports must be returned from runtime so entry inlining is disabled
|
||
/******/ // startup
|
||
/******/ // Load entry module and return exports
|
||
/******/ return __webpack_require__(134);
|
||
/******/ })()
|
||
.default;
|
||
});
|
||
},{}],80:[function(require,module,exports){
|
||
(function (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 queueMicrotask = require('queue-microtask')
|
||
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} opts.onProgress
|
||
* @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
|
||
}
|
||
})
|
||
|
||
const filterJunkFiles = opts.filterJunkFiles === undefined ? true : opts.filterJunkFiles
|
||
if (filterJunkFiles) {
|
||
// Remove junk files
|
||
input = input.filter(item => {
|
||
if (typeof item === 'string') {
|
||
return true
|
||
}
|
||
return !isJunkPath(item.path)
|
||
})
|
||
}
|
||
|
||
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
|
||
}
|
||
return false
|
||
})
|
||
}
|
||
|
||
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 {
|
||
queueMicrotask(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)
|
||
})
|
||
}
|
||
}
|
||
|
||
const MAX_OUTSTANDING_HASHES = 5
|
||
|
||
function getPieceList (files, pieceLength, estimatedTorrentLength, opts, cb) {
|
||
cb = once(cb)
|
||
const pieces = []
|
||
let length = 0
|
||
let hashedLength = 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
|
||
if (remainingHashes < MAX_OUTSTANDING_HASHES) {
|
||
blockstream.resume()
|
||
}
|
||
hashedLength += chunk.length
|
||
if (opts.onProgress) opts.onProgress(hashedLength, estimatedTorrentLength)
|
||
maybeDone()
|
||
})
|
||
remainingHashes += 1
|
||
if (remainingHashes >= MAX_OUTSTANDING_HASHES) {
|
||
blockstream.pause()
|
||
}
|
||
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 estimatedTorrentLength = files.reduce(sumLength, 0)
|
||
const pieceLength = opts.pieceLength || calcPieceLength(estimatedTorrentLength)
|
||
torrent.info['piece length'] = pieceLength
|
||
|
||
getPieceList(
|
||
files,
|
||
pieceLength,
|
||
estimatedTorrentLength,
|
||
opts,
|
||
(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))
|
||
}
|
||
)
|
||
}
|
||
|
||
/**
|
||
* Determine if a a file is junk based on its path
|
||
* (defined as hidden OR recognized by the `junk` package)
|
||
*
|
||
* @param {string} path
|
||
* @return {boolean}
|
||
*/
|
||
function isJunkPath (path) {
|
||
const filename = path[path.length - 1]
|
||
return filename[0] === '.' && junk.is(filename)
|
||
}
|
||
|
||
/**
|
||
* 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
|
||
module.exports.isJunkPath = isJunkPath
|
||
|
||
}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
|
||
},{"./get-files":55,"bencode":7,"block-stream2":39,"buffer":57,"filestream/read":114,"is-file":55,"junk":122,"multistream":165,"once":182,"path":184,"piece-length":185,"queue-microtask":192,"readable-stream":95,"run-parallel":217,"simple-sha1":241}],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":186,"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":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"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":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],87:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":90,"_process":186,"dup":22}],88:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],89:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"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":182}],97:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
/**
|
||
* @typedef {{ [key: string]: any }} Extensions
|
||
* @typedef {Error} Err
|
||
* @property {string} message
|
||
*/
|
||
|
||
/**
|
||
*
|
||
* @param {Error} obj
|
||
* @param {Extensions} props
|
||
* @returns {Error & Extensions}
|
||
*/
|
||
function assign(obj, props) {
|
||
for (const key in props) {
|
||
Object.defineProperty(obj, key, {
|
||
value: props[key],
|
||
enumerable: true,
|
||
configurable: true,
|
||
});
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {any} err - An Error
|
||
* @param {string|Extensions} code - A string code or props to set on the error
|
||
* @param {Extensions} [props] - Props to set on the error
|
||
* @returns {Error & Extensions}
|
||
*/
|
||
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 = '';
|
||
}
|
||
|
||
if (code) {
|
||
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));
|
||
|
||
// @ts-ignore
|
||
const output = assign(new ErrClass(), props);
|
||
|
||
return output;
|
||
}
|
||
}
|
||
|
||
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 errorListener(err) {
|
||
emitter.removeListener(name, resolver);
|
||
reject(err);
|
||
}
|
||
|
||
function resolver() {
|
||
if (typeof emitter.removeListener === 'function') {
|
||
emitter.removeListener('error', errorListener);
|
||
}
|
||
resolve([].slice.call(arguments));
|
||
};
|
||
|
||
eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
|
||
if (name !== 'error') {
|
||
addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
|
||
}
|
||
});
|
||
}
|
||
|
||
function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
|
||
if (typeof emitter.on === 'function') {
|
||
eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
|
||
}
|
||
}
|
||
|
||
function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
|
||
if (typeof emitter.on === 'function') {
|
||
if (flags.once) {
|
||
emitter.once(name, listener);
|
||
} else {
|
||
emitter.on(name, listener);
|
||
}
|
||
} else if (typeof emitter.addEventListener === 'function') {
|
||
// EventTarget does not have `error` event semantics like Node
|
||
// EventEmitters, we do not listen for `error` events here.
|
||
emitter.addEventListener(name, function wrapListener(arg) {
|
||
// IE does not have builtin `{ once: true }` support so we
|
||
// have to do it manually.
|
||
if (flags.once) {
|
||
emitter.removeEventListener(name, wrapListener);
|
||
}
|
||
listener(arg);
|
||
});
|
||
} else {
|
||
throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter);
|
||
}
|
||
}
|
||
|
||
},{}],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":186,"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":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"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":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],105:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":108,"_process":186,"dup":22}],106:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],107:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"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":295}],115:[function(require,module,exports){
|
||
// originally pulled out of simple-peer
|
||
|
||
module.exports = function getBrowserRTC () {
|
||
if (typeof globalThis === 'undefined') return null
|
||
var wrtc = {
|
||
RTCPeerConnection: globalThis.RTCPeerConnection || globalThis.mozRTCPeerConnection ||
|
||
globalThis.webkitRTCPeerConnection,
|
||
RTCSessionDescription: globalThis.RTCSessionDescription ||
|
||
globalThis.mozRTCSessionDescription || globalThis.webkitRTCSessionDescription,
|
||
RTCIceCandidate: globalThis.RTCIceCandidate || globalThis.mozRTCIceCandidate ||
|
||
globalThis.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":263,"url":298}],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":192}],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){
|
||
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)]
|
||
}
|
||
|
||
},{}],122:[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;
|
||
|
||
},{}],123:[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.xs) {
|
||
const xss = Array.isArray(result.xs) ? result.xs : [result.xs]
|
||
xss.forEach(xs => {
|
||
if ((m = xs.match(/^urn:btpk:(.{64})/))) {
|
||
result.publicKey = m[1].toLowerCase()
|
||
}
|
||
})
|
||
}
|
||
|
||
if (result.infoHash) result.infoHashBuffer = Buffer.from(result.infoHash, 'hex')
|
||
if (result.publicKey) result.publicKeyBuffer = Buffer.from(result.publicKey, '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.publicKeyBuffer) obj.xs = `urn:btpk:${obj.publicKeyBuffer.toString('hex')}`
|
||
if (obj.publicKey) obj.xs = `urn:btpk:${obj.publicKey}`
|
||
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 === 'as' || key === 'ws') {
|
||
val = encodeURIComponent(val)
|
||
}
|
||
// Don't URI encode BEP46 keys
|
||
if (key === 'xs' && !val.startsWith('urn:btpk:')) {
|
||
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":57,"thirty-two":286}],124:[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":139,"to-arraybuffer":289}],125:[function(require,module,exports){
|
||
arguments[4][16][0].apply(exports,arguments)
|
||
},{"dup":16}],126:[function(require,module,exports){
|
||
arguments[4][17][0].apply(exports,arguments)
|
||
},{"./_stream_readable":128,"./_stream_writable":130,"_process":186,"dup":17,"inherits":119}],127:[function(require,module,exports){
|
||
arguments[4][18][0].apply(exports,arguments)
|
||
},{"./_stream_transform":129,"dup":18,"inherits":119}],128:[function(require,module,exports){
|
||
arguments[4][19][0].apply(exports,arguments)
|
||
},{"../errors":125,"./_stream_duplex":126,"./internal/streams/async_iterator":131,"./internal/streams/buffer_list":132,"./internal/streams/destroy":133,"./internal/streams/from":135,"./internal/streams/state":137,"./internal/streams/stream":138,"_process":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"util":55}],129:[function(require,module,exports){
|
||
arguments[4][20][0].apply(exports,arguments)
|
||
},{"../errors":125,"./_stream_duplex":126,"dup":20,"inherits":119}],130:[function(require,module,exports){
|
||
arguments[4][21][0].apply(exports,arguments)
|
||
},{"../errors":125,"./_stream_duplex":126,"./internal/streams/destroy":133,"./internal/streams/state":137,"./internal/streams/stream":138,"_process":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],131:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":134,"_process":186,"dup":22}],132:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],133:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"dup":24}],134:[function(require,module,exports){
|
||
arguments[4][25][0].apply(exports,arguments)
|
||
},{"../../../errors":125,"dup":25}],135:[function(require,module,exports){
|
||
arguments[4][26][0].apply(exports,arguments)
|
||
},{"dup":26}],136:[function(require,module,exports){
|
||
arguments[4][27][0].apply(exports,arguments)
|
||
},{"../../../errors":125,"./end-of-stream":134,"dup":27}],137:[function(require,module,exports){
|
||
arguments[4][28][0].apply(exports,arguments)
|
||
},{"../../../errors":125,"dup":28}],138:[function(require,module,exports){
|
||
arguments[4][29][0].apply(exports,arguments)
|
||
},{"dup":29,"events":98}],139:[function(require,module,exports){
|
||
arguments[4][30][0].apply(exports,arguments)
|
||
},{"./lib/_stream_duplex.js":126,"./lib/_stream_passthrough.js":127,"./lib/_stream_readable.js":128,"./lib/_stream_transform.js":129,"./lib/_stream_writable.js":130,"./lib/internal/streams/end-of-stream.js":134,"./lib/internal/streams/pipeline.js":136,"dup":30}],140:[function(require,module,exports){
|
||
module.exports = Storage
|
||
|
||
const queueMicrotask = require('queue-microtask')
|
||
|
||
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'))
|
||
|
||
const 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'))
|
||
const buf = this.chunks[index]
|
||
if (!buf) {
|
||
const err = new Error('Chunk not found')
|
||
err.notFound = true
|
||
return nextTick(cb, err)
|
||
}
|
||
if (!opts) return nextTick(cb, null, buf)
|
||
|
||
const offset = opts.offset || 0
|
||
const len = opts.length || (buf.length - offset)
|
||
|
||
if (opts.offset === 0 && len === buf.length - offset) {
|
||
return nextTick(cb, null, buf)
|
||
}
|
||
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) {
|
||
queueMicrotask(function () {
|
||
if (cb) cb(err, val)
|
||
})
|
||
}
|
||
|
||
},{"queue-microtask":192}],141:[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/captive+json": {
|
||
"source": "iana",
|
||
"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/clr": {
|
||
"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": ["es","ecma"]
|
||
},
|
||
"application/edi-consent": {
|
||
"source": "iana"
|
||
},
|
||
"application/edi-x12": {
|
||
"source": "iana",
|
||
"compressible": false
|
||
},
|
||
"application/edifact": {
|
||
"source": "iana",
|
||
"compressible": false
|
||
},
|
||
"application/efi": {
|
||
"source": "iana"
|
||
},
|
||
"application/elm+json": {
|
||
"source": "iana",
|
||
"charset": "UTF-8",
|
||
"compressible": true
|
||
},
|
||
"application/elm+xml": {
|
||
"source": "iana",
|
||
"compressible": true
|
||
},
|
||
"application/emergencycalldata.cap+xml": {
|
||
"source": "iana",
|
||
"charset": "UTF-8",
|
||
"compressible": true
|
||
},
|
||
"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/jscalendar+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
|
||
},
|
||
"application/mrb-publish+xml": {
|
||
"source": "iana",
|
||
"compressible": true
|
||
},
|
||
"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/opc-nodeset+xml": {
|
||
"source": "iana",
|
||
"compressible": true
|
||
},
|
||
"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.cyn": {
|
||
"source": "iana",
|
||
"charset": "7-BIT"
|
||
},
|
||
"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/sarif+json": {
|
||
"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/ubjson": {
|
||
"compressible": false,
|
||
"extensions": ["ubj"]
|
||
},
|
||
"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,
|
||
"extensions": ["td"]
|
||
},
|
||
"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.interworking-data": {
|
||
"source": "iana"
|
||
},
|
||
"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.cmoca-cmresource": {
|
||
"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-cmtable": {
|
||
"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": ["key"]
|
||
},
|
||
"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.cryptomator.encrypted": {
|
||
"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.cyclonedx+json": {
|
||
"source": "iana",
|
||
"compressible": true
|
||
},
|
||
"application/vnd.cyclonedx+xml": {
|
||
"source": "iana",
|
||
"compressible": true
|
||
},
|
||
"application/vnd.d2l.coursepackage1p0+zip": {
|
||
"source": "iana",
|
||
"compressible": false
|
||
},
|
||
"application/vnd.d3m-dataset": {
|
||
"source": "iana"
|
||
},
|
||
"application/vnd.d3m-problem": {
|
||
"source": "iana"
|
||
},
|
||
"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",
|
||
"extensions": ["dbf"]
|
||
},
|
||
"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.slides": {
|
||
"source": "iana"
|
||
},
|
||
"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.nebumind.line": {
|
||
"source": "iana"
|
||
},
|
||
"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+cbor": {
|
||
"source": "iana"
|
||
},
|
||
"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",
|
||
"extensions": ["rar"]
|
||
},
|
||
"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.seis+json": {
|
||
"source": "iana",
|
||
"compressible": true
|
||
},
|
||
"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.sycle+xml": {
|
||
"source": "iana",
|
||
"compressible": true
|
||
},
|
||
"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.dpp": {
|
||
"source": "iana"
|
||
},
|
||
"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
|
||
},
|
||
"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": ["xsl","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",
|
||
"extensions": ["amr"]
|
||
},
|
||
"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","opus"]
|
||
},
|
||
"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/scip": {
|
||
"source": "iana"
|
||
},
|
||
"audio/silk": {
|
||
"source": "apache",
|
||
"extensions": ["sil"]
|
||
},
|
||
"audio/smv": {
|
||
"source": "iana"
|
||
},
|
||
"audio/smv-qcp": {
|
||
"source": "iana"
|
||
},
|
||
"audio/smv0": {
|
||
"source": "iana"
|
||
},
|
||
"audio/sofa": {
|
||
"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/tsvcis": {
|
||
"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/avif": {
|
||
"source": "iana",
|
||
"compressible": false,
|
||
"extensions": ["avif"]
|
||
},
|
||
"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/ktx2": {
|
||
"source": "iana",
|
||
"extensions": ["ktx2"]
|
||
},
|
||
"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.pco.b16": {
|
||
"source": "iana",
|
||
"extensions": ["b16"]
|
||
},
|
||
"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/e57": {
|
||
"source": "iana"
|
||
},
|
||
"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.sap.vds": {
|
||
"source": "iana",
|
||
"extensions": ["vds"]
|
||
},
|
||
"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/cql": {
|
||
"source": "iana"
|
||
},
|
||
"text/cql-expression": {
|
||
"source": "iana"
|
||
},
|
||
"text/cql-identifier": {
|
||
"source": "iana"
|
||
},
|
||
"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/fhirpath": {
|
||
"source": "iana"
|
||
},
|
||
"text/flexfec": {
|
||
"source": "iana"
|
||
},
|
||
"text/fwdred": {
|
||
"source": "iana"
|
||
},
|
||
"text/gff3": {
|
||
"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/shaclc": {
|
||
"source": "iana"
|
||
},
|
||
"text/shex": {
|
||
"extensions": ["shex"]
|
||
},
|
||
"text/slim": {
|
||
"extensions": ["slim","slm"]
|
||
},
|
||
"text/spdx": {
|
||
"source": "iana",
|
||
"extensions": ["spdx"]
|
||
},
|
||
"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.hans": {
|
||
"source": "iana"
|
||
},
|
||
"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/av1": {
|
||
"source": "iana"
|
||
},
|
||
"video/bmpeg": {
|
||
"source": "iana"
|
||
},
|
||
"video/bt656": {
|
||
"source": "iana"
|
||
},
|
||
"video/celb": {
|
||
"source": "iana"
|
||
},
|
||
"video/dv": {
|
||
"source": "iana"
|
||
},
|
||
"video/encaprtp": {
|
||
"source": "iana"
|
||
},
|
||
"video/ffv1": {
|
||
"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",
|
||
"extensions": ["m4s"]
|
||
},
|
||
"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/scip": {
|
||
"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
|
||
}
|
||
}
|
||
|
||
},{}],142:[function(require,module,exports){
|
||
/*!
|
||
* mime-db
|
||
* Copyright(c) 2014 Jonathan Ong
|
||
* MIT Licensed
|
||
*/
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = require('./db.json')
|
||
|
||
},{"./db.json":141}],143:[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":142,"path":184}],144:[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":145,"./index":146,"buffer":57,"uint64be":296}],145:[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":57}],146:[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":144,"buffer":57,"uint64be":296}],147:[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, () => {
|
||
this._pending--
|
||
this._kick()
|
||
})
|
||
}
|
||
|
||
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":57,"mp4-box-encoding":146,"next-event":181,"readable-stream":164}],148:[function(require,module,exports){
|
||
(function (Buffer){(function (){
|
||
var stream = require('readable-stream')
|
||
var Box = require('mp4-box-encoding')
|
||
var queueMicrotask = require('queue-microtask')
|
||
|
||
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 queueMicrotask(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("buffer").Buffer)
|
||
},{"buffer":57,"mp4-box-encoding":146,"queue-microtask":192,"readable-stream":164}],149:[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":147,"./encode":148}],150:[function(require,module,exports){
|
||
arguments[4][16][0].apply(exports,arguments)
|
||
},{"dup":16}],151:[function(require,module,exports){
|
||
arguments[4][17][0].apply(exports,arguments)
|
||
},{"./_stream_readable":153,"./_stream_writable":155,"_process":186,"dup":17,"inherits":119}],152:[function(require,module,exports){
|
||
arguments[4][18][0].apply(exports,arguments)
|
||
},{"./_stream_transform":154,"dup":18,"inherits":119}],153:[function(require,module,exports){
|
||
arguments[4][19][0].apply(exports,arguments)
|
||
},{"../errors":150,"./_stream_duplex":151,"./internal/streams/async_iterator":156,"./internal/streams/buffer_list":157,"./internal/streams/destroy":158,"./internal/streams/from":160,"./internal/streams/state":162,"./internal/streams/stream":163,"_process":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"util":55}],154:[function(require,module,exports){
|
||
arguments[4][20][0].apply(exports,arguments)
|
||
},{"../errors":150,"./_stream_duplex":151,"dup":20,"inherits":119}],155:[function(require,module,exports){
|
||
arguments[4][21][0].apply(exports,arguments)
|
||
},{"../errors":150,"./_stream_duplex":151,"./internal/streams/destroy":158,"./internal/streams/state":162,"./internal/streams/stream":163,"_process":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],156:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":159,"_process":186,"dup":22}],157:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],158:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"dup":24}],159:[function(require,module,exports){
|
||
arguments[4][25][0].apply(exports,arguments)
|
||
},{"../../../errors":150,"dup":25}],160:[function(require,module,exports){
|
||
arguments[4][26][0].apply(exports,arguments)
|
||
},{"dup":26}],161:[function(require,module,exports){
|
||
arguments[4][27][0].apply(exports,arguments)
|
||
},{"../../../errors":150,"./end-of-stream":159,"dup":27}],162:[function(require,module,exports){
|
||
arguments[4][28][0].apply(exports,arguments)
|
||
},{"../../../errors":150,"dup":28}],163:[function(require,module,exports){
|
||
arguments[4][29][0].apply(exports,arguments)
|
||
},{"dup":29,"events":98}],164:[function(require,module,exports){
|
||
arguments[4][30][0].apply(exports,arguments)
|
||
},{"./lib/_stream_duplex.js":151,"./lib/_stream_passthrough.js":152,"./lib/_stream_readable.js":153,"./lib/_stream_transform.js":154,"./lib/_stream_writable.js":155,"./lib/internal/streams/end-of-stream.js":159,"./lib/internal/streams/pipeline.js":161,"dup":30}],165:[function(require,module,exports){
|
||
/*! multistream. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||
const stream = require('readable-stream')
|
||
const once = require('once')
|
||
|
||
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
|
||
|
||
const 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, autoDestroy: true })
|
||
|
||
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
|
||
|
||
let chunk
|
||
while (this._drained && (chunk = this._current.read()) !== null) {
|
||
this._drained = this.push(chunk)
|
||
}
|
||
|
||
this._forwarding = false
|
||
}
|
||
|
||
_destroy (err, cb) {
|
||
let streams = []
|
||
if (this._current) streams.push(this._current)
|
||
if (typeof this._queue !== 'function') streams = streams.concat(this._queue)
|
||
|
||
if (streams.length === 0) {
|
||
cb(err)
|
||
} else {
|
||
let counter = streams.length
|
||
let er = err
|
||
streams.forEach(stream => {
|
||
destroy(stream, err, err => {
|
||
er = er || err
|
||
if (--counter === 0) {
|
||
cb(er)
|
||
}
|
||
})
|
||
})
|
||
}
|
||
}
|
||
|
||
_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 {
|
||
let 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)
|
||
return
|
||
}
|
||
|
||
this._current = stream
|
||
this._forward()
|
||
|
||
const onReadable = () => {
|
||
this._forward()
|
||
}
|
||
|
||
const onClose = () => {
|
||
if (!stream._readableState.ended && !stream.destroyed) {
|
||
const err = new Error('ERR_STREAM_PREMATURE_CLOSE')
|
||
err.code = 'ERR_STREAM_PREMATURE_CLOSE'
|
||
this.destroy(err)
|
||
}
|
||
}
|
||
|
||
const onEnd = () => {
|
||
this._current = null
|
||
stream.removeListener('readable', onReadable)
|
||
stream.removeListener('end', onEnd)
|
||
stream.removeListener('close', onClose)
|
||
stream.destroy()
|
||
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
|
||
|
||
// Normalize stream destroy w/ callback.
|
||
function destroy (stream, err, cb) {
|
||
if (!stream.destroy || stream.destroyed) {
|
||
cb(err)
|
||
} else {
|
||
const callback = once(er => cb(er || err))
|
||
stream
|
||
.on('error', callback)
|
||
.on('close', () => callback())
|
||
.destroy(err, callback)
|
||
}
|
||
}
|
||
|
||
},{"once":182,"readable-stream":180}],166:[function(require,module,exports){
|
||
arguments[4][16][0].apply(exports,arguments)
|
||
},{"dup":16}],167:[function(require,module,exports){
|
||
arguments[4][17][0].apply(exports,arguments)
|
||
},{"./_stream_readable":169,"./_stream_writable":171,"_process":186,"dup":17,"inherits":119}],168:[function(require,module,exports){
|
||
arguments[4][18][0].apply(exports,arguments)
|
||
},{"./_stream_transform":170,"dup":18,"inherits":119}],169:[function(require,module,exports){
|
||
arguments[4][19][0].apply(exports,arguments)
|
||
},{"../errors":166,"./_stream_duplex":167,"./internal/streams/async_iterator":172,"./internal/streams/buffer_list":173,"./internal/streams/destroy":174,"./internal/streams/from":176,"./internal/streams/state":178,"./internal/streams/stream":179,"_process":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"util":55}],170:[function(require,module,exports){
|
||
arguments[4][20][0].apply(exports,arguments)
|
||
},{"../errors":166,"./_stream_duplex":167,"dup":20,"inherits":119}],171:[function(require,module,exports){
|
||
arguments[4][21][0].apply(exports,arguments)
|
||
},{"../errors":166,"./_stream_duplex":167,"./internal/streams/destroy":174,"./internal/streams/state":178,"./internal/streams/stream":179,"_process":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],172:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":175,"_process":186,"dup":22}],173:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],174:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"dup":24}],175:[function(require,module,exports){
|
||
arguments[4][25][0].apply(exports,arguments)
|
||
},{"../../../errors":166,"dup":25}],176:[function(require,module,exports){
|
||
arguments[4][26][0].apply(exports,arguments)
|
||
},{"dup":26}],177:[function(require,module,exports){
|
||
arguments[4][27][0].apply(exports,arguments)
|
||
},{"../../../errors":166,"./end-of-stream":175,"dup":27}],178:[function(require,module,exports){
|
||
arguments[4][28][0].apply(exports,arguments)
|
||
},{"../../../errors":166,"dup":28}],179:[function(require,module,exports){
|
||
arguments[4][29][0].apply(exports,arguments)
|
||
},{"dup":29,"events":98}],180:[function(require,module,exports){
|
||
arguments[4][30][0].apply(exports,arguments)
|
||
},{"./lib/_stream_duplex.js":167,"./lib/_stream_passthrough.js":168,"./lib/_stream_readable.js":169,"./lib/_stream_transform.js":170,"./lib/_stream_writable.js":171,"./lib/internal/streams/end-of-stream.js":175,"./lib/internal/streams/pipeline.js":177,"dup":30}],181:[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
|
||
}
|
||
}
|
||
|
||
},{}],182:[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":334}],183:[function(require,module,exports){
|
||
(function (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')
|
||
const queueMicrotask = require('queue-microtask')
|
||
|
||
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) {
|
||
queueMicrotask(() => {
|
||
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 {
|
||
queueMicrotask(() => {
|
||
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("buffer").Buffer)
|
||
},{"bencode":7,"blob-to-buffer":38,"buffer":57,"fs":55,"magnet-uri":123,"path":184,"queue-microtask":192,"simple-get":221,"simple-sha1":241}],184:[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":186}],185:[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)
|
||
}
|
||
|
||
},{}],186:[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; };
|
||
|
||
},{}],187:[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":186,"end-of-stream":96,"fs":55,"once":182}],188:[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 : {})
|
||
},{}],189:[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]';
|
||
};
|
||
|
||
},{}],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';
|
||
|
||
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;
|
||
};
|
||
|
||
},{}],191:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
exports.decode = exports.parse = require('./decode');
|
||
exports.encode = exports.stringify = require('./encode');
|
||
|
||
},{"./decode":189,"./encode":190}],192:[function(require,module,exports){
|
||
(function (global){(function (){
|
||
/*! queue-microtask. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||
let promise
|
||
|
||
module.exports = typeof queueMicrotask === 'function'
|
||
? queueMicrotask.bind(typeof window !== 'undefined' ? window : global)
|
||
// reuse resolved promise, and allocate it lazily
|
||
: cb => (promise || (promise = Promise.resolve()))
|
||
.then(cb)
|
||
.catch(err => setTimeout(() => { throw err }, 0))
|
||
|
||
}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
},{}],193:[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
|
||
|
||
},{}],194:[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":186,"safe-buffer":219}],195:[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":210}],196:[function(require,module,exports){
|
||
arguments[4][16][0].apply(exports,arguments)
|
||
},{"dup":16}],197:[function(require,module,exports){
|
||
arguments[4][17][0].apply(exports,arguments)
|
||
},{"./_stream_readable":199,"./_stream_writable":201,"_process":186,"dup":17,"inherits":119}],198:[function(require,module,exports){
|
||
arguments[4][18][0].apply(exports,arguments)
|
||
},{"./_stream_transform":200,"dup":18,"inherits":119}],199:[function(require,module,exports){
|
||
arguments[4][19][0].apply(exports,arguments)
|
||
},{"../errors":196,"./_stream_duplex":197,"./internal/streams/async_iterator":202,"./internal/streams/buffer_list":203,"./internal/streams/destroy":204,"./internal/streams/from":206,"./internal/streams/state":208,"./internal/streams/stream":209,"_process":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"util":55}],200:[function(require,module,exports){
|
||
arguments[4][20][0].apply(exports,arguments)
|
||
},{"../errors":196,"./_stream_duplex":197,"dup":20,"inherits":119}],201:[function(require,module,exports){
|
||
arguments[4][21][0].apply(exports,arguments)
|
||
},{"../errors":196,"./_stream_duplex":197,"./internal/streams/destroy":204,"./internal/streams/state":208,"./internal/streams/stream":209,"_process":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],202:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":205,"_process":186,"dup":22}],203:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],204:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"dup":24}],205:[function(require,module,exports){
|
||
arguments[4][25][0].apply(exports,arguments)
|
||
},{"../../../errors":196,"dup":25}],206:[function(require,module,exports){
|
||
arguments[4][26][0].apply(exports,arguments)
|
||
},{"dup":26}],207:[function(require,module,exports){
|
||
arguments[4][27][0].apply(exports,arguments)
|
||
},{"../../../errors":196,"./end-of-stream":205,"dup":27}],208:[function(require,module,exports){
|
||
arguments[4][28][0].apply(exports,arguments)
|
||
},{"../../../errors":196,"dup":28}],209:[function(require,module,exports){
|
||
arguments[4][29][0].apply(exports,arguments)
|
||
},{"dup":29,"events":98}],210:[function(require,module,exports){
|
||
arguments[4][30][0].apply(exports,arguments)
|
||
},{"./lib/_stream_duplex.js":197,"./lib/_stream_passthrough.js":198,"./lib/_stream_readable.js":199,"./lib/_stream_transform.js":200,"./lib/_stream_writable.js":201,"./lib/internal/streams/end-of-stream.js":205,"./lib/internal/streams/pipeline.js":207,"dup":30}],211:[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":212,"debug":213,"is-ascii":120,"mediasource":124,"path":184,"stream-to-blob-url":282,"videostream":307}],212:[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"
|
||
}
|
||
|
||
},{}],213:[function(require,module,exports){
|
||
arguments[4][13][0].apply(exports,arguments)
|
||
},{"./common":214,"_process":186,"dup":13}],214:[function(require,module,exports){
|
||
arguments[4][14][0].apply(exports,arguments)
|
||
},{"dup":14,"ms":215}],215:[function(require,module,exports){
|
||
arguments[4][15][0].apply(exports,arguments)
|
||
},{"dup":15}],216:[function(require,module,exports){
|
||
/*! run-parallel-limit. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||
module.exports = runParallelLimit
|
||
|
||
const queueMicrotask = require('queue-microtask')
|
||
|
||
function runParallelLimit (tasks, limit, cb) {
|
||
if (typeof limit !== 'number') throw new Error('second argument must be a Number')
|
||
let results, len, pending, keys, isErrored
|
||
let isSync = true
|
||
let next
|
||
|
||
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) queueMicrotask(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) {
|
||
let 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) })
|
||
}
|
||
}
|
||
}
|
||
|
||
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
|
||
return false
|
||
})
|
||
} else {
|
||
// array
|
||
tasks.some(function (task, i) {
|
||
task(function (err, result) { each(i, err, result) })
|
||
if (i === limit - 1) return true // early return
|
||
return false
|
||
})
|
||
}
|
||
|
||
isSync = false
|
||
}
|
||
|
||
},{"queue-microtask":192}],217:[function(require,module,exports){
|
||
/*! run-parallel. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||
module.exports = runParallel
|
||
|
||
const queueMicrotask = require('queue-microtask')
|
||
|
||
function runParallel (tasks, cb) {
|
||
let results, pending, keys
|
||
let 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) queueMicrotask(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
|
||
}
|
||
|
||
},{"queue-microtask":192}],218:[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();
|
||
};
|
||
|
||
/***/ })
|
||
/******/ ]);
|
||
});
|
||
},{}],219:[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":57}],220:[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":57}],221:[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":57,"decompress-response":55,"http":263,"https":116,"once":182,"querystring":191,"simple-concat":220,"url":298}],222:[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) {
|
||
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)
|
||
}
|
||
|
||
// HACK: Fix for odd Firefox behavior, see: https://github.com/feross/simple-peer/pull/783
|
||
if (typeof this._pc.peerIdentity === 'object') {
|
||
this._pc.peerIdentity.catch(err => {
|
||
this.destroy(errCode(err, 'ERR_PC_PEER_IDENTITY'))
|
||
})
|
||
}
|
||
|
||
// 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.destroying) return
|
||
if (this.destroyed) throw errCode(new Error('cannot signal after peer is destroyed'), 'ERR_DESTROYED')
|
||
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) {
|
||
if (this.destroying) return
|
||
if (this.destroyed) throw errCode(new Error('cannot send after peer is destroyed'), 'ERR_DESTROYED')
|
||
this._channel.send(chunk)
|
||
}
|
||
|
||
/**
|
||
* Add a Transceiver to the connection.
|
||
* @param {String} kind
|
||
* @param {Object} init
|
||
*/
|
||
addTransceiver (kind, init) {
|
||
if (this.destroying) return
|
||
if (this.destroyed) throw errCode(new Error('cannot addTransceiver after peer is destroyed'), 'ERR_DESTROYED')
|
||
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) {
|
||
if (this.destroying) return
|
||
if (this.destroyed) throw errCode(new Error('cannot addStream after peer is destroyed'), 'ERR_DESTROYED')
|
||
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) {
|
||
if (this.destroying) return
|
||
if (this.destroyed) throw errCode(new Error('cannot addTrack after peer is destroyed'), 'ERR_DESTROYED')
|
||
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) {
|
||
if (this.destroying) return
|
||
if (this.destroyed) throw errCode(new Error('cannot replaceTrack after peer is destroyed'), 'ERR_DESTROYED')
|
||
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) {
|
||
if (this.destroying) return
|
||
if (this.destroyed) throw errCode(new Error('cannot removeTrack after peer is destroyed'), 'ERR_DESTROYED')
|
||
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) {
|
||
if (this.destroying) return
|
||
if (this.destroyed) throw errCode(new Error('cannot removeStream after peer is destroyed'), 'ERR_DESTROYED')
|
||
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.destroying) return
|
||
if (this.destroyed) throw errCode(new Error('cannot negotiate after peer is destroyed'), 'ERR_DESTROYED')
|
||
|
||
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 = event => {
|
||
const err = event.error instanceof Error
|
||
? event.error
|
||
: new Error(`Datachannel error: ${event.message} ${event.filename}:${event.lineno}:${event.colno}`)
|
||
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":57,"debug":223,"err-code":97,"get-browser-rtc":115,"queue-microtask":192,"randombytes":194,"readable-stream":240}],223:[function(require,module,exports){
|
||
arguments[4][13][0].apply(exports,arguments)
|
||
},{"./common":224,"_process":186,"dup":13}],224:[function(require,module,exports){
|
||
arguments[4][14][0].apply(exports,arguments)
|
||
},{"dup":14,"ms":225}],225:[function(require,module,exports){
|
||
arguments[4][15][0].apply(exports,arguments)
|
||
},{"dup":15}],226:[function(require,module,exports){
|
||
arguments[4][16][0].apply(exports,arguments)
|
||
},{"dup":16}],227:[function(require,module,exports){
|
||
arguments[4][17][0].apply(exports,arguments)
|
||
},{"./_stream_readable":229,"./_stream_writable":231,"_process":186,"dup":17,"inherits":119}],228:[function(require,module,exports){
|
||
arguments[4][18][0].apply(exports,arguments)
|
||
},{"./_stream_transform":230,"dup":18,"inherits":119}],229:[function(require,module,exports){
|
||
arguments[4][19][0].apply(exports,arguments)
|
||
},{"../errors":226,"./_stream_duplex":227,"./internal/streams/async_iterator":232,"./internal/streams/buffer_list":233,"./internal/streams/destroy":234,"./internal/streams/from":236,"./internal/streams/state":238,"./internal/streams/stream":239,"_process":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"util":55}],230:[function(require,module,exports){
|
||
arguments[4][20][0].apply(exports,arguments)
|
||
},{"../errors":226,"./_stream_duplex":227,"dup":20,"inherits":119}],231:[function(require,module,exports){
|
||
arguments[4][21][0].apply(exports,arguments)
|
||
},{"../errors":226,"./_stream_duplex":227,"./internal/streams/destroy":234,"./internal/streams/state":238,"./internal/streams/stream":239,"_process":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],232:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":235,"_process":186,"dup":22}],233:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],234:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"dup":24}],235:[function(require,module,exports){
|
||
arguments[4][25][0].apply(exports,arguments)
|
||
},{"../../../errors":226,"dup":25}],236:[function(require,module,exports){
|
||
arguments[4][26][0].apply(exports,arguments)
|
||
},{"dup":26}],237:[function(require,module,exports){
|
||
arguments[4][27][0].apply(exports,arguments)
|
||
},{"../../../errors":226,"./end-of-stream":235,"dup":27}],238:[function(require,module,exports){
|
||
arguments[4][28][0].apply(exports,arguments)
|
||
},{"../../../errors":226,"dup":28}],239:[function(require,module,exports){
|
||
arguments[4][29][0].apply(exports,arguments)
|
||
},{"dup":29,"events":98}],240:[function(require,module,exports){
|
||
arguments[4][30][0].apply(exports,arguments)
|
||
},{"./lib/_stream_duplex.js":227,"./lib/_stream_passthrough.js":228,"./lib/_stream_readable.js":229,"./lib/_stream_transform.js":230,"./lib/_stream_writable.js":231,"./lib/internal/streams/end-of-stream.js":235,"./lib/internal/streams/pipeline.js":237,"dup":30}],241:[function(require,module,exports){
|
||
/* global self */
|
||
|
||
const Rusha = require('rusha')
|
||
const rushaWorkerSha1 = require('./rusha-worker-sha1')
|
||
|
||
const rusha = new Rusha()
|
||
const scope = typeof window !== 'undefined' ? window : self
|
||
const crypto = scope.crypto || scope.msCrypto || {}
|
||
let 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) {
|
||
const l = s.length
|
||
const array = new Uint8Array(l)
|
||
for (let i = 0; i < l; i++) {
|
||
array[i] = s.charCodeAt(i)
|
||
}
|
||
return array
|
||
}
|
||
|
||
function hex (buf) {
|
||
const l = buf.length
|
||
const chars = []
|
||
for (let i = 0; i < l; i++) {
|
||
const 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":242,"rusha":218}],242:[function(require,module,exports){
|
||
const Rusha = require('rusha')
|
||
|
||
let worker
|
||
let nextTaskId
|
||
let cbs
|
||
|
||
function init () {
|
||
worker = Rusha.createWorker()
|
||
nextTaskId = 1
|
||
cbs = {} // taskId -> cb
|
||
|
||
worker.onmessage = function onRushaMessage (e) {
|
||
const taskId = e.data.id
|
||
const 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":218}],243:[function(require,module,exports){
|
||
(function (Buffer){(function (){
|
||
/*! simple-websocket. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||
/* global WebSocket */
|
||
|
||
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, null, {
|
||
...opts,
|
||
encoding: undefined // encoding option breaks ws internals
|
||
})
|
||
} else {
|
||
this._ws = new _WebSocket(opts.url)
|
||
}
|
||
} catch (err) {
|
||
queueMicrotask(() => this.destroy(err))
|
||
return
|
||
}
|
||
}
|
||
|
||
this._ws.binaryType = 'arraybuffer'
|
||
|
||
if (opts.socket && this.connected) {
|
||
queueMicrotask(() => this._handleOpen())
|
||
} else {
|
||
this._ws.onopen = () => this._handleOpen()
|
||
}
|
||
|
||
this._ws.onmessage = event => this._handleMessage(event)
|
||
this._ws.onclose = () => this._handleClose()
|
||
this._ws.onerror = err => this._handleError(err)
|
||
|
||
this._handleFinishBound = () => this._handleFinish()
|
||
this.once('finish', this._handleFinishBound)
|
||
}
|
||
|
||
/**
|
||
* 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._handleFinishBound) {
|
||
this.removeListener('finish', this._handleFinishBound)
|
||
}
|
||
this._handleFinishBound = 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) 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
|
||
}
|
||
}
|
||
|
||
_handleOpen () {
|
||
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')
|
||
}
|
||
|
||
_handleMessage (event) {
|
||
if (this.destroyed) return
|
||
let data = event.data
|
||
if (data instanceof ArrayBuffer) data = Buffer.from(data)
|
||
this.push(data)
|
||
}
|
||
|
||
_handleClose () {
|
||
if (this.destroyed) return
|
||
this._debug('on close')
|
||
this.destroy()
|
||
}
|
||
|
||
_handleError (_) {
|
||
this.destroy(new Error(`Error connecting to ${this.url}`))
|
||
}
|
||
|
||
// When stream finishes writing, close socket. Half open connections are not
|
||
// supported.
|
||
_handleFinish () {
|
||
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)
|
||
}
|
||
}
|
||
|
||
_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)
|
||
}
|
||
|
||
_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":57,"debug":244,"queue-microtask":192,"randombytes":194,"readable-stream":261,"ws":55}],244:[function(require,module,exports){
|
||
arguments[4][13][0].apply(exports,arguments)
|
||
},{"./common":245,"_process":186,"dup":13}],245:[function(require,module,exports){
|
||
arguments[4][14][0].apply(exports,arguments)
|
||
},{"dup":14,"ms":246}],246:[function(require,module,exports){
|
||
arguments[4][15][0].apply(exports,arguments)
|
||
},{"dup":15}],247:[function(require,module,exports){
|
||
arguments[4][16][0].apply(exports,arguments)
|
||
},{"dup":16}],248:[function(require,module,exports){
|
||
arguments[4][17][0].apply(exports,arguments)
|
||
},{"./_stream_readable":250,"./_stream_writable":252,"_process":186,"dup":17,"inherits":119}],249:[function(require,module,exports){
|
||
arguments[4][18][0].apply(exports,arguments)
|
||
},{"./_stream_transform":251,"dup":18,"inherits":119}],250:[function(require,module,exports){
|
||
arguments[4][19][0].apply(exports,arguments)
|
||
},{"../errors":247,"./_stream_duplex":248,"./internal/streams/async_iterator":253,"./internal/streams/buffer_list":254,"./internal/streams/destroy":255,"./internal/streams/from":257,"./internal/streams/state":259,"./internal/streams/stream":260,"_process":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"util":55}],251:[function(require,module,exports){
|
||
arguments[4][20][0].apply(exports,arguments)
|
||
},{"../errors":247,"./_stream_duplex":248,"dup":20,"inherits":119}],252:[function(require,module,exports){
|
||
arguments[4][21][0].apply(exports,arguments)
|
||
},{"../errors":247,"./_stream_duplex":248,"./internal/streams/destroy":255,"./internal/streams/state":259,"./internal/streams/stream":260,"_process":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],253:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":256,"_process":186,"dup":22}],254:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],255:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"dup":24}],256:[function(require,module,exports){
|
||
arguments[4][25][0].apply(exports,arguments)
|
||
},{"../../../errors":247,"dup":25}],257:[function(require,module,exports){
|
||
arguments[4][26][0].apply(exports,arguments)
|
||
},{"dup":26}],258:[function(require,module,exports){
|
||
arguments[4][27][0].apply(exports,arguments)
|
||
},{"../../../errors":247,"./end-of-stream":256,"dup":27}],259:[function(require,module,exports){
|
||
arguments[4][28][0].apply(exports,arguments)
|
||
},{"../../../errors":247,"dup":28}],260:[function(require,module,exports){
|
||
arguments[4][29][0].apply(exports,arguments)
|
||
},{"dup":29,"events":98}],261:[function(require,module,exports){
|
||
arguments[4][30][0].apply(exports,arguments)
|
||
},{"./lib/_stream_duplex.js":248,"./lib/_stream_passthrough.js":249,"./lib/_stream_readable.js":250,"./lib/_stream_transform.js":251,"./lib/_stream_writable.js":252,"./lib/internal/streams/end-of-stream.js":256,"./lib/internal/streams/pipeline.js":258,"dup":30}],262:[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
|
||
}
|
||
}
|
||
|
||
},{}],263:[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":265,"./lib/response":266,"builtin-status-codes":61,"url":298,"xtend":335}],264:[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 : {})
|
||
},{}],265:[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._socketTimeout = null
|
||
self._socketTimer = 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
|
||
|
||
if ('timeout' in opts && opts.timeout !== 0) {
|
||
self.setTimeout(opts.timeout)
|
||
}
|
||
|
||
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._resetTimers(false)
|
||
self._connect()
|
||
}, function (reason) {
|
||
self._resetTimers(true)
|
||
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._resetTimers(true)
|
||
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
|
||
|
||
self._resetTimers(false)
|
||
|
||
if (!statusValid(self._xhr) || self._destroyed)
|
||
return
|
||
|
||
if (!self._response)
|
||
self._connect()
|
||
|
||
self._response._onXHRProgress(self._resetTimers.bind(self))
|
||
}
|
||
|
||
ClientRequest.prototype._connect = function () {
|
||
var self = this
|
||
|
||
if (self._destroyed)
|
||
return
|
||
|
||
self._response = new IncomingMessage(self._xhr, self._fetchResponse, self._mode, self._resetTimers.bind(self))
|
||
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._resetTimers = function (done) {
|
||
var self = this
|
||
|
||
global.clearTimeout(self._socketTimer)
|
||
self._socketTimer = null
|
||
|
||
if (done) {
|
||
global.clearTimeout(self._fetchTimer)
|
||
self._fetchTimer = null
|
||
} else if (self._socketTimeout) {
|
||
self._socketTimer = global.setTimeout(function () {
|
||
self.emit('timeout')
|
||
}, self._socketTimeout)
|
||
}
|
||
}
|
||
|
||
ClientRequest.prototype.abort = ClientRequest.prototype.destroy = function (err) {
|
||
var self = this
|
||
self._destroyed = true
|
||
self._resetTimers(true)
|
||
if (self._response)
|
||
self._response._destroyed = true
|
||
if (self._xhr)
|
||
self._xhr.abort()
|
||
else if (self._fetchAbortController)
|
||
self._fetchAbortController.abort()
|
||
|
||
if (err)
|
||
self.emit('error', err)
|
||
}
|
||
|
||
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.setTimeout = function (timeout, cb) {
|
||
var self = this
|
||
|
||
if (cb)
|
||
self.once('timeout', cb)
|
||
|
||
self._socketTimeout = timeout
|
||
self._resetTimers(false)
|
||
}
|
||
|
||
ClientRequest.prototype.flushHeaders = 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":264,"./response":266,"_process":186,"buffer":57,"inherits":119,"readable-stream":281}],266:[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, resetTimers) {
|
||
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) {
|
||
resetTimers(false)
|
||
return new Promise(function (resolve, reject) {
|
||
if (self._destroyed) {
|
||
reject()
|
||
} else if(self.push(Buffer.from(chunk))) {
|
||
resolve()
|
||
} else {
|
||
self._resumeFetch = resolve
|
||
}
|
||
})
|
||
},
|
||
close: function () {
|
||
resetTimers(true)
|
||
if (!self._destroyed)
|
||
self.push(null)
|
||
},
|
||
abort: function (err) {
|
||
resetTimers(true)
|
||
if (!self._destroyed)
|
||
self.emit('error', err)
|
||
}
|
||
})
|
||
|
||
try {
|
||
response.body.pipeTo(writable).catch(function (err) {
|
||
resetTimers(true)
|
||
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
|
||
resetTimers(result.done)
|
||
if (result.done) {
|
||
self.push(null)
|
||
return
|
||
}
|
||
self.push(Buffer.from(result.value))
|
||
read()
|
||
}).catch(function (err) {
|
||
resetTimers(true)
|
||
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 (resetTimers) {
|
||
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 () {
|
||
resetTimers(true)
|
||
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') {
|
||
resetTimers(true)
|
||
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":264,"_process":186,"buffer":57,"inherits":119,"readable-stream":281}],267:[function(require,module,exports){
|
||
arguments[4][16][0].apply(exports,arguments)
|
||
},{"dup":16}],268:[function(require,module,exports){
|
||
arguments[4][17][0].apply(exports,arguments)
|
||
},{"./_stream_readable":270,"./_stream_writable":272,"_process":186,"dup":17,"inherits":119}],269:[function(require,module,exports){
|
||
arguments[4][18][0].apply(exports,arguments)
|
||
},{"./_stream_transform":271,"dup":18,"inherits":119}],270:[function(require,module,exports){
|
||
arguments[4][19][0].apply(exports,arguments)
|
||
},{"../errors":267,"./_stream_duplex":268,"./internal/streams/async_iterator":273,"./internal/streams/buffer_list":274,"./internal/streams/destroy":275,"./internal/streams/from":277,"./internal/streams/state":279,"./internal/streams/stream":280,"_process":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"util":55}],271:[function(require,module,exports){
|
||
arguments[4][20][0].apply(exports,arguments)
|
||
},{"../errors":267,"./_stream_duplex":268,"dup":20,"inherits":119}],272:[function(require,module,exports){
|
||
arguments[4][21][0].apply(exports,arguments)
|
||
},{"../errors":267,"./_stream_duplex":268,"./internal/streams/destroy":275,"./internal/streams/state":279,"./internal/streams/stream":280,"_process":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],273:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":276,"_process":186,"dup":22}],274:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],275:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"dup":24}],276:[function(require,module,exports){
|
||
arguments[4][25][0].apply(exports,arguments)
|
||
},{"../../../errors":267,"dup":25}],277:[function(require,module,exports){
|
||
arguments[4][26][0].apply(exports,arguments)
|
||
},{"dup":26}],278:[function(require,module,exports){
|
||
arguments[4][27][0].apply(exports,arguments)
|
||
},{"../../../errors":267,"./end-of-stream":276,"dup":27}],279:[function(require,module,exports){
|
||
arguments[4][28][0].apply(exports,arguments)
|
||
},{"../../../errors":267,"dup":28}],280:[function(require,module,exports){
|
||
arguments[4][29][0].apply(exports,arguments)
|
||
},{"dup":29,"events":98}],281:[function(require,module,exports){
|
||
arguments[4][30][0].apply(exports,arguments)
|
||
},{"./lib/_stream_duplex.js":268,"./lib/_stream_passthrough.js":269,"./lib/_stream_readable.js":270,"./lib/_stream_transform.js":271,"./lib/_stream_writable.js":272,"./lib/internal/streams/end-of-stream.js":276,"./lib/internal/streams/pipeline.js":278,"dup":30}],282:[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":283}],283:[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)
|
||
})
|
||
}
|
||
|
||
},{}],284:[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":57,"once":182}],285:[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":219}],286:[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":287}],287:[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":57}],288:[function(require,module,exports){
|
||
(function (process){(function (){
|
||
/**!
|
||
* tippy.js v6.3.1
|
||
* (c) 2017-2021 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 _element$ownerDocumen;
|
||
|
||
var _normalizeToArray = normalizeToArray(elementOrElements),
|
||
element = _normalizeToArray[0]; // Elements created via a <template> have an ownerDocument with no reference to the body
|
||
|
||
|
||
return (element == null ? void 0 : (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body) ? element.ownerDocument : 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() {
|
||
var _instance$popperInsta2;
|
||
|
||
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); // certain modifiers (e.g. `maxSize`) require a second update after the
|
||
// popper has been positioned for the first time
|
||
|
||
(_instance$popperInsta2 = instance.popperInstance) == null ? void 0 : _instance$popperInsta2.forceUpdate();
|
||
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
|
||
});
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
// every time the popper is destroyed (i.e. a new target), removing the styles
|
||
// and causing transitions to break for singletons when the console is open, but
|
||
// most notably for non-transform styles being used, `gpuAcceleration: false`.
|
||
|
||
var applyStylesModifier = Object.assign({}, core.applyStyles, {
|
||
effect: function effect(_ref) {
|
||
var state = _ref.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);
|
||
state.styles = initialStyles;
|
||
|
||
if (state.elements.arrow) {
|
||
Object.assign(state.elements.arrow.style, initialStyles.arrow);
|
||
} // intentionally return no cleanup function
|
||
// return () => { ... }
|
||
|
||
}
|
||
});
|
||
|
||
var createSingleton = function createSingleton(tippyInstances, optionalProps) {
|
||
var _optionalProps$popper;
|
||
|
||
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 = [];
|
||
var shownOnCreate = false;
|
||
|
||
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;
|
||
};
|
||
});
|
||
} // have to pass singleton, as it maybe undefined on first call
|
||
|
||
|
||
function prepareInstance(singleton, target) {
|
||
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;
|
||
}, {});
|
||
singleton.setProps(Object.assign({}, overrideProps, {
|
||
getReferenceClientRect: typeof overrideProps.getReferenceClientRect === 'function' ? overrideProps.getReferenceClientRect : function () {
|
||
return target.getBoundingClientRect();
|
||
}
|
||
}));
|
||
}
|
||
|
||
enableInstances(false);
|
||
setReferences();
|
||
var plugin = {
|
||
fn: function fn() {
|
||
return {
|
||
onDestroy: function onDestroy() {
|
||
enableInstances(true);
|
||
},
|
||
onHidden: function onHidden() {
|
||
currentTarget = null;
|
||
},
|
||
onClickOutside: function onClickOutside(instance) {
|
||
if (instance.props.showOnCreate && !shownOnCreate) {
|
||
shownOnCreate = true;
|
||
currentTarget = null;
|
||
}
|
||
},
|
||
onShow: function onShow(instance) {
|
||
if (instance.props.showOnCreate && !shownOnCreate) {
|
||
shownOnCreate = true;
|
||
prepareInstance(instance, references[0]);
|
||
}
|
||
},
|
||
onTrigger: function onTrigger(instance, event) {
|
||
prepareInstance(instance, event.currentTarget);
|
||
}
|
||
};
|
||
}
|
||
};
|
||
var singleton = tippy(div(), Object.assign({}, removeProperties(optionalProps, ['overrides']), {
|
||
plugins: [plugin].concat(optionalProps.plugins || []),
|
||
triggerTarget: references,
|
||
popperOptions: Object.assign({}, optionalProps.popperOptions, {
|
||
modifiers: [].concat(((_optionalProps$popper = optionalProps.popperOptions) == null ? void 0 : _optionalProps$popper.modifiers) || [], [applyStylesModifier])
|
||
})
|
||
}));
|
||
var originalShow = singleton.show;
|
||
|
||
singleton.show = function (target) {
|
||
originalShow(); // first time, showOnCreate or programmatic call with no params
|
||
// default to showing first instance
|
||
|
||
if (!currentTarget && target == null) {
|
||
return prepareInstance(singleton, references[0]);
|
||
} // triggered from event (do nothing as prepareInstance already called by onTrigger)
|
||
// programmatic call with no params when already visible (do nothing again)
|
||
|
||
|
||
if (currentTarget && target == null) {
|
||
return;
|
||
} // target is index of instance
|
||
|
||
|
||
if (typeof target === 'number') {
|
||
return references[target] && prepareInstance(singleton, references[target]);
|
||
} // target is a child tippy instance
|
||
|
||
|
||
if (individualInstances.includes(target)) {
|
||
var ref = target.reference;
|
||
return prepareInstance(singleton, ref);
|
||
} // target is a ReferenceElement
|
||
|
||
|
||
if (references.includes(target)) {
|
||
return prepareInstance(singleton, target);
|
||
}
|
||
};
|
||
|
||
singleton.showNext = function () {
|
||
var first = references[0];
|
||
|
||
if (!currentTarget) {
|
||
return singleton.show(0);
|
||
}
|
||
|
||
var index = references.indexOf(currentTarget);
|
||
singleton.show(references[index + 1] || first);
|
||
};
|
||
|
||
singleton.showPrevious = function () {
|
||
var last = references[references.length - 1];
|
||
|
||
if (!currentTarget) {
|
||
return singleton.show(last);
|
||
}
|
||
|
||
var index = references.indexOf(currentTarget);
|
||
var target = references[index - 1] || last;
|
||
singleton.show(target);
|
||
};
|
||
|
||
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, TOUCH_OPTIONS);
|
||
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":186}],289:[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":57}],290:[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":186,"bittorrent-dht/client":55,"bittorrent-lsd":55,"bittorrent-tracker/client":31,"debug":291,"events":98,"run-parallel":217}],291:[function(require,module,exports){
|
||
arguments[4][13][0].apply(exports,arguments)
|
||
},{"./common":292,"_process":186,"dup":13}],292:[function(require,module,exports){
|
||
arguments[4][14][0].apply(exports,arguments)
|
||
},{"dup":14,"ms":293}],293:[function(require,module,exports){
|
||
arguments[4][15][0].apply(exports,arguments)
|
||
},{"dup":15}],294:[function(require,module,exports){
|
||
(function (Buffer){(function (){
|
||
/*! torrent-piece. MIT License. WebTorrent LLC <https://webtorrent.io/opensource> */
|
||
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._cancellations.length || this._reservations < this._chunks) {
|
||
let min = this._reservations
|
||
while (this._cancellations.length) {
|
||
min = Math.min(min, this._cancellations.pop())
|
||
}
|
||
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":57}],295:[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":57,"is-typedarray":121}],296:[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":59}],297:[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
|
||
}
|
||
|
||
},{}],298:[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":299,"punycode":188,"querystring":191}],299:[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;
|
||
}
|
||
};
|
||
|
||
},{}],300:[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":301,"buffer":57,"debug":302,"events":98,"simple-sha1":241}],301:[function(require,module,exports){
|
||
arguments[4][12][0].apply(exports,arguments)
|
||
},{"dup":12}],302:[function(require,module,exports){
|
||
arguments[4][13][0].apply(exports,arguments)
|
||
},{"./common":303,"_process":186,"dup":13}],303:[function(require,module,exports){
|
||
arguments[4][14][0].apply(exports,arguments)
|
||
},{"dup":14,"ms":304}],304:[function(require,module,exports){
|
||
arguments[4][15][0].apply(exports,arguments)
|
||
},{"dup":15}],305:[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 : {})
|
||
},{}],306:[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":57,"events":98,"mp4-box-encoding":146,"mp4-stream":149,"range-slice-stream":195}],307:[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":306,"mediasource":124,"pump":187}],308:[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":313,"./package.json":333,"_process":186,"bittorrent-dht/client":55,"buffer":57,"create-torrent":80,"debug":315,"events":98,"load-ip-set":55,"parse-torrent":183,"path":184,"randombytes":194,"run-parallel":217,"simple-concat":220,"simple-peer":222,"speedometer":262}],309:[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":315,"readable-stream":332}],310:[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":309,"_process":186,"end-of-stream":96,"events":98,"path":184,"readable-stream":332,"render-media":211,"stream-to-blob":283,"stream-to-blob-url":282,"stream-with-known-length-to-buffer":284}],311:[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":314,"bittorrent-protocol":11,"debug":315,"unordered-array-remove":297}],312:[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
|
||
|
||
},{}],313:[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":333,"./file":310,"./peer":311,"./rarity-map":312,"./server":55,"_process":186,"addr-to-ip-port":3,"bitfield":10,"chunk-store-stream/write":78,"debug":315,"events":98,"fs":56,"fs-chunk-store":140,"immediate-chunk-store":118,"multistream":165,"net":55,"os":55,"parse-torrent":183,"path":184,"pump":187,"random-iterate":193,"run-parallel":217,"run-parallel-limit":216,"simple-get":221,"simple-sha1":241,"speedometer":262,"torrent-discovery":290,"torrent-piece":294,"ut_metadata":300,"ut_pex":55,"utp-native":55}],314:[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":333,"bitfield":10,"bittorrent-protocol":11,"buffer":57,"debug":315,"simple-get":221,"simple-sha1":241}],315:[function(require,module,exports){
|
||
arguments[4][13][0].apply(exports,arguments)
|
||
},{"./common":316,"_process":186,"dup":13}],316:[function(require,module,exports){
|
||
arguments[4][14][0].apply(exports,arguments)
|
||
},{"dup":14,"ms":317}],317:[function(require,module,exports){
|
||
arguments[4][15][0].apply(exports,arguments)
|
||
},{"dup":15}],318:[function(require,module,exports){
|
||
arguments[4][16][0].apply(exports,arguments)
|
||
},{"dup":16}],319:[function(require,module,exports){
|
||
arguments[4][17][0].apply(exports,arguments)
|
||
},{"./_stream_readable":321,"./_stream_writable":323,"_process":186,"dup":17,"inherits":119}],320:[function(require,module,exports){
|
||
arguments[4][18][0].apply(exports,arguments)
|
||
},{"./_stream_transform":322,"dup":18,"inherits":119}],321:[function(require,module,exports){
|
||
arguments[4][19][0].apply(exports,arguments)
|
||
},{"../errors":318,"./_stream_duplex":319,"./internal/streams/async_iterator":324,"./internal/streams/buffer_list":325,"./internal/streams/destroy":326,"./internal/streams/from":328,"./internal/streams/state":330,"./internal/streams/stream":331,"_process":186,"buffer":57,"dup":19,"events":98,"inherits":119,"string_decoder/":285,"util":55}],322:[function(require,module,exports){
|
||
arguments[4][20][0].apply(exports,arguments)
|
||
},{"../errors":318,"./_stream_duplex":319,"dup":20,"inherits":119}],323:[function(require,module,exports){
|
||
arguments[4][21][0].apply(exports,arguments)
|
||
},{"../errors":318,"./_stream_duplex":319,"./internal/streams/destroy":326,"./internal/streams/state":330,"./internal/streams/stream":331,"_process":186,"buffer":57,"dup":21,"inherits":119,"util-deprecate":305}],324:[function(require,module,exports){
|
||
arguments[4][22][0].apply(exports,arguments)
|
||
},{"./end-of-stream":327,"_process":186,"dup":22}],325:[function(require,module,exports){
|
||
arguments[4][23][0].apply(exports,arguments)
|
||
},{"buffer":57,"dup":23,"util":55}],326:[function(require,module,exports){
|
||
arguments[4][24][0].apply(exports,arguments)
|
||
},{"_process":186,"dup":24}],327:[function(require,module,exports){
|
||
arguments[4][25][0].apply(exports,arguments)
|
||
},{"../../../errors":318,"dup":25}],328:[function(require,module,exports){
|
||
arguments[4][26][0].apply(exports,arguments)
|
||
},{"dup":26}],329:[function(require,module,exports){
|
||
arguments[4][27][0].apply(exports,arguments)
|
||
},{"../../../errors":318,"./end-of-stream":327,"dup":27}],330:[function(require,module,exports){
|
||
arguments[4][28][0].apply(exports,arguments)
|
||
},{"../../../errors":318,"dup":28}],331:[function(require,module,exports){
|
||
arguments[4][29][0].apply(exports,arguments)
|
||
},{"dup":29,"events":98}],332:[function(require,module,exports){
|
||
arguments[4][30][0].apply(exports,arguments)
|
||
},{"./lib/_stream_duplex.js":319,"./lib/_stream_passthrough.js":320,"./lib/_stream_readable.js":321,"./lib/_stream_transform.js":322,"./lib/_stream_writable.js":323,"./lib/internal/streams/end-of-stream.js":327,"./lib/internal/streams/pipeline.js":329,"dup":30}],333:[function(require,module,exports){
|
||
module.exports={
|
||
"version": "0.110.1"
|
||
}
|
||
},{}],334:[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
|
||
}
|
||
}
|
||
|
||
},{}],335:[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
|
||
}
|
||
|
||
},{}],336:[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 examples = document.getElementById('examples');
|
||
var example1 = document.getElementById('example1');
|
||
var example2 = document.getElementById('example2');
|
||
var example3 = document.getElementById('example3');
|
||
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 downloadTorrentWrapper = document.getElementById('downloadTorrentWrapper');
|
||
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(downloadTorrentWrapper, {"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() {
|
||
|
||
// magnet input
|
||
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);
|
||
}
|
||
});
|
||
|
||
// torrent select button
|
||
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));
|
||
});
|
||
});
|
||
|
||
// body drag-and-drop torrent file support
|
||
document.addEventListener('dragover', function(event) {
|
||
event.preventDefault();
|
||
});
|
||
|
||
document.addEventListener('drop', function(event) {
|
||
event.preventDefault();
|
||
event.dataTransfer.items[0].getAsFile().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));
|
||
});
|
||
});
|
||
|
||
// example buttons
|
||
example1.addEventListener('click', function(event) {
|
||
event.preventDefault();
|
||
notyf.success("Parsing Ubuntu 20.04 Magnet URL");
|
||
parse("magnet:?xt=urn:btih:9fc20b9e98ea98b4a35e6223041a5ef94ea27809&dn=ubuntu-20.04-desktop-amd64.iso&tr=https%3A%2F%2Ftorrent.ubuntu.com%2Fannounce&tr=https%3A%2F%2Fipv6.torrent.ubuntu.com%2Fannounce");
|
||
});
|
||
|
||
example2.addEventListener('click', async function(event) {
|
||
event.preventDefault();
|
||
notyf.success("Fetching and Parsing “The WIRED CD” Torrent File...");
|
||
parseRemote("https://webtorrent.io/torrents/wired-cd.torrent");
|
||
});
|
||
|
||
example3.addEventListener('click', async function(event) {
|
||
event.preventDefault();
|
||
notyf.success("Parsing Jack Johnson Archive.org Torrent File");
|
||
let response = await fetch("/ext/jj2008-06-14.mk4_archive.torrent");
|
||
let arrayBuffer = await response.arrayBuffer();
|
||
parse(Buffer.from(arrayBuffer));
|
||
});
|
||
|
||
// share buttons
|
||
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);
|
||
});
|
||
|
||
// details field listeners
|
||
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 that 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";
|
||
if (parsed.files.length < 100) {
|
||
for (let file of parsed.files) {
|
||
let icon = getFontAwesomeIconForMimetype(mime.lookup(file.name));
|
||
files.appendChild(createFileRow(icon, file.name, file.length));
|
||
}
|
||
} else {
|
||
for (let i = 0; i < 100; i++) {
|
||
let icon = getFontAwesomeIconForMimetype(mime.lookup(parsed.files[i].name));
|
||
files.appendChild(createFileRow(icon, parsed.files[i].name, parsed.files[i].length));
|
||
}
|
||
files.appendChild(createFileRow('', '...and another ' + (parsed.files.length - 100) + ' more files', ''));
|
||
}
|
||
files.appendChild(createFileRow('folder-tree', '', parsed.length));
|
||
downloadTorrentTooltip.setContent('Download Torrent file');
|
||
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>';
|
||
}
|
||
downloadTorrentTooltip.setContent('Files metadata is required to generate a Torrent file. Try fetching files list from WebTorrent.');
|
||
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));
|
||
|
||
examples.style.display = 'none';
|
||
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');
|
||
if (icon) 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 = "";
|
||
examples.style.display = 'flex';
|
||
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":143,"parse-torrent":183,"tippy.js":288,"webtorrent":308}]},{},[336]);
|