diff --git a/.esdoc.json b/.esdoc.json index 08d78ceae26..9375e46b1a0 100644 --- a/.esdoc.json +++ b/.esdoc.json @@ -2,12 +2,13 @@ "source": "./src", "destination": "./api-docs", "plugins": [ - {"name": "esdoc-standard-plugin"}, - {"name": "esdoc-typescript-plugin", "option": {"enable": true}}, + {"name": "@itsjamie/esdoc-standard-plugin"}, + {"name": "@itsjamie/esdoc-typescript-plugin", "option": {"enable": true}}, { - "name": "esdoc-ecmascript-proposal-plugin", + "name": "@itsjamie/esdoc-ecmascript-proposal-plugin", "option": { - "objectRestSpread": true + "objectRestSpread": true, + "optionalChaining": true } } ] diff --git a/.eslintrc.js b/.eslintrc.js index c5db9c6d820..3c4543dfb98 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -106,7 +106,6 @@ module.exports = { 'no-empty': 1, 'no-mixed-operators': 1, 'no-unused-vars': 2, - '@typescript-eslint/no-unused-vars': 1, 'no-console': 1, 'no-fallthrough': 1, 'no-case-declarations': 2, @@ -122,12 +121,22 @@ module.exports = { 'no-void': 0, 'no-useless-catch': 2, 'lines-between-class-members': 2, - 'no-prototype-builtins': 0, - '@typescript-eslint/consistent-type-assertions': [ 2, - { - 'assertionStyle': 'as', - 'objectLiteralTypeAssertions': 'never' + 'no-prototype-builtins': 0 + }, + 'overrides': [ + { + 'files': ['*.ts'], + 'rules': { + 'no-unused-vars': 0, + '@typescript-eslint/no-unused-vars': 1, + '@typescript-eslint/prefer-optional-chain': 2, + '@typescript-eslint/consistent-type-assertions': [ 2, + { + 'assertionStyle': 'as', + 'objectLiteralTypeAssertions': 'never' + } + ] } - ] - } + } + ] }; diff --git a/README.md b/README.md index 80f2ef378db..c717cb11da3 100644 --- a/README.md +++ b/README.md @@ -69,13 +69,13 @@ Find the commit on [https://github.com/video-dev/hls.js/blob/deployments/README. hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED,function() { video.play(); - }); - } - // hls.js is not supported on platforms that do not have Media Source Extensions (MSE) enabled. - // When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video element through the `src` property. - // This is using the built-in support of the plain video element, without using hls.js. - // Note: it would be more normal to wait on the 'canplay' event below however on Safari (where you are most likely to find built-in HLS support) the video.src URL must be on the user-driven - // white-list before a 'canplay' event will be emitted; the last video event that can be reliably listened-for when the URL is not on the white-list is 'loadedmetadata'. + }); + } + // hls.js is not supported on platforms that do not have Media Source Extensions (MSE) enabled. + // When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video element through the `src` property. + // This is using the built-in support of the plain video element, without using hls.js. + // Note: it would be more normal to wait on the 'canplay' event below however on Safari (where you are most likely to find built-in HLS support) the video.src URL must be on the user-driven + // white-list before a 'canplay' event will be emitted; the last video event that can be reliably listened-for when the URL is not on the white-list is 'loadedmetadata'. else if (video.canPlayType('application/vnd.apple.mpegurl')) { video.src = 'https://video-dev.github.io/streams/x36xhzz/x36xhzz.m3u8'; video.addEventListener('loadedmetadata',function() { @@ -216,9 +216,9 @@ All HLS resources must be delivered with [CORS headers](https://developer.mozill - Adaptive streaming - Manual & Auto Quality Switching - 3 Quality Switching modes are available (controllable through API means) - - Instant switching (immediate quality switch at current video position) - - Smooth switching (quality switch for next loaded fragment) - - Bandwidth conservative switching (quality switch change for next loaded fragment, without flushing the buffer) + - Instant switching (immediate quality switch at current video position) + - Smooth switching (quality switch for next loaded fragment) + - Bandwidth conservative switching (quality switch change for next loaded fragment, without flushing the buffer) - In Auto-Quality mode, emergency switch down in case bandwidth is suddenly dropping to minimize buffering. - Accurate Seeking on VoD & Live (not limited to fragment or keyframe boundary) - Ability to seek in buffer and back buffer without redownloading segments @@ -241,6 +241,7 @@ All HLS resources must be delivered with [CORS headers](https://developer.mozill - `#EXT-X-ENDLIST` (Live playlist) - `#EXT-X-MEDIA-SEQUENCE` - `#EXT-X-TARGETDURATION` + - `#EXT-X-CONTINUITY` - `#EXT-X-DISCONTINUITY` - `#EXT-X-DISCONTINUITY-SEQUENCE` - `#EXT-X-BYTERANGE` @@ -248,6 +249,8 @@ All HLS resources must be delivered with [CORS headers](https://developer.mozill - `#EXT-X-KEY` (https://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-3.4.4) - `#EXT-X-PROGRAM-DATE-TIME` (https://tools.ietf.org/html/draft-pantos-http-live-streaming-18#section-4.3.2.6) - `EXT-X-START:TIME-OFFSET=x` (https://tools.ietf.org/html/draft-pantos-http-live-streaming-18#section-4.3.5.2) + - `#EXT-X-PREFETCH` + - `#EXT-X-PREFETCH-DISCONTINUITY` ## License diff --git a/demo/basic-usage.html b/demo/basic-usage.html index 279bff8f857..c369bd3b50c 100644 --- a/demo/basic-usage.html +++ b/demo/basic-usage.html @@ -20,9 +20,9 @@

Hls.js demo - basic usage

}); hls.loadSource('https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8'); hls.attachMedia(video); - hls.on(Hls.Events.MANIFEST_PARSED,function() { + hls.on(Hls.Events.MANIFEST_PARSED, function() { video.play(); - }); + }); } // hls.js is not supported on platforms that do not have Media Source Extensions (MSE) enabled. // When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video element throught the `src` property. diff --git a/demo/main.js b/demo/main.js index c00374dce40..90538fa9b5b 100644 --- a/demo/main.js +++ b/demo/main.js @@ -1,19 +1,19 @@ -import {sortObject, copyTextToClipboard} from './demo-utils' +import { sortObject, copyTextToClipboard } from './demo-utils'; const STORAGE_KEYS = { Editor_Persistence: 'hlsjs:config-editor-persist', - Hls_Config : 'hlsjs:config' + Hls_Config: 'hlsjs:config' }; const testStreams = require('../tests/test-streams'); -const defaultTestStreamUrl = testStreams['bbb'].url; -const sourceURL = decodeURIComponent(getURLParam('src', defaultTestStreamUrl)) +const defaultTestStreamUrl = testStreams.bbb.url; +const sourceURL = decodeURIComponent(getURLParam('src', defaultTestStreamUrl)); -let demoConfig = getURLParam('demoConfig', null) +let demoConfig = getURLParam('demoConfig', null); if (demoConfig) { - demoConfig = JSON.parse(atob(demoConfig)) + demoConfig = JSON.parse(atob(demoConfig)); } else { - demoConfig = {} + demoConfig = {}; } const hlsjsDefaults = { @@ -30,8 +30,8 @@ let dumpfMP4 = getDemoConfigPropOrDefault('dumpfMP4', false); let bufferingIdx = -1; let selectedTestStream = null; -let video = $('#video')[0]; -let startTime = Date.now() +const video = $('#video')[0]; +const startTime = Date.now(); let lastSeekingIdx; let lastStartPosition; @@ -46,67 +46,67 @@ let fmp4Data; let configPersistenceEnabled = false; let configEditor = null; -$(document).ready(function() { +$(document).ready(function () { setupConfigEditor(); Object.keys(testStreams).forEach((key) => { const stream = testStreams[key]; const option = new Option(stream.description, key); $('#streamSelect').append(option); - }) + }); - $('#streamSelect').change(function() { + $('#streamSelect').change(function () { selectedTestStream = testStreams[$('#streamSelect').val()]; const streamUrl = selectedTestStream.url; $('#streamURL').val(streamUrl); loadSelectedStream(); }); - $('#streamURL').change(function() { + $('#streamURL').change(function () { selectedTestStream = null; loadSelectedStream(); }); - $('#videoSize').change(function() { + $('#videoSize').change(function () { $('#video').width($('#videoSize').val()); $('#bufferedCanvas').width($('#videoSize').val()); }); - $('#enableStreaming').click(function() { + $('#enableStreaming').click(function () { enableStreaming = this.checked; loadSelectedStream(); }); - $('#autoRecoverError').click(function() { + $('#autoRecoverError').click(function () { autoRecoverError = this.checked; onDemoConfigChanged(); }); - $('#dumpfMP4').click(function() { + $('#dumpfMP4').click(function () { dumpfMP4 = this.checked; onDemoConfigChanged(); }); - $('#limitMetrics').change(function() { + $('#limitMetrics').change(function () { limitMetrics = this.value; onDemoConfigChanged(); - }) + }); - $('#levelCapping').change(function() { + $('#levelCapping').change(function () { levelCapping = this.value; onDemoConfigChanged(); }); $('#limitMetrics').val(limitMetrics); - $('#enableStreaming').prop('checked', enableStreaming ); - $('#autoRecoverError').prop('checked', autoRecoverError ); - $('#dumpfMP4').prop('checked', dumpfMP4 ); + $('#enableStreaming').prop('checked', enableStreaming); + $('#autoRecoverError').prop('checked', autoRecoverError); + $('#dumpfMP4').prop('checked', dumpfMP4); $('#levelCapping').val(levelCapping); $('h2').append(' v' + Hls.version + ''); $('#currentVersion').html('Hls version:' + Hls.version); - $('#streamURL').val(sourceURL) + $('#streamURL').val(sourceURL); video.volume = 0.05; @@ -116,11 +116,10 @@ $(document).ready(function() { $('#metricsButtonFixed').toggle(!windowSliding); loadSelectedStream(); - }); -function setupGlobals() { - window.events = events = { +function setupGlobals () { + self.events = events = { url : url, t0 : performance.now(), load : [], @@ -131,39 +130,35 @@ function setupGlobals() { }; // actual values, only on window - window.recoverDecodingErrorDate = null; - window.recoverSwapAudioCodecDate = null; - - window.fmp4Data = fmp4Data = { - 'audio': [], - 'video': [] + self.recoverDecodingErrorDate = null; + self.recoverSwapAudioCodecDate = null; + self.fmp4Data = fmp4Data = { + audio: [], + video: [] }; - - window.onClickBufferedRange = onClickBufferedRange; - - window.updateLevelInfo = updateLevelInfo; - window.onDemoConfigChanged = onDemoConfigChanged; - window.createfMP4 = createfMP4; - window.goToMetricsPermaLink = goToMetricsPermaLink; - window.toggleTab = toggleTab; - window.applyConfigEditorValue = applyConfigEditorValue; + self.onClickBufferedRange = onClickBufferedRange; + self.updateLevelInfo = updateLevelInfo; + self.onDemoConfigChanged = onDemoConfigChanged; + self.createfMP4 = createfMP4; + self.goToMetricsPermaLink = goToMetricsPermaLink; + self.toggleTab = toggleTab; + self.applyConfigEditorValue = applyConfigEditorValue; } -function trimArray( target, limit ) { - if( limit < 0 ) { +function trimArray (target, limit) { + if (limit < 0) { return; } - while(target.length > limit ) - { + while (target.length > limit) { target.shift(); } } -function trimEventHistory() { +function trimEventHistory () { const x = limitMetrics; - if(x < 0) { + if (x < 0) { return; } @@ -174,35 +169,34 @@ function trimEventHistory() { trimArray(events.bitrate, x); } -function loadSelectedStream() { +function loadSelectedStream () { if (!Hls.isSupported()) { handleUnsupported(); return; } - url = $('#streamURL').val() + url = $('#streamURL').val(); setupGlobals(); hideCanvas(); - if(hls) { + if (hls) { hls.destroy(); - if(hls.bufferTimer) { + if (hls.bufferTimer) { clearInterval(hls.bufferTimer); hls.bufferTimer = undefined; } hls = null; } - if(!enableStreaming) { + if (!enableStreaming) { logStatus('Streaming disabled'); return; } logStatus('Loading ' + url); - // Extending both a demo-specific config and the user config which can override all const hlsConfig = $.extend({}, hlsjsDefaults, getEditorValue({ parse: true })); @@ -215,7 +209,7 @@ function loadSelectedStream() { onDemoConfigChanged(); console.log('Using Hls.js config:', hlsConfig); - window.hls = hls = new Hls(hlsConfig); + self.hls = hls = new Hls(hlsConfig); logStatus('Loading manifest and attaching video element...'); @@ -223,7 +217,7 @@ function loadSelectedStream() { hls.autoLevelCapping = levelCapping; hls.attachMedia(video); - hls.on(Hls.Events.MEDIA_ATTACHED, function() { + hls.on(Hls.Events.MEDIA_ATTACHED, function () { logStatus('Media element attached'); bufferingIdx = -1; events.video.push({ @@ -233,7 +227,7 @@ function loadSelectedStream() { trimEventHistory(); }); - hls.on(Hls.Events.MEDIA_DETACHED, function() { + hls.on(Hls.Events.MEDIA_DETACHED, function () { logStatus('Media element detached'); bufferingIdx = -1; tracks = []; @@ -244,9 +238,9 @@ function loadSelectedStream() { trimEventHistory(); }); - hls.on(Hls.Events.FRAG_PARSING_INIT_SEGMENT, function(event, data) { + hls.on(Hls.Events.FRAG_PARSING_INIT_SEGMENT, function (eventName, data) { showCanvas(); - var event = { + const event = { time: performance.now() - events.t0, type: data.id + ' init segment' }; @@ -254,69 +248,69 @@ function loadSelectedStream() { trimEventHistory(); }); - hls.on(Hls.Events.FRAG_PARSING_METADATA, function(event, data) { - //console.log("Id3 samples ", data.samples); + hls.on(Hls.Events.FRAG_PARSING_METADATA, function (eventName, data) { + // console.log("Id3 samples ", data.samples); }); - hls.on(Hls.Events.LEVEL_SWITCHING, function(event, data) { + hls.on(Hls.Events.LEVEL_SWITCHING, function (eventName, data) { events.level.push({ - time : performance.now() - events.t0, - id : data.level, - bitrate: Math.round(hls.levels[data.level].bitrate/1000) + time: performance.now() - events.t0, + id: data.level, + bitrate: Math.round(hls.levels[data.level].bitrate / 1000) }); trimEventHistory(); updateLevelInfo(); }); - hls.on(Hls.Events.MANIFEST_PARSED, function(event, data) { - var event = { - type : 'manifest', - name : '', - start : 0, - end : data.levels.length, - time : data.stats.trequest - events.t0, - latency : data.stats.tfirst - data.stats.trequest, - load : data.stats.tload - data.stats.tfirst, - duration: data.stats.tload - data.stats.tfirst, + hls.on(Hls.Events.MANIFEST_PARSED, function (eventName, data) { + const event = { + type: 'manifest', + name: '', + start: 0, + end: data.levels.length, + time: data.stats.trequest - events.t0, + latency: data.stats.tfirst - data.stats.trequest, + load: data.stats.tload - data.stats.tfirst, + duration: data.stats.tload - data.stats.tfirst }; events.load.push(event); trimEventHistory(); refreshCanvas(); }); - hls.on(Hls.Events.MANIFEST_PARSED, function(event, data) { + hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) { logStatus('No of quality levels found: ' + hls.levels.length); logStatus('Manifest successfully loaded'); stats = { - levelNb : data.levels.length, + levelNb: data.levels.length, levelParsed: 0 }; trimEventHistory(); updateLevelInfo(); }); - hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, function(event, data) { + hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, function (event, data) { logStatus('No of audio tracks found: ' + data.audioTracks.length); updateAudioTrackInfo(); }); - hls.on(Hls.Events.AUDIO_TRACK_SWITCHING, function(event, data) { + hls.on(Hls.Events.AUDIO_TRACK_SWITCHING, function (eventName, data) { logStatus('Audio track switching...'); updateAudioTrackInfo(); - var event = { + const event = { time: performance.now() - events.t0, type: 'audio switching', name: '@' + data.id }; events.video.push(event); trimEventHistory(); - lastAudioTrackSwitchingIdx = events.video.length-1; + lastAudioTrackSwitchingIdx = events.video.length - 1; }); - hls.on(Hls.Events.AUDIO_TRACK_SWITCHED, function(event, data) { + hls.on(Hls.Events.AUDIO_TRACK_SWITCHED, function (eventName, data) { logStatus('Audio track switched'); updateAudioTrackInfo(); - var event = { + const event = { time: performance.now() - events.t0, type: 'audio switched', name: '@' + data.id @@ -329,46 +323,48 @@ function loadSelectedStream() { trimEventHistory(); }); - hls.on(Hls.Events.LEVEL_LOADED, function(event, data) { + hls.on(Hls.Events.LEVEL_LOADED, function (eventName, data) { events.isLive = data.details.live; - var event = { - type : 'level', - id : data.level, - start : data.details.startSN, - end : data.details.endSN, - time : data.stats.trequest - events.t0, - latency : data.stats.tfirst - data.stats.trequest, - load : data.stats.tload - data.stats.tfirst, - parsing : data.stats.tparsed - data.stats.tload, + const event = { + type: 'level', + id: data.level, + start: data.details.startSN, + end: data.details.endSN, + time: data.stats.trequest - events.t0, + latency: data.stats.tfirst - data.stats.trequest, + load: data.stats.tload - data.stats.tfirst, + parsing: data.stats.tparsed - data.stats.tload, duration: data.stats.tload - data.stats.tfirst }; + const parsingDuration = data.stats.tparsed - data.stats.tload; - if (stats.levelParsed) - {this.sumLevelParsingMs += parsingDuration;} - else - {this.sumLevelParsingMs = parsingDuration;} + if (stats.levelParsed) { + this.sumLevelParsingMs += parsingDuration; + } else { + this.sumLevelParsingMs = parsingDuration; + } stats.levelParsed++; - stats.levelParsingUs = Math.round(1000*this.sumLevelParsingMs / stats.levelParsed); + stats.levelParsingUs = Math.round(1000 * this.sumLevelParsingMs / stats.levelParsed); - //console.log('parsing level duration :' + stats.levelParsingUs + 'us,count:' + stats.levelParsed); + // console.log('parsing level duration :' + stats.levelParsingUs + 'us,count:' + stats.levelParsed); events.load.push(event); trimEventHistory(); refreshCanvas(); }); - hls.on(Hls.Events.AUDIO_TRACK_LOADED, function(event, data) { + hls.on(Hls.Events.AUDIO_TRACK_LOADED, function (eventName, data) { events.isLive = data.details.live; - var event = { - type : 'audio track', - id : data.id, - start : data.details.startSN, - end : data.details.endSN, - time : data.stats.trequest - events.t0, - latency : data.stats.tfirst - data.stats.trequest, - load : data.stats.tload - data.stats.tfirst, - parsing : data.stats.tparsed - data.stats.tload, + const event = { + type: 'audio track', + id: data.id, + start: data.details.startSN, + end: data.details.endSN, + time: data.stats.trequest - events.t0, + latency: data.stats.tfirst - data.stats.trequest, + load: data.stats.tload - data.stats.tfirst, + parsing: data.stats.tparsed - data.stats.tload, duration: data.stats.tload - data.stats.tfirst }; events.load.push(event); @@ -376,43 +372,44 @@ function loadSelectedStream() { refreshCanvas(); }); - hls.on(Hls.Events.FRAG_BUFFERED, function(event, data) { - var event = { - type : data.frag.type + ' fragment', - id : data.frag.level, - id2 : data.frag.sn, - time : data.stats.trequest - events.t0, - latency : data.stats.tfirst - data.stats.trequest, - load : data.stats.tload - data.stats.tfirst, - parsing : data.stats.tparsed - data.stats.tload, - buffer : data.stats.tbuffered - data.stats.tparsed, + hls.on(Hls.Events.FRAG_BUFFERED, function (eventName, data) { + const event = { + type: data.frag.type + ' fragment', + id: data.frag.level, + id2: data.frag.sn, + time: data.stats.trequest - events.t0, + latency: data.stats.tfirst - data.stats.trequest, + load: data.stats.tload - data.stats.tfirst, + parsing: data.stats.tparsed - data.stats.tload, + buffer: data.stats.tbuffered - data.stats.tparsed, duration: data.stats.tbuffered - data.stats.tfirst, - bw : Math.round(8*data.stats.total/(data.stats.tbuffered - data.stats.trequest)), - size : data.stats.total + bw: Math.round(8 * data.stats.total / (data.stats.tbuffered - data.stats.trequest)), + size: data.stats.total }; events.load.push(event); events.bitrate.push({ - time : performance.now() - events.t0, - bitrate : event.bw, + time: performance.now() - events.t0, + bitrate: event.bw, duration: data.frag.duration, - level : event.id + level: event.id }); - if(hls.bufferTimer === undefined) { + if (hls.bufferTimer === undefined) { events.buffer.push({ - time : 0, + time: 0, buffer: 0, - pos : 0 + pos: 0 }); - hls.bufferTimer = window.setInterval(checkBuffer, 100); + hls.bufferTimer = self.setInterval(checkBuffer, 100); } trimEventHistory(); refreshCanvas(); updateLevelInfo(); - let latency = data.stats.tfirst - data.stats.trequest, - parsing = data.stats.tparsed - data.stats.tload, - process = data.stats.tbuffered - data.stats.trequest, - bitrate = Math.round(8 * data.stats.length / (data.stats.tbuffered - data.stats.tfirst)); + const latency = data.stats.tfirst - data.stats.trequest; + const parsing = data.stats.tparsed - data.stats.tload; + const process = data.stats.tbuffered - data.stats.trequest; + const bitrate = Math.round(8 * data.stats.length / (data.stats.tbuffered - data.stats.tfirst)); + if (stats.fragBuffered) { stats.fragMinLatency = Math.min(stats.fragMinLatency, latency); stats.fragMaxLatency = Math.max(stats.fragMaxLatency, latency); @@ -451,8 +448,8 @@ function loadSelectedStream() { stats.autoLevelCappingLast = hls.autoLevelCapping; }); - hls.on(Hls.Events.LEVEL_SWITCHED, function(event, data) { - var event = { + hls.on(Hls.Events.LEVEL_SWITCHED, function (eventName, data) { + const event = { time: performance.now() - events.t0, type: 'level switched', name: data.level @@ -463,8 +460,8 @@ function loadSelectedStream() { updateLevelInfo(); }); - hls.on(Hls.Events.FRAG_CHANGED, function(event, data) { - var event = { + hls.on(Hls.Events.FRAG_CHANGED, function (eventName, data) { + const event = { time: performance.now() - events.t0, type: 'frag changed', name: data.frag.sn + ' @ ' + data.frag.level @@ -475,18 +472,20 @@ function loadSelectedStream() { updateLevelInfo(); stats.tagList = data.frag.tagList; - let level = data.frag.level, autoLevel = data.frag.autoLevel; - if (stats.levelStart === undefined) - {stats.levelStart = level;} + let level = data.frag.level; + let autoLevel = data.frag.autoLevel; + if (stats.levelStart === undefined) { + stats.levelStart = level; + } if (autoLevel) { if (stats.fragChangedAuto) { stats.autoLevelMin = Math.min(stats.autoLevelMin, level); stats.autoLevelMax = Math.max(stats.autoLevelMax, level); stats.fragChangedAuto++; - if (this.levelLastAuto && level !== stats.autoLevelLast) - {stats.autoLevelSwitch++;} - + if (this.levelLastAuto && level !== stats.autoLevelLast) { + stats.autoLevelSwitch++; + } } else { stats.autoLevelMin = stats.autoLevelMax = level; stats.autoLevelSwitch = 0; @@ -501,9 +500,9 @@ function loadSelectedStream() { stats.manualLevelMin = Math.min(stats.manualLevelMin, level); stats.manualLevelMax = Math.max(stats.manualLevelMax, level); stats.fragChangedManual++; - if (!this.levelLastAuto && level !== stats.manualLevelLast) - {stats.manualLevelSwitch++;} - + if (!this.levelLastAuto && level !== stats.manualLevelLast) { + stats.manualLevelSwitch++; + } } else { stats.manualLevelMin = stats.manualLevelMax = level; stats.manualLevelSwitch = 0; @@ -514,17 +513,17 @@ function loadSelectedStream() { this.levelLastAuto = autoLevel; }); - hls.on(Hls.Events.FRAG_LOAD_EMERGENCY_ABORTED, function(event, data) { + hls.on(Hls.Events.FRAG_LOAD_EMERGENCY_ABORTED, function (eventName, data) { if (stats) { - if (stats.fragLoadEmergencyAborted === undefined) - {stats.fragLoadEmergencyAborted = 1;} - else - {stats.fragLoadEmergencyAborted++;} - + if (stats.fragLoadEmergencyAborted === undefined) { + stats.fragLoadEmergencyAborted = 1; + } else { + stats.fragLoadEmergencyAborted++; + } } }); - hls.on(Hls.Events.FRAG_DECRYPTED, function(event, data) { + hls.on(Hls.Events.FRAG_DECRYPTED, function (eventName, data) { if (!stats.fragDecrypted) { stats.fragDecrypted = 0; this.totalDecryptTime = 0; @@ -535,71 +534,72 @@ function loadSelectedStream() { stats.fragAvgDecryptTime = this.totalDecryptTime / stats.fragDecrypted; }); - hls.on(Hls.Events.ERROR, function(event, data) { + hls.on(Hls.Events.ERROR, function (eventName, data) { console.warn('Error event:', data); - switch(data.details) { - case Hls.ErrorDetails.MANIFEST_LOAD_ERROR: - try { - $('#errorOut').html('Cannot load ' + url + '
HTTP response code:' + data.response.code + '
' + data.response.text); - if(data.response.code === 0){ - $('#errorOut').append('This might be a CORS issue, consider installing Allow-Control-Allow-Origin Chrome Extension'); - } - } catch(err) { - $('#errorOut').html('Cannot load ' + url + '
Response body: ' + data.response.text); + switch (data.details) { + case Hls.ErrorDetails.MANIFEST_LOAD_ERROR: + try { + $('#errorOut').html('Cannot load ' + url + '
HTTP response code:' + data.response.code + '
' + data.response.text); + if (data.response.code === 0) { + $('#errorOut').append('This might be a CORS issue, consider installing Allow-Control-Allow-Origin Chrome Extension'); } - break; - case Hls.ErrorDetails.MANIFEST_LOAD_TIMEOUT: - logError('Timeout while loading manifest'); - break; - case Hls.ErrorDetails.MANIFEST_PARSING_ERROR: - logError('Error while parsing manifest:' + data.reason); - break; - case Hls.ErrorDetails.LEVEL_LOAD_ERROR: - logError('Error while loading level playlist'); - break; - case Hls.ErrorDetails.LEVEL_LOAD_TIMEOUT: - logError('Timeout while loading level playlist'); - break; - case Hls.ErrorDetails.LEVEL_SWITCH_ERROR: - logError('Error while trying to switch to level ' + data.level); - break; - case Hls.ErrorDetails.FRAG_LOAD_ERROR: - logError('Error while loading fragment ' + data.frag.url); - break; - case Hls.ErrorDetails.FRAG_LOAD_TIMEOUT: - logError('Timeout while loading fragment ' + data.frag.url); - break; - case Hls.ErrorDetails.FRAG_LOOP_LOADING_ERROR: - logError('Fragment-loop loading error'); - break; - case Hls.ErrorDetails.FRAG_DECRYPT_ERROR: - logError('Decrypting error:' + data.reason); - break; - case Hls.ErrorDetails.FRAG_PARSING_ERROR: - logError('Parsing error:' + data.reason); - break; - case Hls.ErrorDetails.KEY_LOAD_ERROR: - logError('Error while loading key ' + data.frag.decryptdata.uri); - break; - case Hls.ErrorDetails.KEY_LOAD_TIMEOUT: - logError('Timeout while loading key ' + data.frag.decryptdata.uri); - break; - case Hls.ErrorDetails.BUFFER_APPEND_ERROR: - logError('Buffer append error'); - break; - case Hls.ErrorDetails.BUFFER_ADD_CODEC_ERROR: - logError('Buffer add codec error for ' + data.mimeType + ':' + data.err.message); - break; - case Hls.ErrorDetails.BUFFER_APPENDING_ERROR: - logError('Buffer appending error'); - break; - case Hls.ErrorDetails.BUFFER_STALLED_ERROR: - logError('Buffer stalled error'); - break; - default: - break; + } catch (err) { + $('#errorOut').html('Cannot load ' + url + '
Response body: ' + data.response.text); + } + break; + case Hls.ErrorDetails.MANIFEST_LOAD_TIMEOUT: + logError('Timeout while loading manifest'); + break; + case Hls.ErrorDetails.MANIFEST_PARSING_ERROR: + logError('Error while parsing manifest:' + data.reason); + break; + case Hls.ErrorDetails.LEVEL_LOAD_ERROR: + logError('Error while loading level playlist'); + break; + case Hls.ErrorDetails.LEVEL_LOAD_TIMEOUT: + logError('Timeout while loading level playlist'); + break; + case Hls.ErrorDetails.LEVEL_SWITCH_ERROR: + logError('Error while trying to switch to level ' + data.level); + break; + case Hls.ErrorDetails.FRAG_LOAD_ERROR: + logError('Error while loading fragment ' + data.frag.url); + break; + case Hls.ErrorDetails.FRAG_LOAD_TIMEOUT: + logError('Timeout while loading fragment ' + data.frag.url); + break; + case Hls.ErrorDetails.FRAG_LOOP_LOADING_ERROR: + logError('Fragment-loop loading error'); + break; + case Hls.ErrorDetails.FRAG_DECRYPT_ERROR: + logError('Decrypting error:' + data.reason); + break; + case Hls.ErrorDetails.FRAG_PARSING_ERROR: + logError('Parsing error:' + data.reason); + break; + case Hls.ErrorDetails.KEY_LOAD_ERROR: + logError('Error while loading key ' + data.frag.decryptdata.uri); + break; + case Hls.ErrorDetails.KEY_LOAD_TIMEOUT: + logError('Timeout while loading key ' + data.frag.decryptdata.uri); + break; + case Hls.ErrorDetails.BUFFER_APPEND_ERROR: + logError('Buffer append error'); + break; + case Hls.ErrorDetails.BUFFER_ADD_CODEC_ERROR: + logError('Buffer add codec error for ' + data.mimeType + ':' + data.err.message); + break; + case Hls.ErrorDetails.BUFFER_APPENDING_ERROR: + logError('Buffer appending error'); + break; + case Hls.ErrorDetails.BUFFER_STALLED_ERROR: + logError('Buffer stalled error'); + break; + default: + break; } - if(data.fatal) { + + if (data.fatal) { console.error('Fatal error :' + data.details); switch(data.type) { case Hls.ErrorTypes.MEDIA_ERROR: @@ -614,14 +614,17 @@ function loadSelectedStream() { break; } } - if(!stats) { + + if (!stats) { stats = {}; } + // track all errors independently - if (stats[data.details] === undefined) - {stats[data.details] = 1;} - else - {stats[data.details] += 1;} + if (stats[data.details] === undefined) { + stats[data.details] = 1; + } else { + stats[data.details] += 1; + } // track fatal error if (data.fatal) { @@ -634,29 +637,30 @@ function loadSelectedStream() { $('#statisticsOut').text(JSON.stringify(sortObject(stats), null, '\t')); }); - hls.on(Hls.Events.BUFFER_CREATED, function(event, data) { + hls.on(Hls.Events.BUFFER_CREATED, function (eventName, data) { tracks = data.tracks; }); - hls.on(Hls.Events.BUFFER_APPENDING, function(event, data) { + hls.on(Hls.Events.BUFFER_APPENDING, function (eventName, data) { if (dumpfMP4) { fmp4Data[data.type].push(data.data); } }); - hls.on(Hls.Events.FPS_DROP, function(event, data) { - let evt = { + hls.on(Hls.Events.FPS_DROP, function (eventName, data) { + const event = { time: performance.now() - events.t0, type: 'frame drop', name: data.currentDropped + '/' + data.currentDecoded }; - events.video.push(evt); + events.video.push(event); trimEventHistory(); if (stats) { - if (stats.fpsDropEvent === undefined) - {stats.fpsDropEvent = 1;} - else - {stats.fpsDropEvent++;} + if (stats.fpsDropEvent === undefined) { + stats.fpsDropEvent = 1; + } else { + stats.fpsDropEvent++; + } stats.fpsTotalDroppedFrames = data.totalDroppedFrames; } @@ -677,100 +681,101 @@ function loadSelectedStream() { video.addEventListener('durationchange', handleVideoEvent); } -function handleUnsupported() { - if(navigator.userAgent.toLowerCase().indexOf('firefox') !== -1) { +function handleUnsupported () { + if (navigator.userAgent.toLowerCase().indexOf('firefox') !== -1) { logStatus('You are using Firefox, it looks like MediaSource is not enabled,
please ensure the following keys are set appropriately in about:config
media.mediasource.enabled=true
media.mediasource.mp4.enabled=true
media.mediasource.whitelist=false'); } else { logStatus('Your Browser does not support MediaSourceExtension / MP4 mediasource'); } } -function handleVideoEvent(evt) { +function handleVideoEvent (evt) { let data = ''; - switch(evt.type) { - case 'durationchange': - if(evt.target.duration - lastDuration <= 0.5) { - // some browsers report several duration change events with almost the same value ... avoid spamming video events - return; + switch (evt.type) { + case 'durationchange': + if (evt.target.duration - lastDuration <= 0.5) { + // some browsers report several duration change events with almost the same value ... avoid spamming video events + return; + } + lastDuration = evt.target.duration; + data = Math.round(evt.target.duration * 1000); + break; + case 'resize': + data = evt.target.videoWidth + '/' + evt.target.videoHeight; + break; + case 'loadedmetadata': + case 'loadeddata': + case 'canplay': + case 'canplaythrough': + case 'ended': + case 'seeking': + case 'seeked': + case 'play': + case 'playing': + lastStartPosition = evt.target.currentTime; + case 'pause': + case 'waiting': + case 'stalled': + case 'error': + data = Math.round(evt.target.currentTime * 1000); + if (evt.type === 'error') { + let errorTxt; + const mediaError = evt.currentTarget.error; + switch (mediaError.code) { + case mediaError.MEDIA_ERR_ABORTED: + errorTxt = 'You aborted the video playback'; + break; + case mediaError.MEDIA_ERR_DECODE: + errorTxt = 'The video playback was aborted due to a corruption problem or because the video used features your browser did not support'; + handleMediaError(); + break; + case mediaError.MEDIA_ERR_NETWORK: + errorTxt = 'A network error caused the video download to fail part-way'; + break; + case mediaError.MEDIA_ERR_SRC_NOT_SUPPORTED: + errorTxt = 'The video could not be loaded, either because the server or network failed or because the format is not supported'; + break; } - lastDuration = evt.target.duration; - data = Math.round(evt.target.duration*1000); - break; - case 'resize': - data = evt.target.videoWidth + '/' + evt.target.videoHeight; - break; - case 'loadedmetadata': - case 'loadeddata': - case 'canplay': - case 'canplaythrough': - case 'ended': - case 'seeking': - case 'seeked': - case 'play': - case 'playing': - lastStartPosition = evt.target.currentTime; - case 'pause': - case 'waiting': - case 'stalled': - case 'error': - data = Math.round(evt.target.currentTime*1000); - if(evt.type === 'error') { - let errorTxt, mediaError=evt.currentTarget.error; - switch(mediaError.code) { - case mediaError.MEDIA_ERR_ABORTED: - errorTxt = 'You aborted the video playback'; - break; - case mediaError.MEDIA_ERR_DECODE: - errorTxt = 'The video playback was aborted due to a corruption problem or because the video used features your browser did not support'; - handleMediaError(); - break; - case mediaError.MEDIA_ERR_NETWORK: - errorTxt = 'A network error caused the video download to fail part-way'; - break; - case mediaError.MEDIA_ERR_SRC_NOT_SUPPORTED: - errorTxt = 'The video could not be loaded, either because the server or network failed or because the format is not supported'; - break; - } - - if (mediaError.message) { - errorTxt += ' - ' + mediaError.message; - } - logStatus(errorTxt); - console.error(errorTxt); + if (mediaError.message) { + errorTxt += ' - ' + mediaError.message; } - break; - default: - break; + + logStatus(errorTxt); + console.error(errorTxt); + } + break; + default: + break; } - let event = { + const event = { time: performance.now() - events.t0, type: evt.type, name: data }; events.video.push(event); - if(evt.type === 'seeking') { - lastSeekingIdx = events.video.length-1; + if (evt.type === 'seeking') { + lastSeekingIdx = events.video.length - 1; } - if(evt.type === 'seeked') { + if (evt.type === 'seeked') { events.video[lastSeekingIdx].duration = event.time - events.video[lastSeekingIdx].time; } trimEventHistory(); } -function handleMediaError() { - if(autoRecoverError) { +function handleMediaError () { + if (autoRecoverError) { let now = performance.now(); - if(!recoverDecodingErrorDate || (now - recoverDecodingErrorDate) > 3000) { + if (!recoverDecodingErrorDate || (now - recoverDecodingErrorDate) > 3000) { recoverDecodingErrorDate = performance.now(); $('#statusOut').append(', trying to recover media error.'); hls.recoverMediaError(); } else { - if(!recoverSwapAudioCodecDate || (now - recoverSwapAudioCodecDate) > 3000) { + if (!recoverSwapAudioCodecDate || (now - recoverSwapAudioCodecDate) > 3000) { recoverSwapAudioCodecDate = performance.now(); $('#statusOut').append(', trying to swap audio codec and recover media error.'); hls.swapAudioCodec(); @@ -782,45 +787,47 @@ function handleMediaError() { } } -function timeRangesToString(r) { +function timeRangesToString (r) { let log = ''; - for (let i=0; i= r.start(i) && pos < r.end(i)) { + if (!canvas.width || canvas.width !== v.clientWidth) { + canvas.width = v.clientWidth; + } + + const pos = v.currentTime; + let bufferLen = 0; + for (let i = 0; i < r.length; i++) { + const start = r.start(i) / v.duration * canvas.width; + const end = r.end(i) / v.duration * canvas.width; + ctx.fillRect(start, 3, Math.max(2, end - start), 10); + if (pos >= r.start(i) && pos < r.end(i)) { // play position is inside this buffer TimeRange, retrieve end of buffer position and buffer length bufferLen = r.end(i) - pos; } } // check if we are in buffering / or playback ended state - if(bufferLen <= 0.1 && v.paused === false && (pos-lastStartPosition) > 0.5) { - // don't create buffering event if we are at the end of the playlist, don't report ended for live playlist - if(lastDuration -pos <= 0.5 && events.isLive === false) { + if (bufferLen <= 0.1 && v.paused === false && (pos - lastStartPosition) > 0.5) { + if (lastDuration - pos <= 0.5 && events.isLive === false) { + // don't create buffering event if we are at the end of the playlist, don't report ended for live playlist } else { // we are not at the end of the playlist ... real buffering - if(bufferingIdx !== -1) { + if (bufferingIdx !== -1) { bufferingDuration = performance.now() - events.t0 - events.video[bufferingIdx].time; events.video[bufferingIdx].duration = bufferingDuration; events.video[bufferingIdx].name = bufferingDuration; @@ -831,12 +838,12 @@ function checkBuffer() { }); trimEventHistory(); // we are in buffering state - bufferingIdx = events.video.length-1; + bufferingIdx = events.video.length - 1; } } } - if(bufferLen > 0.1 && bufferingIdx !=-1) { + if (bufferLen > 0.1 && bufferingIdx !== -1) { bufferingDuration = performance.now() - events.t0 - events.video[bufferingIdx].time; events.video[bufferingIdx].duration = bufferingDuration; events.video[bufferingIdx].name = bufferingDuration; @@ -845,238 +852,234 @@ function checkBuffer() { } // update buffer/position for current Time - let event = { - time : performance.now() - events.t0, - buffer: Math.round(bufferLen*1000), - pos : Math.round(pos*1000) + const event = { + time: performance.now() - events.t0, + buffer: Math.round(bufferLen * 1000), + pos: Math.round(pos * 1000) }; - let bufEvents = events.buffer, bufEventLen = bufEvents.length; - if(bufEventLen > 1) { - let event0 = bufEvents[bufEventLen-2], event1 = bufEvents[bufEventLen-1]; - let slopeBuf0 = (event0.buffer - event1.buffer)/(event0.time-event1.time); - let slopeBuf1 = (event1.buffer - event.buffer)/(event1.time-event.time); - - let slopePos0 = (event0.pos - event1.pos)/(event0.time-event1.time); - let slopePos1 = (event1.pos - event.pos)/(event1.time-event.time); + const bufEvents = events.buffer; + const bufEventLen = bufEvents.length; + if (bufEventLen > 1) { + const event0 = bufEvents[bufEventLen - 2]; + const event1 = bufEvents[bufEventLen - 1]; + const slopeBuf0 = (event0.buffer - event1.buffer) / (event0.time - event1.time); + const slopeBuf1 = (event1.buffer - event.buffer) / (event1.time - event.time); + + const slopePos0 = (event0.pos - event1.pos) / (event0.time - event1.time); + const slopePos1 = (event1.pos - event.pos) / (event1.time - event.time); // compute slopes. if less than 30% difference, remove event1 - if((slopeBuf0 === slopeBuf1 || Math.abs(slopeBuf0/slopeBuf1 -1) <= 0.3) && - (slopePos0 === slopePos1 || Math.abs(slopePos0/slopePos1 -1) <= 0.3)) - {bufEvents.pop();} - + if ( + (slopeBuf0 === slopeBuf1 || Math.abs(slopeBuf0 / slopeBuf1 - 1) <= 0.3) && + (slopePos0 === slopePos1 || Math.abs(slopePos0 / slopePos1 - 1) <= 0.3) + ) { + bufEvents.pop(); + } } events.buffer.push(event); trimEventHistory(); refreshCanvas(); - let log = 'Duration: ' - + v.duration + '\n' - + 'Buffered: ' - + timeRangesToString(v.buffered) + '\n' - + 'Seekable: ' - + timeRangesToString(v.seekable) + '\n' - + 'Played: ' - + timeRangesToString(v.played) + '\n'; + let log = `Duration: ${v.duration}\nBuffered: ${timeRangesToString(v.buffered)}\nSeekable: ${timeRangesToString(v.seekable)}\nPlayed: ${timeRangesToString(v.played)}\n` if (hls.media) { - for(let type in tracks) { + for (const type in tracks) { log += 'Buffer for ' + type + ' contains: ' + timeRangesToString(tracks[type].buffer.buffered) + '\n'; } const videoPlaybackQuality = v.getVideoPlaybackQuality; - if(videoPlaybackQuality && typeof (videoPlaybackQuality) === typeof (Function)) { - log += 'Dropped frames: '+ v.getVideoPlaybackQuality().droppedVideoFrames + '\n'; - log += 'Corrupted frames:'+ v.getVideoPlaybackQuality().corruptedVideoFrames + '\n'; - } else if(v.webkitDroppedFrameCount) { - log+='Dropped frames:'+ v.webkitDroppedFrameCount + '\n'; + if (videoPlaybackQuality && typeof (videoPlaybackQuality) === typeof (Function)) { + log += `Dropped frames: ${v.getVideoPlaybackQuality().droppedVideoFrames}\n`; + log += `Corrupted frames: ${v.getVideoPlaybackQuality().corruptedVideoFrames}\n`; + } else if (v.webkitDroppedFrameCount) { + log += `Dropped frames: ${v.webkitDroppedFrameCount}`; } } - $('#bufferedOut').text(log); + $('#bufferedOut').text(log); $('#statisticsOut').text(JSON.stringify(sortObject(stats), null, '\t')); - ctx.fillStyle = 'blue'; - const x = v.currentTime / v.duration * canvas.width; ctx.fillRect(x, 0, 2, 15); } } -function showCanvas() { +function showCanvas () { showMetrics(); $('#bufferedOut').show(); $('#bufferedCanvas').show(); } -function hideCanvas() { +function hideCanvas () { hideMetrics(); $('#bufferedOut').hide(); $('#bufferedCanvas').hide(); } -function getMetrics() { - let json = JSON.stringify(events); - let jsonpacked = jsonpack.pack(json); +function getMetrics () { + const json = JSON.stringify(events); + const jsonpacked = jsonpack.pack(json); // console.log('packing JSON from ' + json.length + ' to ' + jsonpacked.length + ' bytes'); return btoa(jsonpacked); } -function copyMetricsToClipBoard() { +function copyMetricsToClipBoard () { copyTextToClipboard(getMetrics()); } -function goToMetrics() { +function goToMetrics () { let url = document.URL; url = url.substr(0, url.lastIndexOf('/')+1) + 'metrics.html'; - window.open(url, '_blank'); + self.open(url, '_blank'); } -function goToMetricsPermaLink() { +function goToMetricsPermaLink () { let url = document.URL; - let b64 = getMetrics(); - url = url.substr(0, url.lastIndexOf('/')+1) + 'metrics.html#data=' + b64; - window.open(url, '_blank'); + const b64 = getMetrics(); + url = url.substr(0, url.lastIndexOf('/') + 1) + 'metrics.html#data=' + b64; + self.open(url, '_blank'); } -function minsecs(ts) { - let m = Math.floor(Math.floor(ts % 3600) / 60); - let s = Math.floor(ts % 60); +function minsecs (ts) { + const m = Math.floor(Math.floor(ts % 3600) / 60); + const s = Math.floor(ts % 60); return m + ':' + (s < 10 ? '0' : '') + s; } -function onClickBufferedRange(event) { - let canvas = $('#bufferedCanvas')[0]; - let v = $('#video')[0]; - let target = (event.clientX - canvas.offsetLeft) / canvas.width * v.duration; +function onClickBufferedRange (event) { + const canvas = $('#bufferedCanvas')[0]; + const v = $('#video')[0]; + const target = (event.clientX - canvas.offsetLeft) / canvas.width * v.duration; v.currentTime = target; } -function updateLevelInfo() { +function updateLevelInfo () { if (!hls.levels) { return; } - let button_template = ''; - html2 += button_template; - if(hls.loadLevel === i) { - html2 += button_enabled; + html2 += buttonTemplate; + if (hls.loadLevel === i) { + html2 += buttonEnabled; } else { - html2 += button_disabled; + html2 += buttonDisabled; } html2 += 'onclick="hls.loadLevel=' + i + '">' + levelName + ''; - html3 += button_template; - if(hls.autoLevelCapping === i) { - html3 += button_enabled; + html3 += buttonTemplate; + if (hls.autoLevelCapping === i) { + html3 += buttonEnabled; } else { - html3 += button_disabled; + html3 += buttonDisabled; } html3 += 'onclick="levelCapping=hls.autoLevelCapping=' + i + ';updateLevelInfo();onDemoConfigChanged();">' + levelName + ''; - html4 += button_template; - if(hls.nextLevel === i) { - html4 += button_enabled; + html4 += buttonTemplate; + if (hls.nextLevel === i) { + html4 += buttonEnabled; } else { - html4 += button_disabled; + html4 += buttonDisabled; } html4 += 'onclick="hls.nextLevel=' + i + '">' + levelName + ''; } - let v = $('#video')[0]; + const v = $('#video')[0]; - if(v.videoWidth && v.videoHeight) { + if (v.videoWidth && v.videoHeight) { $('#currentResolution').html(v.videoWidth + ' x ' + v.videoHeight); } - if($('#currentLevelControl').html() != html1) { + if ($('#currentLevelControl').html() != html1) { $('#currentLevelControl').html(html1); } - if($('#loadLevelControl').html() != html2) { + if ($('#loadLevelControl').html() != html2) { $('#loadLevelControl').html(html2); } - if($('#levelCappingControl').html() != html3) { + if ($('#levelCappingControl').html() != html3) { $('#levelCappingControl').html(html3); } - if($('#nextLevelControl').html() != html4) { + if ($('#nextLevelControl').html() != html4) { $('#nextLevelControl').html(html4); } } -function updateAudioTrackInfo() { - let button_template = ''; @@ -1084,17 +1087,17 @@ function updateAudioTrackInfo() { $('#audioTrackControl').html(html1); } -function level2label(index) { - if(hls && hls.levels.length-1 >= index) { - let level = hls.levels[index]; +function level2label (index) { + if (hls && hls.levels.length - 1 >= index) { + const level = hls.levels[index]; if (level.name) { return level.name; } else { if (level.height) { - return(level.height + 'p / ' + Math.round(level.bitrate / 1024) + 'kb'); + return (level.height + 'p / ' + Math.round(level.bitrate / 1024) + 'kb'); } else { - if(level.bitrate) { - return(Math.round(level.bitrate / 1024) + 'kb'); + if (level.bitrate) { + return (Math.round(level.bitrate / 1024) + 'kb'); } else { return null; } @@ -1103,29 +1106,30 @@ function level2label(index) { } } -function getDemoConfigPropOrDefault(propName, defaultVal) { +function getDemoConfigPropOrDefault (propName, defaultVal) { return typeof demoConfig[propName] !== 'undefined' ? demoConfig[propName] : defaultVal; } -function getURLParam(sParam, defaultValue) { - let sPageURL = window.location.search.substring(1); - let sURLVariables = sPageURL.split('&'); +function getURLParam (sParam, defaultValue) { + const sPageURL = self.location.search.substring(1); + const sURLVariables = sPageURL.split('&'); for (let i = 0; i < sURLVariables.length; i++) { - let sParameterName = sURLVariables[i].split('='); - if (sParameterName[0] == sParam) - {return 'undefined' == sParameterName[1] ? undefined : 'false' == sParameterName[1] ? false : sParameterName[1];} + const sParameterName = sURLVariables[i].split('='); + if (sParameterName[0] == sParam) { + return sParameterName[1] == 'undefined' ? undefined : sParameterName[1] == 'false' ? false : sParameterName[1]; + } } return defaultValue; } -function onDemoConfigChanged() { +function onDemoConfigChanged () { demoConfig = { enableStreaming, autoRecoverError, dumpfMP4, levelCapping, - limitMetrics, + limitMetrics }; if (configPersistenceEnabled) { @@ -1140,7 +1144,7 @@ function onDemoConfigChanged() { $('#StreamPermalink').html(`${permalinkURL}`); } -function onConfigPersistenceChanged(event) { +function onConfigPersistenceChanged (event) { configPersistenceEnabled = event.target.checked; localStorage.setItem(STORAGE_KEYS.Editor_Persistence, JSON.stringify(configPersistenceEnabled)); @@ -1151,7 +1155,7 @@ function onConfigPersistenceChanged(event) { } } -function getEditorValue(options) { +function getEditorValue (options) { options = $.extend({ parse: false }, options || {}); let value = configEditor.session.getValue(); @@ -1167,9 +1171,8 @@ function getEditorValue(options) { return value; } -function getPersistedHlsConfig() { - var value = localStorage.getItem(STORAGE_KEYS.Hls_Config); - +function getPersistedHlsConfig () { + let value = localStorage.getItem(STORAGE_KEYS.Hls_Config); if (value === null) { return value; } @@ -1184,11 +1187,11 @@ function getPersistedHlsConfig() { return value; } -function persistEditorValue() { +function persistEditorValue () { localStorage.setItem(STORAGE_KEYS.Hls_Config, getEditorValue()); } -function setupConfigEditor() { +function setupConfigEditor () { configEditor = ace.edit('config-editor'); configEditor.setTheme('ace/theme/github'); configEditor.session.setMode('ace/mode/json'); @@ -1208,39 +1211,41 @@ function setupConfigEditor() { updateConfigEditorValue(contents); } -function updateConfigEditorValue(obj) { +function updateConfigEditorValue (obj) { const json = JSON.stringify(obj, null, 2); configEditor.session.setValue(json); } -function applyConfigEditorValue() { +function applyConfigEditorValue () { onDemoConfigChanged(); loadSelectedStream(); } -function createfMP4(type) { +function createfMP4 (type) { if (fmp4Data[type].length) { - let blob = new Blob([arrayConcat(fmp4Data[type])], { + const blob = new Blob([arrayConcat(fmp4Data[type])], { type: 'application/octet-stream' }); - let filename = type + '-' + new Date().toISOString() + '.mp4'; + const filename = type + '-' + new Date().toISOString() + '.mp4'; saveAs(blob, filename); //$('body').append('Download ' + filename + ' track
'); } } -function arrayConcat(inputArray) { - let totalLength = inputArray.reduce( function(prev, cur) { return prev+cur.length; }, 0); - let result = new Uint8Array(totalLength); +function arrayConcat (inputArray) { + const totalLength = inputArray.reduce(function (prev, cur) { + return prev + cur.length; + }, 0); + const result = new Uint8Array(totalLength); let offset = 0; - inputArray.forEach(function(element) { + inputArray.forEach(function (element) { result.set(element, offset); offset += element.length; }); return result; } -function hideAllTabs() { +function hideAllTabs () { $('#playbackControlTab').hide(); $('#qualityLevelControlTab').hide(); $('#audioTrackControlTab').hide(); @@ -1248,29 +1253,29 @@ function hideAllTabs() { $('#statsDisplayTab').hide(); } -function toggleTab(tabElId) { +function toggleTab (tabElId) { hideAllTabs(); hideMetrics(); $('#' + tabElId).show(); } -function appendLog(textElId, message) { - const el = $('#' + textElId) - let logText = el.text() +function appendLog (textElId, message) { + const el = $('#' + textElId); + let logText = el.text(); if (logText.length) { - logText += '\n' + logText += '\n'; } - const timestamp = (Date.now() - startTime) / 1000 - const newMessage = timestamp + ' | ' + message - logText += newMessage + const timestamp = (Date.now() - startTime) / 1000; + const newMessage = timestamp + ' | ' + message; + logText += newMessage; // update - el.text(logText) + el.text(logText); } -function logStatus(message) { - appendLog('statusOut', message) +function logStatus (message) { + appendLog('statusOut', message); } -function logError(message) { - appendLog('errorOut', message) +function logError (message) { + appendLog('errorOut', message); } diff --git a/package-lock.json b/package-lock.json index ccd05f429fa..c9ead358e0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,25 +13,122 @@ } }, "@babel/core": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.2.0.tgz", - "integrity": "sha512-7pvAdC4B+iKjFFp9Ztj0QgBndJ++qaMeonT185wAqUnhipw8idm9Rv1UMyBuKtYjfl6ORNkgEgcsYLfHX/GpLw==", + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.7.tgz", + "integrity": "sha512-jlSjuj/7z138NLZALxVgrx13AOtqip42ATZP7+kYl53GvDV6+4dCek1mVUo8z8c8Xnw/mx2q3d9HWh3griuesQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.2.0", - "@babel/helpers": "^7.2.0", - "@babel/parser": "^7.2.0", - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.6", - "@babel/types": "^7.2.0", - "convert-source-map": "^1.1.0", + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.7", + "@babel/helpers": "^7.7.4", + "@babel/parser": "^7.7.7", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4", + "convert-source-map": "^1.7.0", "debug": "^4.1.0", "json5": "^2.1.0", - "lodash": "^4.17.10", + "lodash": "^4.17.13", "resolve": "^1.3.2", "semver": "^5.4.1", "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/traverse": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + } } }, "@babel/generator": { @@ -48,68 +145,389 @@ } }, "@babel/helper-annotate-as-pure": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", - "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz", + "integrity": "sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", - "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz", + "integrity": "sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-explode-assignable-expression": "^7.7.4", + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-call-delegate": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", - "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz", + "integrity": "sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" + "@babel/helper-hoist-variables": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/traverse": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-create-class-features-plugin": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.6.0.tgz", - "integrity": "sha512-O1QWBko4fzGju6VoVvrZg0RROCVifcLxiApnGP3OWfWzvxRZFCoBD81K5ur5e3bVY2Vf/5rIJm8cqPKn8HUJng==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.7.4.tgz", + "integrity": "sha512-l+OnKACG4uiDHQ/aJT8dwpR+LhCJALxL0mJ6nzjB25e5IPwqV1VOsY7ah6UB1DG+VOXAIMtuC54rFJGiHkxjgA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-member-expression-to-functions": "^7.5.5", - "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-member-expression-to-functions": "^7.7.4", + "@babel/helper-optimise-call-expression": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5", - "@babel/helper-split-export-declaration": "^7.4.4" + "@babel/helper-replace-supers": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4" + }, + "dependencies": { + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz", + "integrity": "sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A==", + "dev": true, + "requires": { + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" } }, "@babel/helper-define-map": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz", - "integrity": "sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz", + "integrity": "sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/types": "^7.5.5", + "@babel/helper-function-name": "^7.7.4", + "@babel/types": "^7.7.4", "lodash": "^4.17.13" + }, + "dependencies": { + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-explode-assignable-expression": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", - "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz", + "integrity": "sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg==", "dev": true, "requires": { - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/traverse": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-function-name": { @@ -133,53 +551,144 @@ } }, "@babel/helper-hoist-variables": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", - "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz", + "integrity": "sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ==", "dev": true, "requires": { - "@babel/types": "^7.4.4" + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-member-expression-to-functions": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz", - "integrity": "sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz", + "integrity": "sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw==", "dev": true, "requires": { - "@babel/types": "^7.5.5" + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-module-imports": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", - "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz", + "integrity": "sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-module-transforms": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz", - "integrity": "sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz", + "integrity": "sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/template": "^7.4.4", - "@babel/types": "^7.5.5", + "@babel/helper-module-imports": "^7.7.4", + "@babel/helper-simple-access": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4", "lodash": "^4.17.13" + }, + "dependencies": { + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-optimise-call-expression": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", - "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz", + "integrity": "sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-plugin-utils": { @@ -198,38 +707,244 @@ } }, "@babel/helper-remap-async-to-generator": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", - "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz", + "integrity": "sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-wrap-function": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-annotate-as-pure": "^7.7.4", + "@babel/helper-wrap-function": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/traverse": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-replace-supers": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz", - "integrity": "sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz", + "integrity": "sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.5.5", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.5.5", - "@babel/types": "^7.5.5" + "@babel/helper-member-expression-to-functions": "^7.7.4", + "@babel/helper-optimise-call-expression": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/traverse": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-simple-access": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", - "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz", + "integrity": "sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A==", "dev": true, "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-split-export-declaration": { @@ -242,26 +957,202 @@ } }, "@babel/helper-wrap-function": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", - "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz", + "integrity": "sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.2.0" + "@babel/helper-function-name": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/traverse": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helpers": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.0.tgz", - "integrity": "sha512-W9kao7OBleOjfXtFGgArGRX6eCP0UEcA2ZWEWNkJdRZnHhW4eEbeswbG3EwaRsnQUAEGWYgMq1HsIXuNNNy2eQ==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.7.4.tgz", + "integrity": "sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==", "dev": true, "requires": { - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.0", - "@babel/types": "^7.6.0" + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/traverse": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/highlight": { @@ -282,145 +1173,334 @@ "dev": true }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", - "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz", + "integrity": "sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0", - "@babel/plugin-syntax-async-generators": "^7.2.0" + "@babel/helper-remap-async-to-generator": "^7.7.4", + "@babel/plugin-syntax-async-generators": "^7.7.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.3.tgz", - "integrity": "sha512-XO9eeU1/UwGPM8L+TjnQCykuVcXqaO5J1bkRPIygqZ/A2L1xVMJ9aZXrY31c0U4H2/LHKL4lbFQLsxktSrc/Ng==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.7.4.tgz", + "integrity": "sha512-EcuXeV4Hv1X3+Q1TsuOmyyxeTRiSqurGJ26+I/FW1WbymmRRapVORm6x1Zl3iDIHyRxEs+VXWp6qnlcfcJSbbw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.3.0", + "@babel/helper-create-class-features-plugin": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.7.4.tgz", + "integrity": "sha512-l+OnKACG4uiDHQ/aJT8dwpR+LhCJALxL0mJ6nzjB25e5IPwqV1VOsY7ah6UB1DG+VOXAIMtuC54rFJGiHkxjgA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-member-expression-to-functions": "^7.7.4", + "@babel/helper-optimise-call-expression": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4" + } + }, + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz", + "integrity": "sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz", + "integrity": "sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-replace-supers": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz", + "integrity": "sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.7.4", + "@babel/helper-optimise-call-expression": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/traverse": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz", + "integrity": "sha512-StH+nGAdO6qDB1l8sZ5UBV8AC3F2VW2I8Vfld73TMKyptMU9DY5YsJAS8U81+vEtxcH3Y/La0wG0btDrhpnhjQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.7.4" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", - "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz", + "integrity": "sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-json-strings": "^7.2.0" + "@babel/plugin-syntax-json-strings": "^7.7.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz", - "integrity": "sha512-DjeMS+J2+lpANkYLLO+m6GjoTMygYglKmRe6cDTbFv3L9i6mmiE8fe6B8MtCSLZpVXscD5kn7s6SgtHrDoBWoA==", + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.7.tgz", + "integrity": "sha512-3qp9I8lelgzNedI3hrhkvhaEYree6+WHnyA/q4Dza9z7iEIs1eyhWyJnetk3jJ69RT0AT4G0UhEGwyGFJ7GUuQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + "@babel/plugin-syntax-object-rest-spread": "^7.7.4" + }, + "dependencies": { + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz", + "integrity": "sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + } } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz", + "integrity": "sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + "@babel/plugin-syntax-optional-catch-binding": "^7.7.4" } }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz", - "integrity": "sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==", + "@babel/plugin-proposal-optional-chaining": { + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.7.5.tgz", + "integrity": "sha512-sOwFqT8JSchtJeDD+CjmWCaiFoLxY4Ps7NjvwHC/U7l4e9i5pTRNt8nDMIFSOUL+ncFbYSwruHM8WknYItWdXw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" + "@babel/plugin-syntax-optional-chaining": "^7.7.4" } }, - "@babel/plugin-syntax-async-generators": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", - "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.7.tgz", + "integrity": "sha512-80PbkKyORBUVm1fbTLrHpYdJxMThzM1UqFGh0ALEhO9TYbG86Ah9zQYAB/84axz2vcxefDLdZwWwZNlYARlu9w==", "dev": true, "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" } }, - "@babel/plugin-syntax-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", - "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "@babel/plugin-syntax-async-generators": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz", + "integrity": "sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", - "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "@babel/plugin-syntax-dynamic-import": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz", + "integrity": "sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "@babel/plugin-syntax-json-strings": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz", + "integrity": "sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, - "@babel/plugin-syntax-typescript": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz", - "integrity": "sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag==", + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz", + "integrity": "sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", - "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz", + "integrity": "sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz", - "integrity": "sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==", + "@babel/plugin-syntax-optional-chaining": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.7.4.tgz", + "integrity": "sha512-2MqYD5WjZSbJdUagnJvIdSfkb/ucOC9/1fRJxm7GAxY6YQLWlUvkfxoNbUPcPLHJyetKUDQ4+yyuUyAoc0HriA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", - "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "@babel/plugin-syntax-top-level-await": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.4.tgz", + "integrity": "sha512-wdsOw0MvkL1UIgiQ/IFr3ETcfv1xb8RMM0H9wbiDyLaJFyiDg5oZvDLCXosIXmFeIlweML5iOBXAkqddkYNizg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.7.4.tgz", + "integrity": "sha512-77blgY18Hud4NM1ggTA8xVT/dBENQf17OpiToSa2jSmEY3fWXD2jwrdVlO4kq5yzUTeF15WSQ6b4fByNvJcjpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz", + "integrity": "sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz", + "integrity": "sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.7.4" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz", + "integrity": "sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.0.tgz", - "integrity": "sha512-tIt4E23+kw6TgL/edACZwP1OUKrjOTyMrFMLoT5IOFrfMRabCgekjqFd5o6PaAMildBu46oFkekIdMuGkkPEpA==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz", + "integrity": "sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -428,211 +1508,554 @@ } }, "@babel/plugin-transform-classes": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz", - "integrity": "sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz", + "integrity": "sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.5.5", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-annotate-as-pure": "^7.7.4", + "@babel/helper-define-map": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-optimise-call-expression": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5", - "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/helper-replace-supers": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", "globals": "^11.1.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz", + "integrity": "sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz", + "integrity": "sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-replace-supers": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz", + "integrity": "sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.7.4", + "@babel/helper-optimise-call-expression": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/traverse": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/plugin-transform-computed-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", - "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz", + "integrity": "sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-destructuring": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz", - "integrity": "sha512-2bGIS5P1v4+sWTCnKNDZDxbGvEqi0ijeqM/YqHtVGrvG2y0ySgnEEhXErvE9dA0bnIzY9bIzdFK0jFA46ASIIQ==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz", + "integrity": "sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz", - "integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==", + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.7.tgz", + "integrity": "sha512-b4in+YlTeE/QmTgrllnb3bHA0HntYvjz8O3Mcbx75UBPJA2xhb5A8nle498VhxSXJHQefjtQxpnLPehDJ4TRlg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" + "@babel/helper-create-regexp-features-plugin": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz", - "integrity": "sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz", + "integrity": "sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", - "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz", + "integrity": "sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-for-of": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", - "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz", + "integrity": "sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-function-name": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", - "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz", + "integrity": "sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", + "@babel/helper-function-name": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" + }, + "dependencies": { + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/plugin-transform-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", - "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz", + "integrity": "sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz", + "integrity": "sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz", - "integrity": "sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.5.tgz", + "integrity": "sha512-CT57FG4A2ZUNU1v+HdvDSDrjNWBrtCmSH6YbbgN3Lrf0Di/q/lWRxZrE72p3+HCCz9UjfZOEBdphgC0nzOS6DQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-module-transforms": "^7.7.5", "@babel/helper-plugin-utils": "^7.0.0", "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.6.0.tgz", - "integrity": "sha512-Ma93Ix95PNSEngqomy5LSBMAQvYKVe3dy+JlVJSHEXZR5ASL9lQBedMiCyVtmTLraIDVRE3ZjTZvmXXD2Ozw3g==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz", + "integrity": "sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-module-transforms": "^7.7.5", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-simple-access": "^7.7.4", "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz", - "integrity": "sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz", + "integrity": "sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.4.4", + "@babel/helper-hoist-variables": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", - "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz", + "integrity": "sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-module-transforms": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" } }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz", + "integrity": "sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.7.4" + } + }, "@babel/plugin-transform-new-target": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", - "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz", + "integrity": "sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-object-assign": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.2.0.tgz", - "integrity": "sha512-nmE55cZBPFgUktbF2OuoZgPRadfxosLOpSgzEPYotKSls9J4pEPcembi8r78RU37Rph6UApCpNmsQA4QMWK9Ng==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.7.4.tgz", + "integrity": "sha512-0TpeUlnhQDwKxPLTIckdaWt46L2s61c/5w5snw1OUod5ehOJywZD98Ha3dFHVjeqkfOFtOTH7cqxddjxUuvcmg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-object-super": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz", - "integrity": "sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz", + "integrity": "sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5" + "@babel/helper-replace-supers": "^7.7.4" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", + "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz", + "integrity": "sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz", + "integrity": "sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-replace-supers": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz", + "integrity": "sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.7.4", + "@babel/helper-optimise-call-expression": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/traverse": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", + "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.7.4", + "@babel/helper-function-name": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/plugin-transform-parameters": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", - "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.7.tgz", + "integrity": "sha512-OhGSrf9ZBrr1fw84oFXj5hgi8Nmg+E2w5L7NhnG0lPvpDtqd7dbyilM2/vR8CKbJ907RyxPh2kj6sBCSSfI9Ew==", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.7.4", + "@babel/helper-get-function-arity": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0" + }, + "dependencies": { + "@babel/helper-get-function-arity": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", + "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz", + "integrity": "sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ==", "dev": true, "requires": { - "@babel/helper-call-delegate": "^7.4.4", - "@babel/helper-get-function-arity": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-regenerator": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", - "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.5.tgz", + "integrity": "sha512-/8I8tPvX2FkuEyWbjRCt4qTAgZK0DVy8QRguhA524UH48RfGJy94On2ri+dCuwOpcerPRl9O4ebQkRcVzIaGBw==", "dev": true, "requires": { "regenerator-transform": "^0.14.0" } }, + "@babel/plugin-transform-reserved-words": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.7.4.tgz", + "integrity": "sha512-OrPiUB5s5XvkCO1lS7D8ZtHcswIC57j62acAnJZKqGGnHP+TIc/ljQSrgdX/QyOTdEK5COAhuc820Hi1q2UgLQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", - "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz", + "integrity": "sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-spread": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", - "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz", + "integrity": "sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", - "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz", + "integrity": "sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -640,118 +2063,125 @@ } }, "@babel/plugin-transform-template-literals": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", - "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz", + "integrity": "sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-annotate-as-pure": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", - "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz", + "integrity": "sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-typescript": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.6.0.tgz", - "integrity": "sha512-yzw7EopOOr6saONZ3KA3lpizKnWRTe+rfBqg4AmQbSow7ik7fqmzrfIqt053osLwLE2AaTqGinLM2tl6+M/uog==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.7.4.tgz", + "integrity": "sha512-X8e3tcPEKnwwPVG+vP/vSqEShkwODOEeyQGod82qrIuidwIrfnsGn11qPM1jBLF4MqguTXXYzm58d0dY+/wdpg==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.6.0", + "@babel/helper-create-class-features-plugin": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-typescript": "^7.2.0" + "@babel/plugin-syntax-typescript": "^7.7.4" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz", - "integrity": "sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz", + "integrity": "sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" + "@babel/helper-create-regexp-features-plugin": "^7.7.4", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/preset-env": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.2.0.tgz", - "integrity": "sha512-haGR38j5vOGVeBatrQPr3l0xHbs14505DcM57cbJy48kgMFvvHHoYEhHuRV+7vi559yyAUAVbTWzbK/B/pzJng==", + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.7.7.tgz", + "integrity": "sha512-pCu0hrSSDVI7kCVUOdcMNQEbOPJ52E+LrQ14sN8uL2ALfSqePZQlKrOy+tM4uhEdYlCHi4imr8Zz2cZe9oSdIg==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-module-imports": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.2.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.2.0", - "@babel/plugin-syntax-async-generators": "^7.2.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", - "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.2.0", - "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.2.0", - "@babel/plugin-transform-classes": "^7.2.0", - "@babel/plugin-transform-computed-properties": "^7.2.0", - "@babel/plugin-transform-destructuring": "^7.2.0", - "@babel/plugin-transform-dotall-regex": "^7.2.0", - "@babel/plugin-transform-duplicate-keys": "^7.2.0", - "@babel/plugin-transform-exponentiation-operator": "^7.2.0", - "@babel/plugin-transform-for-of": "^7.2.0", - "@babel/plugin-transform-function-name": "^7.2.0", - "@babel/plugin-transform-literals": "^7.2.0", - "@babel/plugin-transform-modules-amd": "^7.2.0", - "@babel/plugin-transform-modules-commonjs": "^7.2.0", - "@babel/plugin-transform-modules-systemjs": "^7.2.0", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-new-target": "^7.0.0", - "@babel/plugin-transform-object-super": "^7.2.0", - "@babel/plugin-transform-parameters": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.0.0", - "@babel/plugin-transform-shorthand-properties": "^7.2.0", - "@babel/plugin-transform-spread": "^7.2.0", - "@babel/plugin-transform-sticky-regex": "^7.2.0", - "@babel/plugin-transform-template-literals": "^7.2.0", - "@babel/plugin-transform-typeof-symbol": "^7.2.0", - "@babel/plugin-transform-unicode-regex": "^7.2.0", - "browserslist": "^4.3.4", + "@babel/plugin-proposal-async-generator-functions": "^7.7.4", + "@babel/plugin-proposal-dynamic-import": "^7.7.4", + "@babel/plugin-proposal-json-strings": "^7.7.4", + "@babel/plugin-proposal-object-rest-spread": "^7.7.7", + "@babel/plugin-proposal-optional-catch-binding": "^7.7.4", + "@babel/plugin-proposal-unicode-property-regex": "^7.7.7", + "@babel/plugin-syntax-async-generators": "^7.7.4", + "@babel/plugin-syntax-dynamic-import": "^7.7.4", + "@babel/plugin-syntax-json-strings": "^7.7.4", + "@babel/plugin-syntax-object-rest-spread": "^7.7.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.7.4", + "@babel/plugin-syntax-top-level-await": "^7.7.4", + "@babel/plugin-transform-arrow-functions": "^7.7.4", + "@babel/plugin-transform-async-to-generator": "^7.7.4", + "@babel/plugin-transform-block-scoped-functions": "^7.7.4", + "@babel/plugin-transform-block-scoping": "^7.7.4", + "@babel/plugin-transform-classes": "^7.7.4", + "@babel/plugin-transform-computed-properties": "^7.7.4", + "@babel/plugin-transform-destructuring": "^7.7.4", + "@babel/plugin-transform-dotall-regex": "^7.7.7", + "@babel/plugin-transform-duplicate-keys": "^7.7.4", + "@babel/plugin-transform-exponentiation-operator": "^7.7.4", + "@babel/plugin-transform-for-of": "^7.7.4", + "@babel/plugin-transform-function-name": "^7.7.4", + "@babel/plugin-transform-literals": "^7.7.4", + "@babel/plugin-transform-member-expression-literals": "^7.7.4", + "@babel/plugin-transform-modules-amd": "^7.7.5", + "@babel/plugin-transform-modules-commonjs": "^7.7.5", + "@babel/plugin-transform-modules-systemjs": "^7.7.4", + "@babel/plugin-transform-modules-umd": "^7.7.4", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.7.4", + "@babel/plugin-transform-new-target": "^7.7.4", + "@babel/plugin-transform-object-super": "^7.7.4", + "@babel/plugin-transform-parameters": "^7.7.7", + "@babel/plugin-transform-property-literals": "^7.7.4", + "@babel/plugin-transform-regenerator": "^7.7.5", + "@babel/plugin-transform-reserved-words": "^7.7.4", + "@babel/plugin-transform-shorthand-properties": "^7.7.4", + "@babel/plugin-transform-spread": "^7.7.4", + "@babel/plugin-transform-sticky-regex": "^7.7.4", + "@babel/plugin-transform-template-literals": "^7.7.4", + "@babel/plugin-transform-typeof-symbol": "^7.7.4", + "@babel/plugin-transform-unicode-regex": "^7.7.4", + "@babel/types": "^7.7.4", + "browserslist": "^4.6.0", + "core-js-compat": "^3.6.0", "invariant": "^2.2.2", "js-levenshtein": "^1.1.3", - "semver": "^5.3.0" + "semver": "^5.5.0" + }, + "dependencies": { + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/preset-typescript": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.3.3.tgz", - "integrity": "sha512-mzMVuIP4lqtn4du2ynEfdO0+RYcslwrZiJHXu4MGaC1ctJiW2fyaeDrtjJGs7R/KebZ1sgowcIoWf4uRpEfKEg==", + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.7.7.tgz", + "integrity": "sha512-Apg0sCTovsSA+pEaI8efnA44b9x4X/7z4P8vsWMiN8rSUaM4y4+Shl5NMWnMl6njvt96+CEb6jwpXAKYAVCSQA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-typescript": "^7.3.2" - } - }, - "@babel/register": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.0.0.tgz", - "integrity": "sha512-f/+CRmaCe7rVEvcvPvxeA8j5aJhHC3aJie7YuqcMDhUOuyWLA7J/aNrTaHIzoWPEhpHA54mec4Mm8fv8KBlv3g==", - "dev": true, - "requires": { - "core-js": "^2.5.7", - "find-cache-dir": "^1.0.0", - "home-or-tmp": "^3.0.0", - "lodash": "^4.17.10", - "mkdirp": "^0.5.1", - "pirates": "^4.0.0", - "source-map-support": "^0.5.9" + "@babel/plugin-transform-typescript": "^7.7.4" } }, "@babel/template": { @@ -793,273 +2223,803 @@ "to-fast-properties": "^2.0.0" } }, - "@sinonjs/commons": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz", - "integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } + "@itsjamie/esdoc-accessor-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-accessor-plugin/-/esdoc-accessor-plugin-0.2.0.tgz", + "integrity": "sha512-bbHhyDg2IaNyQkTYMfE9X13uv2bNuXVNjXdB6yESWYM12qysHe623zxwpQUu95eVCTNKVq+Gsp4ihxd8iMCOxQ==", + "dev": true }, - "@sinonjs/formatio": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz", - "integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==", + "@itsjamie/esdoc-brand-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-brand-plugin/-/esdoc-brand-plugin-0.2.0.tgz", + "integrity": "sha512-2k7JhIS7kBedLSE9EwKrVz8ALIY3qYkK/uI5pBzgxjF7cgVF4I1JX35hrghqJAR6P5//+wz6GWV8TnuDmFsx/w==", "dev": true, "requires": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" + "cheerio": "0.22.0" }, "dependencies": { - "@sinonjs/samsam": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", - "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "cheerio": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", "dev": true, "requires": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" - } - } - } - }, - "@sinonjs/samsam": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-2.1.3.tgz", - "integrity": "sha512-8zNeBkSKhU9a5cRNbpCKau2WWPfan+Q2zDlcXvXyhn9EsMqgYs4qzo0XHNVlXC6ABQL8fT6nV+zzo5RTHJzyXw==", - "dev": true - }, - "@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", - "dev": true - }, - "@types/chai": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", - "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", - "dev": true - }, - "@types/eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", - "dev": true - }, - "@types/events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", - "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", - "dev": true - }, - "@types/glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", - "dev": true, - "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash.assignin": "^4.0.9", + "lodash.bind": "^4.1.4", + "lodash.defaults": "^4.0.1", + "lodash.filter": "^4.4.0", + "lodash.flatten": "^4.2.0", + "lodash.foreach": "^4.3.0", + "lodash.map": "^4.4.0", + "lodash.merge": "^4.4.0", + "lodash.pick": "^4.2.1", + "lodash.reduce": "^4.4.0", + "lodash.reject": "^4.4.0", + "lodash.some": "^4.4.0" + } + } } }, - "@types/json-schema": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", - "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true - }, - "@types/mocha": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", - "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", - "dev": true - }, - "@types/node": { - "version": "12.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz", - "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "@types/sinon": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.13.tgz", - "integrity": "sha512-d7c/C/+H/knZ3L8/cxhicHUiTDxdgap0b/aNJfsmLwFu/iOP17mdgbQsbHA3SJmrzsjD0l3UEE5SN4xxuz5ung==", + "@itsjamie/esdoc-cli": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-cli/-/esdoc-cli-0.2.0.tgz", + "integrity": "sha512-lqNxdECSr6A3Qg1DmgzbBLlfYMcRUiL6N/TpV0BU+wnjs89yL15mkovn5+eWLPe3IX4zThzO1f5fG/N5hPYifQ==", "dev": true }, - "@types/sinon-chai": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-3.2.2.tgz", - "integrity": "sha512-5zSs2AslzyPZdOsbm2NRtuSNAI2aTWzNKOHa/GRecKo7a5efYD7qGcPxMZXQDayVXT2Vnd5waXxBvV31eCZqiA==", - "dev": true, - "requires": { - "@types/chai": "*", - "@types/sinon": "*" - } - }, - "@typescript-eslint/eslint-plugin": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.3.1.tgz", - "integrity": "sha512-VqVNEsvemviajlaWm03kVMabc6S3xCHGYuY0fReTrIIOZg+3WzB+wfw6fD3KYKerw5lYxmzogmHOZ0i7YKnuwA==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "2.3.1", - "eslint-utils": "^1.4.2", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^2.0.1", - "tsutils": "^3.17.1" - } - }, - "@typescript-eslint/experimental-utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.3.1.tgz", - "integrity": "sha512-FaZEj73o4h6Wd0Lg+R4pZiJGdR0ZYbJr+O2+RbQ1aZjX8bZcfkVDtD+qm74Dv77rfSKkDKE64UTziLBo9UYHQA==", + "@itsjamie/esdoc-core": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-core/-/esdoc-core-0.2.0.tgz", + "integrity": "sha512-mQndj9K6+4xBqIZse/JjNOrd90cNo1GUFfMzUr/gX9GFHM5U7WHqgRTzJJHCHtc8lb5utG1keIRQfRKVeuzTlQ==", "dev": true, "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.3.1", - "eslint-scope": "^5.0.0" + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.3", + "@babel/traverse": "^7.7.2", + "cheerio": "1.0.0-rc.3", + "color-logger": "0.0.6", + "escape-html": "1.0.3", + "fs-extra": "8.1.0", + "ice-cap": "0.0.4", + "marked": "0.7.0", + "minimist": "1.2.0", + "taffydb": "2.7.3" }, "dependencies": { - "@typescript-eslint/typescript-estree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.3.1.tgz", - "integrity": "sha512-9SFhUgFuePJBB6jlLkOPPhMkZNiDCr+S8Ft7yAkkP2c5x5bxPhG3pe/exMiQaF8IGyVMDW6Ul0q4/cZ+uF3uog==", + "@babel/code-frame": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.0.tgz", + "integrity": "sha512-AN2IR/wCUYsM+PdErq6Bp3RFTXl8W0p9Nmymm7zkpsCmh+r/YYcckaCGpU8Q/mEKmST19kkGRaG42A/jxOWwBA==", "dev": true, "requires": { - "glob": "^7.1.4", - "is-glob": "^4.0.1", - "lodash.unescape": "4.0.1", - "semver": "^6.3.0" + "@babel/highlight": "^7.8.0" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@typescript-eslint/parser": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.3.1.tgz", - "integrity": "sha512-ZlWdzhCJ2iZnSp/VBAJ/sowFbyHycIux8t0UEH0JsKgQvfSf7949hLYFMwTXdCMeEnpP1zRTHimrR+YHzs8LIw==", - "dev": true, - "requires": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.3.1", - "@typescript-eslint/typescript-estree": "2.3.1", - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "@typescript-eslint/typescript-estree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.3.1.tgz", - "integrity": "sha512-9SFhUgFuePJBB6jlLkOPPhMkZNiDCr+S8Ft7yAkkP2c5x5bxPhG3pe/exMiQaF8IGyVMDW6Ul0q4/cZ+uF3uog==", + "@babel/generator": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.0.tgz", + "integrity": "sha512-2Lp2e02CV2C7j/H4n4D9YvsvdhPVVg9GDIamr6Tu4tU35mL3mzOrzl1lZ8ZJtysfZXh+y+AGORc2rPS7yHxBUg==", "dev": true, "requires": { - "glob": "^7.1.4", - "is-glob": "^4.0.1", - "lodash.unescape": "4.0.1", - "semver": "^6.3.0" + "@babel/types": "^7.8.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "@babel/helper-function-name": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.0.tgz", + "integrity": "sha512-x9psucuU0Xalw+0Vpr2FYJMLB7/KnPSLZhlkUyOGbYAWRDfmtZBrguYpJYiaNCRV7vGkYjO/gF6/J6yMvdWTDw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.0", + "@babel/template": "^7.8.0", + "@babel/types": "^7.8.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.0.tgz", + "integrity": "sha512-eUP5grliToMapQiTaYS2AAO/WwaCG7cuJztR1v/a1aPzUzUeGt+AaI9OvLATc/AfFkF8SLJ10d5ugGt/AQ9d6w==", + "dev": true, + "requires": { + "@babel/types": "^7.8.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.0.tgz", + "integrity": "sha512-YhYFhH4T6DlbT6CPtVgLfC1Jp2gbCawU/ml7WJvUpBg01bCrXSzTYMZZXbbIGjq/kHmK8YUATxTppcRGzj31pA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.0" + } + }, + "@babel/highlight": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.0.tgz", + "integrity": "sha512-OsdTJbHlPtIk2mmtwXItYrdmalJ8T0zpVzNAbKSkHshuywj7zb29Y09McV/jQsQunc/nEyHiPV2oy9llYMLqxw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.0.tgz", + "integrity": "sha512-VVtsnUYbd1+2A2vOVhm4P2qNXQE8L/W859GpUHfUcdhX8d3pEKThZuIr6fztocWx9HbK+00/CR0tXnhAggJ4CA==", "dev": true + }, + "@babel/template": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.0.tgz", + "integrity": "sha512-0NNMDsY2t3ltAVVK1WHNiaePo3tXPUeJpCX4I3xSKFoEl852wJHG8mrgHVADf8Lz1y+8al9cF7cSSfzSnFSYiw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.0", + "@babel/parser": "^7.8.0", + "@babel/types": "^7.8.0" + } + }, + "@babel/traverse": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.0.tgz", + "integrity": "sha512-d/6sPXFLGlJHZO/zWDtgFaKyalCOHLedzxpVJn6el1cw+f2TZa7xZEszeXdOw6EUemqRFBAn106BWBvtSck9Qw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.0", + "@babel/generator": "^7.8.0", + "@babel/helper-function-name": "^7.8.0", + "@babel/helper-split-export-declaration": "^7.8.0", + "@babel/parser": "^7.8.0", + "@babel/types": "^7.8.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.0.tgz", + "integrity": "sha512-1RF84ehyx9HH09dMMwGWl3UTWlVoCPtqqJPjGuC4JzMe1ZIVDJ2DT8mv3cPv/A7veLD6sgR7vi95lJqm+ZayIg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } } } }, - "@webassemblyjs/ast": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.3.tgz", - "integrity": "sha512-xy3m06+Iu4D32+6soz6zLnwznigXJRuFNTovBX2M4GqVqLb0dnyWLbPnpcXvUSdEN+9DVyDeaq2jyH1eIL2LZQ==", - "dev": true, - "requires": { - "@webassemblyjs/helper-module-context": "1.8.3", - "@webassemblyjs/helper-wasm-bytecode": "1.8.3", - "@webassemblyjs/wast-parser": "1.8.3" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.3.tgz", - "integrity": "sha512-vq1TISG4sts4f0lDwMUM0f3kpe0on+G3YyV5P0IySHFeaLKRYZ++n2fCFfG4TcCMYkqFeTUYFxm75L3ddlk2xA==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.3.tgz", - "integrity": "sha512-BmWEynI4FnZbjk8CaYZXwcv9a6gIiu+rllRRouQUo73hglanXD3AGFJE7Q4JZCoVE0p5/jeX6kf5eKa3D4JxwQ==", + "@itsjamie/esdoc-coverage-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-coverage-plugin/-/esdoc-coverage-plugin-0.2.0.tgz", + "integrity": "sha512-FIYhG3z8rEOgM6I71r70/7Jls5dIyhqEOiEFCoCjt1cZ9Z8cdX2/lHYGeay+HYlmQXBVffFIhbKWNGzB6Mty3w==", "dev": true }, - "@webassemblyjs/helper-buffer": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.3.tgz", - "integrity": "sha512-iVIMhWnNHoFB94+/2l7LpswfCsXeMRnWfExKtqsZ/E2NxZyUx9nTeKK/MEMKTQNEpyfznIUX06OchBHQ+VKi/Q==", + "@itsjamie/esdoc-ecmascript-proposal-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-ecmascript-proposal-plugin/-/esdoc-ecmascript-proposal-plugin-0.2.0.tgz", + "integrity": "sha512-jf0SdlHtYRcCsdSKcVB265iE1Vq9vj1+LuR4mmZQZfOz6rZqm4r7R6WvDy/s48iJwlU4P7OAfoq50o0MQPKo1Q==", "dev": true }, - "@webassemblyjs/helper-code-frame": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.3.tgz", - "integrity": "sha512-K1UxoJML7GKr1QXR+BG7eXqQkvu+eEeTjlSl5wUFQ6W6vaOc5OwSxTcb3oE9x/3+w4NHhrIKD4JXXCZmLdL2cg==", + "@itsjamie/esdoc-external-ecmascript-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-external-ecmascript-plugin/-/esdoc-external-ecmascript-plugin-0.2.0.tgz", + "integrity": "sha512-UpY/0zpsIrODcmq5Nc8cRRe7Bn/qfr3Sgiji3DIndeksq73XH8eOcSnns2q4LRlIL3EjwBrMzKM8MLdc/YD7SQ==", "dev": true, "requires": { - "@webassemblyjs/wast-printer": "1.8.3" + "fs-extra": "1.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + } } }, - "@webassemblyjs/helper-fsm": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.3.tgz", - "integrity": "sha512-387zipfrGyO77/qm7/SDUiZBjQ5KGk4qkrVIyuoubmRNIiqn3g+6ijY8BhnlGqsCCQX5bYKOnttJobT5xoyviA==", + "@itsjamie/esdoc-integrate-manual-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-integrate-manual-plugin/-/esdoc-integrate-manual-plugin-0.2.0.tgz", + "integrity": "sha512-IZATD5ZZ9kxA1zpe88GsS04ZfPRnqq23fRwGJkfrrgZN492c4poDp+11GRx60xHOxkxYMzQq6z6mOnh5rDvjDw==", "dev": true }, - "@webassemblyjs/helper-module-context": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.3.tgz", - "integrity": "sha512-lPLFdQfaRssfnGEJit5Sk785kbBPPPK4ZS6rR5W/8hlUO/5v3F+rN8XuUcMj/Ny9iZiyKhhuinWGTUuYL4VKeQ==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.8.3", - "mamacro": "^0.0.3" - } + "@itsjamie/esdoc-integrate-test-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-integrate-test-plugin/-/esdoc-integrate-test-plugin-0.2.0.tgz", + "integrity": "sha512-9aFTO0Vf/30FqEhRzuDG6GIwg4rilS5Ww6RoQHKdx3/wF0n5H/C9iOXMi+0WNnTaVQ8LbRNUpqpz3lI03zoRUg==", + "dev": true }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.3.tgz", - "integrity": "sha512-R1nJW7bjyJLjsJQR5t3K/9LJ0QWuZezl8fGa49DZq4IVaejgvkbNlKEQxLYTC579zgT4IIIVHb5JA59uBPHXyw==", + "@itsjamie/esdoc-lint-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-lint-plugin/-/esdoc-lint-plugin-0.2.0.tgz", + "integrity": "sha512-T5GN4vqQnEg3oIaZa1+bXg63RrKBS4d9Cw5RbfZOCWNbUbgjAU0hoHR+eOHRPkIVWGehJ5hnP1YBPOG9kZIutw==", "dev": true }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.3.tgz", - "integrity": "sha512-P6F7D61SJY73Yz+fs49Q3+OzlYAZP86OfSpaSY448KzUy65NdfzDmo2NPVte+Rw4562MxEAacvq/mnDuvRWOcg==", + "@itsjamie/esdoc-publish-html-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-publish-html-plugin/-/esdoc-publish-html-plugin-0.2.0.tgz", + "integrity": "sha512-K49y6+j6CGkLCg12mTeebhV9jSyCxOuk+rQ6wypfVC2YWVlkNaU36d/m942cA32NhLZ58psS5po9FiE/O6uIdg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.8.3", - "@webassemblyjs/helper-buffer": "1.8.3", - "@webassemblyjs/helper-wasm-bytecode": "1.8.3", - "@webassemblyjs/wasm-gen": "1.8.3" - } - }, + "babel-generator": "6.11.4", + "cheerio": "0.22.0", + "dompurify": "^2.0.7", + "escape-html": "1.0.3", + "fs-extra": "1.0.0", + "ice-cap": "0.0.4", + "jsdom": "^15.2.1", + "marked": "^0.8.0", + "taffydb": "2.7.2" + }, + "dependencies": { + "abab": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", + "dev": true + }, + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "dev": true + }, + "acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", + "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.11.4.tgz", + "integrity": "sha1-FPaTOrsgxiZm0n47e59bncBxKpo=", + "dev": true, + "requires": { + "babel-messages": "^6.8.0", + "babel-runtime": "^6.9.0", + "babel-types": "^6.10.2", + "detect-indent": "^3.0.1", + "lodash": "^4.2.0", + "source-map": "^0.5.0" + } + }, + "cheerio": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", + "dev": true, + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash.assignin": "^4.0.9", + "lodash.bind": "^4.1.4", + "lodash.defaults": "^4.0.1", + "lodash.filter": "^4.4.0", + "lodash.flatten": "^4.2.0", + "lodash.foreach": "^4.3.0", + "lodash.map": "^4.4.0", + "lodash.merge": "^4.4.0", + "lodash.pick": "^4.2.1", + "lodash.reduce": "^4.4.0", + "lodash.reject": "^4.4.0", + "lodash.some": "^4.4.0" + } + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.0.0.tgz", + "integrity": "sha512-QXSAu2WBsSRXCPjvI43Y40m6fMevvyRm8JVAuF9ksQz5jha4pWP1wpaK7Yu5oLFc6+XAY+hj8YhefyXcBB53gg==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, + "detect-indent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz", + "integrity": "sha1-ncXl3bzu+DJXZLlFGwK8bVQIT3U=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "minimist": "^1.1.0", + "repeating": "^1.1.0" + } + }, + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + } + }, + "jsdom": { + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.2.1.tgz", + "integrity": "sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^7.1.0", + "acorn-globals": "^4.3.2", + "array-equal": "^1.0.0", + "cssom": "^0.4.1", + "cssstyle": "^2.0.0", + "data-urls": "^1.1.0", + "domexception": "^1.0.1", + "escodegen": "^1.11.1", + "html-encoding-sniffer": "^1.0.2", + "nwsapi": "^2.2.0", + "parse5": "5.1.0", + "pn": "^1.1.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.7", + "saxes": "^3.1.9", + "symbol-tree": "^3.2.2", + "tough-cookie": "^3.0.1", + "w3c-hr-time": "^1.0.1", + "w3c-xmlserializer": "^1.1.2", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^7.0.0", + "ws": "^7.0.0", + "xml-name-validator": "^3.0.0" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "marked": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.0.tgz", + "integrity": "sha512-MyUe+T/Pw4TZufHkzAfDj6HarCBWia2y27/bhuYkTaiUnfDYFnCP3KUN+9oM7Wi6JA2rymtVYbQu3spE0GCmxQ==", + "dev": true + }, + "parse5": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", + "dev": true + }, + "repeating": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", + "integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "taffydb": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.7.2.tgz", + "integrity": "sha1-e/gQalwaSCUbPjvAoOFzJIn9Dcg=", + "dev": true + }, + "tough-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", + "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "dev": true, + "requires": { + "ip-regex": "^2.1.0", + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "ws": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz", + "integrity": "sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + } + } + }, + "@itsjamie/esdoc-standard-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-standard-plugin/-/esdoc-standard-plugin-0.2.0.tgz", + "integrity": "sha512-O3nWyUpt7x0v2HRR3TJz3NpmVi/IUiQcCct0iG1+0nOTe3lti8ds9WfcH7SyT5/HUZL+seRW21hGWTRBTkTUBQ==", + "dev": true, + "requires": { + "@itsjamie/esdoc-accessor-plugin": "^0.2.0", + "@itsjamie/esdoc-brand-plugin": "^0.2.0", + "@itsjamie/esdoc-coverage-plugin": "^0.2.0", + "@itsjamie/esdoc-external-ecmascript-plugin": "^0.2.0", + "@itsjamie/esdoc-integrate-manual-plugin": "^0.2.0", + "@itsjamie/esdoc-integrate-test-plugin": "^0.2.0", + "@itsjamie/esdoc-lint-plugin": "^0.2.0", + "@itsjamie/esdoc-publish-html-plugin": "^0.2.0", + "@itsjamie/esdoc-type-inference-plugin": "^0.2.0", + "@itsjamie/esdoc-undocumented-identifier-plugin": "^0.2.0", + "@itsjamie/esdoc-unexported-identifier-plugin": "^0.2.0" + } + }, + "@itsjamie/esdoc-type-inference-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-type-inference-plugin/-/esdoc-type-inference-plugin-0.2.0.tgz", + "integrity": "sha512-5Rw1+3h8cpZPb+M7QQbTN+6uGyQIK8OlBfTkKjjcp0t4rb8w3k+9NywppXzDqLGIWa0CpAWLJ3IO95PKTRMBgg==", + "dev": true, + "requires": { + "color-logger": "0.0.6" + } + }, + "@itsjamie/esdoc-typescript-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-typescript-plugin/-/esdoc-typescript-plugin-0.2.0.tgz", + "integrity": "sha512-/a/PBU+mOJMBPRx0k1pvo+h0A1mi6R7hcOGRE2QZKFoXEK0r299fgN8lUG4y/OnEX18PElyiciyalaORi45vYw==", + "dev": true, + "requires": { + "typescript": "^3.7.4" + } + }, + "@itsjamie/esdoc-undocumented-identifier-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-undocumented-identifier-plugin/-/esdoc-undocumented-identifier-plugin-0.2.0.tgz", + "integrity": "sha512-72lEu8O11Qqjq/cYAhjxX6+nEgSx4dDt5un/yos+29OUOhgbnGo8v2ImOXGTtIiUCe8OxM8fcAUVGLTSrYxoGA==", + "dev": true + }, + "@itsjamie/esdoc-unexported-identifier-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@itsjamie/esdoc-unexported-identifier-plugin/-/esdoc-unexported-identifier-plugin-0.2.0.tgz", + "integrity": "sha512-lqwu30t53LXYb8TJc77n4t29wgQ1YAv25FQ3PAEhmF1sJQpp67l8IX8SVZso0F91oTfl0598zO1ES6xS8BXqNg==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz", + "integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/formatio": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz", + "integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + }, + "dependencies": { + "@sinonjs/samsam": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.3.0", + "array-from": "^2.1.1", + "lodash": "^4.17.15" + } + } + } + }, + "@sinonjs/samsam": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-2.1.3.tgz", + "integrity": "sha512-8zNeBkSKhU9a5cRNbpCKau2WWPfan+Q2zDlcXvXyhn9EsMqgYs4qzo0XHNVlXC6ABQL8fT6nV+zzo5RTHJzyXw==", + "dev": true + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "@types/chai": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", + "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", + "dev": true + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", + "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/mocha": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", + "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", + "dev": true + }, + "@types/node": { + "version": "12.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz", + "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, + "@types/sinon": { + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.13.tgz", + "integrity": "sha512-d7c/C/+H/knZ3L8/cxhicHUiTDxdgap0b/aNJfsmLwFu/iOP17mdgbQsbHA3SJmrzsjD0l3UEE5SN4xxuz5ung==", + "dev": true + }, + "@types/sinon-chai": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-3.2.2.tgz", + "integrity": "sha512-5zSs2AslzyPZdOsbm2NRtuSNAI2aTWzNKOHa/GRecKo7a5efYD7qGcPxMZXQDayVXT2Vnd5waXxBvV31eCZqiA==", + "dev": true, + "requires": { + "@types/chai": "*", + "@types/sinon": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.12.0.tgz", + "integrity": "sha512-1t4r9rpLuEwl3hgt90jY18wJHSyb0E3orVL3DaqwmpiSDHmHiSspVsvsFF78BJ/3NNG3qmeso836jpuBWYziAA==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "2.12.0", + "eslint-utils": "^1.4.3", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "regexpp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.12.0.tgz", + "integrity": "sha512-jv4gYpw5N5BrWF3ntROvCuLe1IjRenLy5+U57J24NbPGwZFAjhnM45qpq0nDH1y/AZMb3Br25YiNVwyPbz6RkA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.12.0", + "eslint-scope": "^5.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.12.0.tgz", + "integrity": "sha512-lPdkwpdzxEfjI8TyTzZqPatkrswLSVu4bqUgnB03fHSOwpC7KSerPgJRgIAf11UGNf7HKjJV6oaPZI4AghLU6g==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.12.0", + "@typescript-eslint/typescript-estree": "2.12.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.12.0.tgz", + "integrity": "sha512-rGehVfjHEn8Frh9UW02ZZIfJs6SIIxIu/K1bbci8rFfDE/1lQ8krIJy5OXOV3DVnNdDPtoiPOdEANkLMrwXbiQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash.unescape": "4.0.1", + "semver": "^6.3.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@webassemblyjs/ast": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.3.tgz", + "integrity": "sha512-xy3m06+Iu4D32+6soz6zLnwznigXJRuFNTovBX2M4GqVqLb0dnyWLbPnpcXvUSdEN+9DVyDeaq2jyH1eIL2LZQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/wast-parser": "1.8.3" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.3.tgz", + "integrity": "sha512-vq1TISG4sts4f0lDwMUM0f3kpe0on+G3YyV5P0IySHFeaLKRYZ++n2fCFfG4TcCMYkqFeTUYFxm75L3ddlk2xA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.3.tgz", + "integrity": "sha512-BmWEynI4FnZbjk8CaYZXwcv9a6gIiu+rllRRouQUo73hglanXD3AGFJE7Q4JZCoVE0p5/jeX6kf5eKa3D4JxwQ==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.3.tgz", + "integrity": "sha512-iVIMhWnNHoFB94+/2l7LpswfCsXeMRnWfExKtqsZ/E2NxZyUx9nTeKK/MEMKTQNEpyfznIUX06OchBHQ+VKi/Q==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.3.tgz", + "integrity": "sha512-K1UxoJML7GKr1QXR+BG7eXqQkvu+eEeTjlSl5wUFQ6W6vaOc5OwSxTcb3oE9x/3+w4NHhrIKD4JXXCZmLdL2cg==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.8.3" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.3.tgz", + "integrity": "sha512-387zipfrGyO77/qm7/SDUiZBjQ5KGk4qkrVIyuoubmRNIiqn3g+6ijY8BhnlGqsCCQX5bYKOnttJobT5xoyviA==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.3.tgz", + "integrity": "sha512-lPLFdQfaRssfnGEJit5Sk785kbBPPPK4ZS6rR5W/8hlUO/5v3F+rN8XuUcMj/Ny9iZiyKhhuinWGTUuYL4VKeQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.3.tgz", + "integrity": "sha512-R1nJW7bjyJLjsJQR5t3K/9LJ0QWuZezl8fGa49DZq4IVaejgvkbNlKEQxLYTC579zgT4IIIVHb5JA59uBPHXyw==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.3.tgz", + "integrity": "sha512-P6F7D61SJY73Yz+fs49Q3+OzlYAZP86OfSpaSY448KzUy65NdfzDmo2NPVte+Rw4562MxEAacvq/mnDuvRWOcg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-buffer": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/wasm-gen": "1.8.3" + } + }, "@webassemblyjs/ieee754": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.3.tgz", @@ -1195,7 +3155,7 @@ }, "acorn": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", + "resolved": "http://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=", "dev": true, "optional": true @@ -1222,6 +3182,12 @@ "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", "dev": true }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "dev": true + }, "after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", @@ -1246,6 +3212,12 @@ "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", "dev": true }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, "ansi-colors": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", @@ -1342,6 +3314,12 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -1435,7 +3413,7 @@ }, "util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -1529,7 +3507,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -1572,7 +3550,7 @@ "dependencies": { "jsesc": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", "dev": true } @@ -1943,6 +3921,12 @@ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", "dev": true }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "dev": true + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -1951,7 +3935,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -2021,19 +4005,19 @@ } }, "browserslist": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz", - "integrity": "sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA==", + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.2.tgz", + "integrity": "sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30000989", - "electron-to-chromium": "^1.3.247", - "node-releases": "^1.1.29" + "caniuse-lite": "^1.0.30001015", + "electron-to-chromium": "^1.3.322", + "node-releases": "^1.1.42" } }, "buffer": { "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { @@ -2127,9 +4111,9 @@ } }, "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true } } @@ -2196,9 +4180,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30000989", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz", - "integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==", + "version": "1.0.30001016", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001016.tgz", + "integrity": "sha512-yYQ2QfotceRiH4U+h1Us86WJXtVHDmy3nEKIdYPsZCYnOV5/tMgGbmoIlrMzmh2VXlproqYtVaKeGDBkMZifFA==", "dev": true }, "caseless": { @@ -2245,13 +4229,13 @@ "dev": true }, "cheerio": { - "version": "1.0.0-rc.2", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz", - "integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=", + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz", + "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==", "dev": true, "requires": { "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", + "dom-serializer": "~0.1.1", "entities": "~1.1.1", "htmlparser2": "^3.9.1", "lodash": "^4.15.0", @@ -2287,9 +4271,9 @@ } }, "chownr": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz", - "integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", "dev": true }, "chrome-trace-event": { @@ -2302,9 +4286,9 @@ } }, "chromedriver": { - "version": "78.0.1", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-78.0.1.tgz", - "integrity": "sha512-eOsyFk4xb9EECs1VMrDbxO713qN+Bu1XUE8K9AuePc3839TPdAegg72kpXSzkeNqRNZiHbnJUItIVCLFkDqceA==", + "version": "79.0.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-79.0.0.tgz", + "integrity": "sha512-DO29C7ntJfzu6q1vuoWwCON8E9x5xzopt7Q41A7Dr7hBKcdNpGw1l9DTt9b+l1qviOWiJLGsD+jHw21ptEHubA==", "dev": true, "requires": { "del": "^4.1.1", @@ -2357,6 +4341,11 @@ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "dev": true }, + "cliclopts": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cliclopts/-/cliclopts-1.1.1.tgz", + "integrity": "sha1-aUMcfLWvcjd0sNORG0w3USQxkQ8=" + }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -2662,6 +4651,24 @@ "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", "dev": true }, + "core-js-compat": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.0.tgz", + "integrity": "sha512-Z3eCNjGgoYluH89Jt4wVkfYsc/VdLrA2/woX5lm0isO/pCT+P+Y+o65bOuEnjDJLthdwTBxbCVzptTXtc18fJg==", + "dev": true, + "requires": { + "browserslist": "^4.8.2", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -2726,7 +4733,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -2739,7 +4746,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -2855,7 +4862,26 @@ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "abab": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", + "dev": true + } } }, "date-format": { @@ -3043,7 +5069,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { @@ -3120,6 +5146,23 @@ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", "dev": true }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + }, + "dependencies": { + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + } + } + }, "domhandler": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", @@ -3129,6 +5172,12 @@ "domelementtype": "1" } }, + "dompurify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.0.7.tgz", + "integrity": "sha512-S3O0lk6rFJtO01ZTzMollCOGg+WAtCwS3U5E2WSDY/x/sy7q70RjEC4Dmrih5/UqzLLB9XoKJ8KqwBxaNvBu4A==", + "dev": true + }, "domutils": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", @@ -3180,9 +5229,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.260", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.260.tgz", - "integrity": "sha512-wGt+OivF1C1MPwaSv3LJ96ebNbLAWlx3HndivDDWqwIVSQxmhL17Y/YmwUdEMtS/bPyommELt47Dct0/VZNQBQ==", + "version": "1.3.322", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz", + "integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==", "dev": true }, "elliptic": { @@ -3225,507 +5274,230 @@ "dev": true, "requires": { "once": "^1.4.0" - } - }, - "engine.io": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", - "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "base64id": "1.0.0", - "cookie": "0.3.1", - "debug": "~3.1.0", - "engine.io-parser": "~2.1.0", - "ws": "~3.3.1" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "engine.io-client": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", - "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", - "dev": true, - "requires": { - "component-emitter": "1.2.1", - "component-inherit": "0.0.3", - "debug": "~3.1.0", - "engine.io-parser": "~2.1.1", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "ws": "~3.3.1", - "xmlhttprequest-ssl": "~1.5.4", - "yeast": "0.1.2" - }, - "dependencies": { - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "engine.io-parser": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", - "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", - "dev": true, - "requires": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.5", - "blob": "0.0.5", - "has-binary2": "~1.0.2" - } - }, - "enhanced-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" - } - }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", - "dev": true - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, - "requires": { - "prr": "~1.0.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz", - "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.0", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-inspect": "^1.6.0", - "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.0.0", - "string.prototype.trimright": "^2.0.0" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es5-ext": { - "version": "0.10.51", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.51.tgz", - "integrity": "sha512-oRpWzM2WcLHVKpnrcyB7OW8j/s67Ba04JCm0WnNv3RiABSvs7mrQlutB8DBv793gKcp0XENR8Il8WxGTlZ73gQ==", - "dev": true, - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.1", - "next-tick": "^1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-symbol": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.2.tgz", - "integrity": "sha512-/ZypxQsArlv+KHpGvng52/Iz8by3EQPxhmbuz8yFG89N/caTFBSbcXONDw0aMjy827gQg26XAjP4uXFvnfINmQ==", - "dev": true, - "requires": { - "d": "^1.0.1", - "es5-ext": "^0.10.51" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", - "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", - "dev": true, - "optional": true, - "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } - } - }, - "esdoc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/esdoc/-/esdoc-1.1.0.tgz", - "integrity": "sha512-vsUcp52XJkOWg9m1vDYplGZN2iDzvmjDL5M/Mp8qkoDG3p2s0yIQCIjKR5wfPBaM3eV14a6zhQNYiNTCVzPnxA==", - "dev": true, - "requires": { - "babel-generator": "6.26.1", - "babel-traverse": "6.26.0", - "babylon": "6.18.0", - "cheerio": "1.0.0-rc.2", - "color-logger": "0.0.6", - "escape-html": "1.0.3", - "fs-extra": "5.0.0", - "ice-cap": "0.0.4", - "marked": "0.3.19", - "minimist": "1.2.0", - "taffydb": "2.7.3" - } - }, - "esdoc-accessor-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-accessor-plugin/-/esdoc-accessor-plugin-1.0.0.tgz", - "integrity": "sha1-eRukhy5sQDUVznSbE0jW8Ck62es=", - "dev": true + } }, - "esdoc-brand-plugin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esdoc-brand-plugin/-/esdoc-brand-plugin-1.0.1.tgz", - "integrity": "sha512-Yv9j3M7qk5PSLmSeD6MbPsfIsEf8K43EdH8qZpE/GZwnJCRVmDPrZJ1cLDj/fPu6P35YqgcEaJK4E2NL/CKA7g==", + "engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", "dev": true, "requires": { - "cheerio": "0.22.0" + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" }, "dependencies": { - "cheerio": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash.assignin": "^4.0.9", - "lodash.bind": "^4.1.4", - "lodash.defaults": "^4.0.1", - "lodash.filter": "^4.4.0", - "lodash.flatten": "^4.2.0", - "lodash.foreach": "^4.3.0", - "lodash.map": "^4.4.0", - "lodash.merge": "^4.4.0", - "lodash.pick": "^4.2.1", - "lodash.reduce": "^4.4.0", - "lodash.reject": "^4.4.0", - "lodash.some": "^4.4.0" + "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, - "esdoc-coverage-plugin": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/esdoc-coverage-plugin/-/esdoc-coverage-plugin-1.1.0.tgz", - "integrity": "sha1-OGmGnNf4eJH5cmJXh2laKZrs5Fw=", - "dev": true - }, - "esdoc-ecmascript-proposal-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-ecmascript-proposal-plugin/-/esdoc-ecmascript-proposal-plugin-1.0.0.tgz", - "integrity": "sha1-OQ3FZWuoooMOOdujVw15E43y/9k=", - "dev": true - }, - "esdoc-external-ecmascript-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-external-ecmascript-plugin/-/esdoc-external-ecmascript-plugin-1.0.0.tgz", - "integrity": "sha1-ePVl1KDFGFrGMVJhTc4f4ahmiNs=", + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", "dev": true, "requires": { - "fs-extra": "1.0.0" + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" }, "dependencies": { - "fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" - } + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { - "graceful-fs": "^4.1.6" + "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, - "esdoc-integrate-manual-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-integrate-manual-plugin/-/esdoc-integrate-manual-plugin-1.0.0.tgz", - "integrity": "sha1-GFSmqhwIEDXXyMUeO91PtlqkcRw=", - "dev": true + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } }, - "esdoc-integrate-test-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-integrate-test-plugin/-/esdoc-integrate-test-plugin-1.0.0.tgz", - "integrity": "sha1-4tDQAJD38MNeXS8sAzMnp55T5Ak=", - "dev": true + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } }, - "esdoc-lint-plugin": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/esdoc-lint-plugin/-/esdoc-lint-plugin-1.0.2.tgz", - "integrity": "sha512-24AYqD2WbZI9We02I7/6dzAa7yUliRTFUaJCZAcYJMQicJT5gUrNFVaI8XmWEN/mhF3szIn1uZBNWeLul4CmNw==", + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", "dev": true }, - "esdoc-publish-html-plugin": { + "entities": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/esdoc-publish-html-plugin/-/esdoc-publish-html-plugin-1.1.2.tgz", - "integrity": "sha512-hG1fZmTcEp3P/Hv/qKiMdG1qSp8MjnVZMMkxL5P5ry7I2sX0HQ4P9lt2lms+90Lt0r340HHhSuVx107UL7dphg==", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "dev": true, "requires": { - "babel-generator": "6.11.4", - "cheerio": "0.22.0", - "escape-html": "1.0.3", - "fs-extra": "1.0.0", - "ice-cap": "0.0.4", - "marked": "0.3.19", - "taffydb": "2.7.2" - }, - "dependencies": { - "babel-generator": { - "version": "6.11.4", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.11.4.tgz", - "integrity": "sha1-FPaTOrsgxiZm0n47e59bncBxKpo=", - "dev": true, - "requires": { - "babel-messages": "^6.8.0", - "babel-runtime": "^6.9.0", - "babel-types": "^6.10.2", - "detect-indent": "^3.0.1", - "lodash": "^4.2.0", - "source-map": "^0.5.0" - } - }, - "cheerio": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", - "dev": true, - "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash.assignin": "^4.0.9", - "lodash.bind": "^4.1.4", - "lodash.defaults": "^4.0.1", - "lodash.filter": "^4.4.0", - "lodash.flatten": "^4.2.0", - "lodash.foreach": "^4.3.0", - "lodash.map": "^4.4.0", - "lodash.merge": "^4.4.0", - "lodash.pick": "^4.2.1", - "lodash.reduce": "^4.4.0", - "lodash.reject": "^4.4.0", - "lodash.some": "^4.4.0" - } - }, - "detect-indent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz", - "integrity": "sha1-ncXl3bzu+DJXZLlFGwK8bVQIT3U=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1", - "minimist": "^1.1.0", - "repeating": "^1.1.0" - } - }, - "fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" - } - }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "repeating": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", - "integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "taffydb": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.7.2.tgz", - "integrity": "sha1-e/gQalwaSCUbPjvAoOFzJIn9Dcg=", - "dev": true - } + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz", + "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.0.0", + "string.prototype.trimright": "^2.0.0" } }, - "esdoc-standard-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-standard-plugin/-/esdoc-standard-plugin-1.0.0.tgz", - "integrity": "sha1-ZhIBysfvhokkkCRG/awVJyU8XU0=", + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "dev": true, "requires": { - "esdoc-accessor-plugin": "^1.0.0", - "esdoc-brand-plugin": "^1.0.0", - "esdoc-coverage-plugin": "^1.0.0", - "esdoc-external-ecmascript-plugin": "^1.0.0", - "esdoc-integrate-manual-plugin": "^1.0.0", - "esdoc-integrate-test-plugin": "^1.0.0", - "esdoc-lint-plugin": "^1.0.0", - "esdoc-publish-html-plugin": "^1.0.0", - "esdoc-type-inference-plugin": "^1.0.0", - "esdoc-undocumented-identifier-plugin": "^1.0.0", - "esdoc-unexported-identifier-plugin": "^1.0.0" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" } }, - "esdoc-type-inference-plugin": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/esdoc-type-inference-plugin/-/esdoc-type-inference-plugin-1.0.2.tgz", - "integrity": "sha512-tMIcEHNe1uhUGA7lT1UTWc9hs2dzthnTgmqXpmeUhurk7fL2tinvoH+IVvG/sLROzwOGZQS9zW/F9KWnpMzLIQ==", - "dev": true + "es5-ext": { + "version": "0.10.51", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.51.tgz", + "integrity": "sha512-oRpWzM2WcLHVKpnrcyB7OW8j/s67Ba04JCm0WnNv3RiABSvs7mrQlutB8DBv793gKcp0XENR8Il8WxGTlZ73gQ==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "^1.0.0" + } }, - "esdoc-typescript-plugin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esdoc-typescript-plugin/-/esdoc-typescript-plugin-1.0.1.tgz", - "integrity": "sha512-QV9rdis5PkypVK1fh2wuESZPQZUVjTwt4hj97Pivb9M8wGPMOTxYu5ofkyGWm3xgNL+K0VxZY6TGEO07kfGAtg==", + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", "dev": true, "requires": { - "typescript": "^2.8.3" - }, - "dependencies": { - "typescript": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", - "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", - "dev": true - } + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" } }, - "esdoc-undocumented-identifier-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-undocumented-identifier-plugin/-/esdoc-undocumented-identifier-plugin-1.0.0.tgz", - "integrity": "sha1-guBdNxwy0ShxFA8dXIHsmf2cwsg=", + "es6-symbol": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.2.tgz", + "integrity": "sha512-/ZypxQsArlv+KHpGvng52/Iz8by3EQPxhmbuz8yFG89N/caTFBSbcXONDw0aMjy827gQg26XAjP4uXFvnfINmQ==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.51" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, - "esdoc-unexported-identifier-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-unexported-identifier-plugin/-/esdoc-unexported-identifier-plugin-1.0.0.tgz", - "integrity": "sha1-H5h0xqfCvr+a05fDzrdcnGnaurE=", + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "escodegen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.1.tgz", + "integrity": "sha512-Q8t2YZ+0e0pc7NRVj3B4tSQ9rim1oi4Fh46k2xhJ2qOiEwhQfdjyEQddWdj7ZFaKmU+5104vn1qrcjEPWq+bgQ==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, "eslint": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.4.0.tgz", @@ -4024,8 +5796,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true, - "optional": true + "dev": true }, "esquery": { "version": "1.0.1", @@ -4204,7 +5975,7 @@ "dependencies": { "array-flatten": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", "dev": true }, @@ -4645,12 +6416,12 @@ } }, "fs-extra": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", - "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", + "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } @@ -5380,9 +7151,9 @@ "dev": true }, "handlebars": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.3.3.tgz", - "integrity": "sha512-VupOxR91xcGojfINrzMqrvlyYbBs39sXIrWa7YdaQWeBudOlvKEGvCczMfJPgnuwHE/zyH1M6J+IUP6cgDVyxg==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", "dev": true, "requires": { "neo-async": "^2.6.0", @@ -5537,12 +7308,6 @@ "minimalistic-crypto-utils": "^1.0.1" } }, - "home-or-tmp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-3.0.0.tgz", - "integrity": "sha1-V6j+JM8zzdUkhgoVgh3cJchmcfs=", - "dev": true - }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -5570,6 +7335,15 @@ "wbuf": "^1.1.0" } }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, "html-entities": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", @@ -6105,7 +7879,7 @@ }, "ip": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "resolved": "http://registry.npmjs.org/ip/-/ip-1.1.5.tgz", "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", "dev": true }, @@ -6721,9 +8495,9 @@ "dev": true }, "json5": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", - "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -7120,6 +8894,12 @@ "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", "dev": true }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, "lodash.unescape": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", @@ -7239,9 +9019,9 @@ } }, "marked": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", - "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", + "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", "dev": true }, "md5.js": { @@ -7449,7 +9229,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -7503,7 +9283,7 @@ "dependencies": { "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true } @@ -7530,7 +9310,7 @@ "dependencies": { "commander": { "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, @@ -7781,10 +9561,9 @@ }, "dependencies": { "@babel/parser": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.3.tgz", - "integrity": "sha512-xsH1CJoln2r74hR+y7cg2B5JCPaTh+Hd+EbBRk9nWGSNspuo6krjhX0Om6RnRQuIvFq8wVXCLKH3kwKDYhanSg==", - "dev": true + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz", + "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==" }, "@iarna/toml": { "version": "2.2.3", @@ -7799,23 +9578,16 @@ "dev": true }, "@netlify/zip-it-and-ship-it": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-0.2.1.tgz", - "integrity": "sha512-ot3S0kbLhAK56VH1xyDQ8kFkKsKjhHfwKLRjZ05yU4S8P96gPWyqxANLUKzSZfT8BoeUCjMy6l59WPa7lgHzCg==", - "dev": true, + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-0.3.1.tgz", + "integrity": "sha512-vLKxc1/Kvy7c0TL6AMr39/3SIweMkXZXkfU5nUtw1DSBVXaz9aYtiFLBX8YOblJXFFs3rpcyhzmzctoQsOnqVA==", "requires": { "archiver": "^3.0.0", - "body-parser": "^1.18.3", - "chokidar": "^2.0.4", + "cliclopts": "^1.1.1", "debug": "^4.1.1", "elf-tools": "^1.1.1", - "express": "^4.16.4", - "express-logging": "^1.1.1", - "get-port": "^4.1.0", "glob": "^7.1.3", "npm-packlist": "^1.1.12", - "p-all": "^1.0.0", - "precinct": "^5.2.1", "read-pkg-up": "^4.0.0", "require-package-name": "^2.0.1", "resolve": "^1.10.0" @@ -7900,15 +9672,32 @@ "wrap-ansi": "^4.0.0" }, "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, "string-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.0.0.tgz", - "integrity": "sha512-rr8CUxBbvOZDUvc5lNIJ+OC1nPVpz+Siw9VBtUjB9b6jZehZLFt0JMCZzShFHIsI8cbhm0EsNIfWJMFV3cu3Ew==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.0.0" + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } } } @@ -7927,9 +9716,9 @@ }, "dependencies": { "clean-stack": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.0.0.tgz", - "integrity": "sha512-VEoL9Qh7I8s8iHnV53DaeWSt8NJ0g3khMfK6NiCPB7H657juhro+cSw2O88uo3bo0c0X5usamtXk0/Of0wXa5A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, "cli-ux": { @@ -8065,7 +9854,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -8101,7 +9889,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/archiver/-/archiver-3.0.0.tgz", "integrity": "sha512-5QeR6Xc5hSA9X1rbQfcuQ6VZuUXOaEdB65Dhmk9duuRJHYif/ZyJfuyJqsQrj34PFjU5emv5/MmfgA8un06onw==", - "dev": true, "requires": { "archiver-utils": "^2.0.0", "async": "^2.0.0", @@ -8116,7 +9903,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.0.0.tgz", "integrity": "sha512-JRBgcVvDX4Mwu2RBF8bBaHcQCSxab7afsxAPYDQ5W+19quIPP5CfKE7Ql+UHs9wYvwsaNR8oDuhtf5iqrKmzww==", - "dev": true, "requires": { "glob": "^7.0.0", "graceful-fs": "^4.1.0", @@ -8177,22 +9963,20 @@ "ast-module-types": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/ast-module-types/-/ast-module-types-2.5.0.tgz", - "integrity": "sha512-dP6vhvatex3Q+OThhvcyGRvHn4noQBg1b8lCNKUAFL05up80hr2pAExveU3YQNDGMhfNPhQit/vzIkkvBPbSXw==", - "dev": true + "integrity": "sha512-dP6vhvatex3Q+OThhvcyGRvHn4noQBg1b8lCNKUAFL05up80hr2pAExveU3YQNDGMhfNPhQit/vzIkkvBPbSXw==" }, "async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", - "dev": true, "requires": { "lodash": "^4.17.11" } }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "atob": { @@ -8213,8 +9997,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base": { "version": "0.11.2", @@ -8274,8 +10057,7 @@ "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", - "dev": true + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" }, "before-after-hook": { "version": "1.3.2", @@ -8284,37 +10066,36 @@ "dev": true }, "binary-extensions": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz", - "integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "bl": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", - "dev": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" } }, "body-parser": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", - "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "dev": true, "requires": { - "bytes": "3.0.0", + "bytes": "3.1.0", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "~1.6.3", - "iconv-lite": "0.4.23", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.5.2", - "raw-body": "2.3.3", - "type-is": "~1.6.16" + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" }, "dependencies": { "debug": { @@ -8326,15 +10107,43 @@ "ms": "2.0.0" } }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "dev": true, + "requires": { + "mime-db": "1.43.0" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -8342,10 +10151,38 @@ "dev": true }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } } } }, @@ -8368,7 +10205,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -8413,7 +10249,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", - "dev": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -8423,7 +10258,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "dev": true, "requires": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" @@ -8432,25 +10266,22 @@ "buffer-alloc-unsafe": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "dev": true + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" }, "buffer-fill": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", - "dev": true + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" }, "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", "dev": true }, "cache-base": { @@ -8496,7 +10327,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -8510,9 +10340,9 @@ "dev": true }, "chokidar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.2.tgz", - "integrity": "sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz", + "integrity": "sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -8526,7 +10356,15 @@ "normalize-path": "^3.0.0", "path-is-absolute": "^1.0.0", "readdirp": "^2.2.1", - "upath": "^1.1.0" + "upath": "^1.1.1" + }, + "dependencies": { + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + } } }, "ci-info": { @@ -8662,7 +10500,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -8670,8 +10507,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "colors": { "version": "1.3.3", @@ -8682,8 +10518,7 @@ "commander": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", - "dev": true + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" }, "component-emitter": { "version": "1.2.1", @@ -8695,7 +10530,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz", "integrity": "sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8=", - "dev": true, "requires": { "buffer-crc32": "^0.2.1", "crc32-stream": "^2.0.0", @@ -8707,7 +10541,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" } @@ -8717,8 +10550,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concordance": { "version": "4.0.0", @@ -8797,14 +10629,12 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "crc": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", - "dev": true, "requires": { "buffer": "^5.1.0" } @@ -8813,7 +10643,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", - "dev": true, "requires": { "crc": "^3.4.4", "readable-stream": "^2.0.0" @@ -8866,7 +10695,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -8886,8 +10714,7 @@ "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, "deepmerge": { "version": "3.2.0", @@ -8970,7 +10797,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/detective-amd/-/detective-amd-3.0.0.tgz", "integrity": "sha512-kOpKHyabdSKF9kj7PqYHLeHPw+TJT8q2u48tZYMkIcas28el1CYeLEJ42Nm+563/Fq060T5WknfwDhdX9+kkBQ==", - "dev": true, "requires": { "ast-module-types": "^2.3.1", "escodegen": "^1.8.0", @@ -8982,7 +10808,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/detective-cjs/-/detective-cjs-3.1.1.tgz", "integrity": "sha512-JQtNTBgFY6h8uT6pgph5QpV3IyxDv+z3qPk/FZRDT9TlFfm5dnRtpH39WtQEr1khqsUxVqXzKjZHpdoQvQbllg==", - "dev": true, "requires": { "ast-module-types": "^2.4.0", "node-source-walk": "^4.0.0" @@ -8992,7 +10817,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/detective-es6/-/detective-es6-2.0.0.tgz", "integrity": "sha512-lo2kHVepcq3v39Q/t5uY6sy3cK1g29Kgi4Sj4KpR/15WGwecwma1yaEzZoofyJg/QyeOz36DZhouJ3eD46efCg==", - "dev": true, "requires": { "node-source-walk": "^4.0.0" } @@ -9001,7 +10825,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/detective-less/-/detective-less-1.0.2.tgz", "integrity": "sha512-Rps1xDkEEBSq3kLdsdnHZL1x2S4NGDcbrjmd4q+PykK5aJwDdP5MBgrJw1Xo+kyUHuv3JEzPqxr+Dj9ryeDRTA==", - "dev": true, "requires": { "debug": "^4.0.0", "gonzales-pe": "^4.2.3", @@ -9012,7 +10835,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/detective-postcss/-/detective-postcss-3.0.0.tgz", "integrity": "sha512-Dq4pza3UAT5gXHmNjinxhTydKGd9m3Tr6d0epP9VBipQfQl/ipe3ml7ybxpHk4TRwT2RPXKRsnCHhXfEdpksAQ==", - "dev": true, "requires": { "debug": "^3.1.0", "is-url": "^1.2.4", @@ -9024,7 +10846,6 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -9035,7 +10856,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/detective-sass/-/detective-sass-3.0.1.tgz", "integrity": "sha512-oSbrBozRjJ+QFF4WJFbjPQKeakoaY1GiR380NPqwdbWYd5wfl5cLWv0l6LsJVqrgWfFN1bjFqSeo32Nxza8Lbw==", - "dev": true, "requires": { "debug": "^4.1.1", "gonzales-pe": "^4.2.3", @@ -9046,7 +10866,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/detective-scss/-/detective-scss-2.0.1.tgz", "integrity": "sha512-VveyXW4WQE04s05KlJ8K0bG34jtHQVgTc9InspqoQxvnelj/rdgSAy7i2DXAazyQNFKlWSWbS+Ro2DWKFOKTPQ==", - "dev": true, "requires": { "debug": "^4.1.1", "gonzales-pe": "^4.2.3", @@ -9056,14 +10875,12 @@ "detective-stylus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detective-stylus/-/detective-stylus-1.0.0.tgz", - "integrity": "sha1-UK7n24uruZA4HwEMY/q7pbWOVM0=", - "dev": true + "integrity": "sha1-UK7n24uruZA4HwEMY/q7pbWOVM0=" }, "detective-typescript": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/detective-typescript/-/detective-typescript-4.1.2.tgz", "integrity": "sha512-jeQMIN/0hjMdMpFGoo9y+ibo+dTb1Vbg6z/peHoRMR69jqH691kgz1gT5XM5UfkDD/Ru0save1bSJBmUr2yjvQ==", - "dev": true, "requires": { "node-source-walk": "^4.0.0", "typescript": "^3.0.3", @@ -9094,8 +10911,7 @@ "elf-tools": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/elf-tools/-/elf-tools-1.1.1.tgz", - "integrity": "sha512-SZSL+FS1mooDVRc3js6jUsEtzVrTaFxjqE8aQzyfmABGBW1UvhT6LQzY305vIGaxazY3bKIbxwsYsWynkYeggA==", - "dev": true + "integrity": "sha512-SZSL+FS1mooDVRc3js6jUsEtzVrTaFxjqE8aQzyfmABGBW1UvhT6LQzY305vIGaxazY3bKIbxwsYsWynkYeggA==" }, "emoji-regex": { "version": "7.0.3", @@ -9113,7 +10929,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, "requires": { "once": "^1.4.0" } @@ -9122,7 +10937,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -9161,14 +10975,12 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", - "dev": true, "requires": { "esprima": "^3.1.3", "estraverse": "^4.2.0", @@ -9180,14 +10992,12 @@ "esprima": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "optional": true } } @@ -9201,14 +11011,12 @@ "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, "etag": { "version": "1.8.1", @@ -9319,6 +11127,30 @@ "vary": "~1.1.2" }, "dependencies": { + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -9328,6 +11160,15 @@ "ms": "2.0.0" } }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -9462,15 +11303,14 @@ }, "fast-diff": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, "figures": { "version": "2.0.0", @@ -9544,18 +11384,13 @@ }, "find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "flatten": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", - "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", - "dev": true + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=" }, "flush-write-stream": { "version": "2.0.0", @@ -9638,8 +11473,7 @@ "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "fs-extra": { "version": "7.0.1", @@ -9655,8 +11489,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "1.2.7", @@ -9671,28 +11504,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "resolved": false, "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, "optional": true, @@ -9703,14 +11536,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -9721,35 +11554,35 @@ }, "chownr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "resolved": false, "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true @@ -9766,28 +11599,28 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "resolved": false, "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "resolved": false, "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -9797,14 +11630,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -9821,7 +11654,7 @@ }, "glob": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "resolved": false, "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "optional": true, @@ -9836,14 +11669,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "resolved": false, "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "optional": true, @@ -9853,7 +11686,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "resolved": false, "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -9863,7 +11696,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -9874,21 +11707,21 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -9898,14 +11731,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -9915,14 +11748,14 @@ }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true }, "minipass": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "resolved": false, "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "dev": true, "optional": true, @@ -9933,7 +11766,7 @@ }, "minizlib": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "resolved": false, "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", "dev": true, "optional": true, @@ -9943,7 +11776,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -9991,7 +11824,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -10020,7 +11853,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -10033,21 +11866,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -10057,21 +11890,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -10082,21 +11915,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "resolved": false, "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "optional": true, @@ -10109,7 +11942,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -10118,7 +11951,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -10134,7 +11967,7 @@ }, "rimraf": { "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "resolved": false, "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "optional": true, @@ -10144,21 +11977,21 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "resolved": false, "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true @@ -10172,21 +12005,21 @@ }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -10198,7 +12031,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -10208,7 +12041,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -10218,14 +12051,14 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "resolved": false, "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "dev": true, "optional": true, @@ -10241,14 +12074,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "resolved": false, "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "optional": true, @@ -10258,14 +12091,14 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true }, "yallist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "resolved": false, "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", "dev": true, "optional": true @@ -10282,7 +12115,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-amd-module-type/-/get-amd-module-type-3.0.0.tgz", "integrity": "sha512-99Q7COuACPfVt18zH9N4VAMyb81S6TUgJm2NgV6ERtkh9VIkAaByZkW530wl3lLN5KTtSrK9jVLxYsoP5hQKsw==", - "dev": true, "requires": { "ast-module-types": "^2.3.2", "node-source-walk": "^4.0.0" @@ -10343,7 +12175,6 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -10387,7 +12218,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.2.3.tgz", "integrity": "sha512-Kjhohco0esHQnOiqqdJeNz/5fyPkOMD/d6XVjwTAoPGUFh0mCollPUTUTa2OZy4dYNAqlPIQdTiNzJTWdd9Htw==", - "dev": true, "requires": { "minimist": "1.1.x" } @@ -10414,8 +12244,7 @@ "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, "has": { "version": "1.0.3", @@ -10429,8 +12258,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { "version": "1.0.0", @@ -10482,8 +12310,7 @@ "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", - "dev": true + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" }, "http-call": { "version": "5.2.3", @@ -10539,14 +12366,12 @@ "ieee754": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", - "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", - "dev": true + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==" }, "ignore-walk": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", - "dev": true, "requires": { "minimatch": "^3.0.4" } @@ -10572,14 +12397,12 @@ "indexes-of": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -10588,8 +12411,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", @@ -10647,8 +12469,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-binary-path": { "version": "1.0.1", @@ -10673,17 +12494,23 @@ }, "is-ci": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.1.tgz", + "integrity": "sha1-/P+rQdGcq0365eV15kJGYZsS0ok=", "dev": true, "requires": { - "ci-info": "^1.5.0" + "colors": "^1.1.2", + "minimist": "^1.2.0" }, "dependencies": { "ci-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } } @@ -10753,8 +12580,8 @@ }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, "is-glob": { @@ -10871,8 +12698,7 @@ "is-url": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" }, "is-windows": { "version": "1.0.2", @@ -10889,8 +12715,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -10913,8 +12738,7 @@ "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "jsonfile": { "version": "4.0.0", @@ -10944,7 +12768,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", - "dev": true, "requires": { "readable-stream": "^2.0.5" } @@ -10953,7 +12776,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -10975,7 +12797,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -10984,8 +12805,7 @@ "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash._reinterpolate": { "version": "3.0.0", @@ -10996,8 +12816,7 @@ "lodash.assign": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", - "dev": true + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" }, "lodash.camelcase": { "version": "4.3.0", @@ -11014,20 +12833,17 @@ "lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", - "dev": true + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" }, "lodash.difference": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", - "dev": true + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" }, "lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", - "dev": true + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" }, "lodash.flattendeep": { "version": "4.4.0", @@ -11062,8 +12878,7 @@ "lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" }, "lodash.merge": { "version": "4.6.2", @@ -11105,8 +12920,7 @@ "lodash.toarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", - "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", - "dev": true + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" }, "lodash.transform": { "version": "4.6.0", @@ -11117,14 +12931,12 @@ "lodash.unescape": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", - "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", - "dev": true + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=" }, "lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", - "dev": true + "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" }, "lodash.uniq": { "version": "4.5.0", @@ -11198,18 +13010,14 @@ }, "md5-hex": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz", - "integrity": "sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM=", - "dev": true, - "requires": { - "md5-o-matic": "^0.1.1" - } + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true }, "md5-o-matic": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", - "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", - "dev": true + "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=" }, "media-typer": { "version": "0.3.0", @@ -11287,7 +13095,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -11295,8 +13102,7 @@ "minimist": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz", - "integrity": "sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=", - "dev": true + "integrity": "sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=" }, "mixin-deep": { "version": "1.3.1", @@ -11323,7 +13129,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/module-definition/-/module-definition-3.1.0.tgz", "integrity": "sha512-XtgUeQUi/4UshwxWlCxCjt4SoJC+LJbjHvhGopOskzZOH3GSy2X6KC96APK3rgA9p9hekHcVP87qdwQpSvhNlQ==", - "dev": true, "requires": { "ast-module-types": "^2.4.0", "node-source-walk": "^4.0.0" @@ -11332,8 +13137,7 @@ "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" }, "mute-stream": { "version": "0.0.7", @@ -11410,6 +13214,105 @@ "through2-filter": "^3.0.0", "through2-map": "^3.0.0", "util.promisify": "^1.0.0" + }, + "dependencies": { + "@netlify/zip-it-and-ship-it": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-0.2.5.tgz", + "integrity": "sha512-SF0dM5FDgZkaa2u/3pDh23kEs2X2D6fYUbtz349pTKAYqY+48YEddCnlOLsjcUtGlEC+jVqOaR8zfAbS+covsQ==", + "dev": true, + "requires": { + "archiver": "^3.0.0", + "body-parser": "^1.18.3", + "chokidar": "^2.0.4", + "cliclopts": "^1.1.1", + "debug": "^4.1.1", + "elf-tools": "^1.1.1", + "express": "^4.16.4", + "express-logging": "^1.1.1", + "get-port": "^4.1.0", + "glob": "^7.1.3", + "minimist": "^1.2.0", + "npm-packlist": "^1.1.12", + "p-all": "^2.0.0", + "precinct": "^6.1.1", + "read-pkg-up": "^4.0.0", + "require-package-name": "^2.0.1", + "resolve": "^1.10.0" + } + }, + "detective-typescript": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/detective-typescript/-/detective-typescript-5.7.0.tgz", + "integrity": "sha512-4SQeACXWAjIOsd2kJykPL8gWC9nVA+z8w7KtAdtd/7BCpDfrpI2ZA7pdhsmHv/zxf3ofeqpYi72vCkZ65bAjtA==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "^2.4.0", + "ast-module-types": "^2.5.0", + "node-source-walk": "^4.2.0", + "typescript": "^3.6.4" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "module-definition": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/module-definition/-/module-definition-3.3.0.tgz", + "integrity": "sha512-HTplA9xwDzH67XJFC1YvZMUElWJD28DV0dUq7lhTs+JKJamUOWA/CcYWSlhW5amJO66uWtY7XdltT+LfX0wIVg==", + "dev": true, + "requires": { + "ast-module-types": "^2.6.0", + "node-source-walk": "^4.0.0" + }, + "dependencies": { + "ast-module-types": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/ast-module-types/-/ast-module-types-2.6.0.tgz", + "integrity": "sha512-zXSoVaMrf2R+r+ISid5/9a8SXm1LLdkhHzh6pSRhj9jklzruOOl1hva1YmFT33wAstg/f9ZndJAlq1BSrFLSGA==", + "dev": true + } + } + }, + "p-all": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-all/-/p-all-2.1.0.tgz", + "integrity": "sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==", + "dev": true, + "requires": { + "p-map": "^2.0.0" + } + }, + "precinct": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/precinct/-/precinct-6.2.0.tgz", + "integrity": "sha512-BCAmnOxZzobF3H1/h/gq70pEyvX/BVLWCrzi8beFD22dqu5Z14qOghNUsI24Wg8oaTsGFcIjOGtFX5L9ttmjVg==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "debug": "^4.1.1", + "detective-amd": "^3.0.0", + "detective-cjs": "^3.1.1", + "detective-es6": "^2.0.0", + "detective-less": "^1.0.2", + "detective-postcss": "^3.0.0", + "detective-sass": "^3.0.0", + "detective-scss": "^2.0.0", + "detective-stylus": "^1.0.0", + "detective-typescript": "^5.1.1", + "module-definition": "^3.3.0", + "node-source-walk": "^4.2.0" + } + }, + "typescript": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.4.tgz", + "integrity": "sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==", + "dev": true + } } }, "nice-try": { @@ -11428,7 +13331,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-4.2.0.tgz", "integrity": "sha512-hPs/QMe6zS94f5+jG3kk9E7TNm4P2SulrKiLWMzKszBfNZvL/V6wseHlTd7IvfW0NZWqPtK3+9yYNr+3USGteA==", - "dev": true, "requires": { "@babel/parser": "^7.0.0" } @@ -11437,7 +13339,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, "requires": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -11448,20 +13349,17 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "npm-bundled": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", - "dev": true + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" }, "npm-packlist": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz", "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", - "dev": true, "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1" @@ -11566,7 +13464,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -11584,7 +13481,6 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.4", @@ -11628,7 +13524,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-all/-/p-all-1.0.0.tgz", "integrity": "sha1-k731OlWiOCH9+pi0F0qZv38x340=", - "dev": true, "requires": { "p-map": "^1.0.0" }, @@ -11636,8 +13531,7 @@ "p-map": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", - "dev": true + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==" } } }, @@ -11651,7 +13545,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", - "dev": true, "requires": { "p-try": "^2.0.0" } @@ -11660,7 +13553,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, "requires": { "p-limit": "^2.0.0" } @@ -11683,8 +13575,7 @@ "p-try": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", - "dev": true + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==" }, "p-wait-for": { "version": "2.0.1", @@ -11728,7 +13619,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -11765,14 +13655,12 @@ "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -11789,8 +13677,7 @@ "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "path-to-regexp": { "version": "0.1.7", @@ -11802,7 +13689,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, "requires": { "pify": "^3.0.0" } @@ -11810,8 +13696,7 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "posix-character-classes": { "version": "0.1.1", @@ -11823,7 +13708,6 @@ "version": "7.0.14", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", - "dev": true, "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -11833,14 +13717,12 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -11851,7 +13733,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-1.5.0.tgz", "integrity": "sha512-3M3p+2gMp0AH3da530TlX8kiO1nxdTnc3C6vr8dMxRLIlh8UYkz0/wcwptSXjhtx2Fr0TySI7a+BHDQ8NL7LaQ==", - "dev": true, "requires": { "flatten": "^1.0.2", "indexes-of": "^1.0.1", @@ -11862,7 +13743,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/precinct/-/precinct-5.3.1.tgz", "integrity": "sha512-HOIXDarP6S5JXYC5GhnpoAj9RqJ6yAwZ8VI71vQFlq1rmkBRPs+Mt60TOr7DUc/fx309iIQaniB4x3zueOOSdw==", - "dev": true, "requires": { "commander": "^2.19.0", "debug": "^4.1.1", @@ -11888,8 +13768,7 @@ "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, "prepend-http": { "version": "1.0.4", @@ -11918,8 +13797,7 @@ "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "proxy-addr": { "version": "2.0.4", @@ -11977,6 +13855,12 @@ "unpipe": "1.0.0" }, "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, "iconv-lite": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", @@ -12012,7 +13896,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, "requires": { "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", @@ -12023,7 +13906,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", @@ -12037,7 +13919,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, "requires": { "find-up": "^3.0.0", "read-pkg": "^3.0.0" @@ -12047,7 +13928,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12110,8 +13990,7 @@ "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" }, "repeat-element": { "version": "1.1.3", @@ -12128,14 +14007,12 @@ "require-package-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/require-package-name/-/require-package-name-2.0.1.tgz", - "integrity": "sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk=", - "dev": true + "integrity": "sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk=" }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", - "dev": true, "requires": { "path-parse": "^1.0.6" } @@ -12183,8 +14060,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -12204,8 +14080,7 @@ "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", - "dev": true + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, "semver-diff": { "version": "2.1.0", @@ -12473,7 +14348,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -12482,14 +14356,12 @@ "spdx-exceptions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==" }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -12498,8 +14370,7 @@ "spdx-license-ids": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", - "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", - "dev": true + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==" }, "split-string": { "version": "3.1.0", @@ -12568,7 +14439,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -12585,8 +14455,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" }, "strip-eof": { "version": "1.0.0", @@ -12604,7 +14473,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -12631,7 +14499,6 @@ "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "dev": true, "requires": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", @@ -12755,8 +14622,7 @@ "to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", - "dev": true + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" }, "to-object-path": { "version": "0.3.0", @@ -12825,7 +14691,6 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, "requires": { "prelude-ls": "~1.1.2" } @@ -12843,14 +14708,12 @@ "typescript": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3.tgz", - "integrity": "sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A==", - "dev": true + "integrity": "sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A==" }, "typescript-eslint-parser": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/typescript-eslint-parser/-/typescript-eslint-parser-18.0.0.tgz", "integrity": "sha512-Pn/A/Cw9ysiXSX5U1xjBmPQlxtWGV2o7jDNiH/u7KgBO2yC/y37wNFl2ogSrGZBQFuglLzGq0Xl0Bt31Jv44oA==", - "dev": true, "requires": { "lodash.unescape": "4.0.1", "semver": "5.5.0" @@ -12859,8 +14722,7 @@ "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" } } }, @@ -12902,8 +14764,7 @@ "uniq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" }, "unique-string": { "version": "1.0.0", @@ -12984,8 +14845,7 @@ "upath": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", - "dev": true + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==" }, "update-notifier": { "version": "2.5.0", @@ -13060,8 +14920,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util.promisify": { "version": "1.0.0", @@ -13089,7 +14948,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -13146,8 +15004,7 @@ "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" }, "wrap-ansi": { "version": "4.0.0", @@ -13180,8 +15037,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { "version": "2.4.2", @@ -13203,8 +15059,7 @@ "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, "yallist": { "version": "2.1.2", @@ -13222,7 +15077,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-2.0.1.tgz", "integrity": "sha512-c+eUhhkDpaK87G/py74wvWLtz2kzMPNCCkUApkun50ssE0oQliIQzWpTnwjB+MTKVIf2tGzIgHyqW/Y+W77ecQ==", - "dev": true, "requires": { "archiver-utils": "^2.0.0", "compress-commons": "^1.2.0", @@ -13309,19 +15163,21 @@ } } }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, "node-releases": { - "version": "1.1.32", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.32.tgz", - "integrity": "sha512-VhVknkitq8dqtWoluagsGPn3dxTvN9fwgR59fV3D7sLBHe0JfDramsMI8n8mY//ccq/Kkrf8ZRHRpsyVZ3qw1A==", + "version": "1.1.43", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.43.tgz", + "integrity": "sha512-Rmfnj52WNhvr83MvuAWHEqXVoZXCcDQssSOffU4n4XOL9sPrP61mSZ88g25NqmABDvH7PiAlFCzoSCSdzA293w==", "dev": true, "requires": { - "semver": "^5.3.0" + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "normalize-package-data": { @@ -13373,6 +15229,12 @@ "dev": true, "optional": true }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -13544,7 +15406,7 @@ "dependencies": { "minimist": { "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", "dev": true }, @@ -13872,15 +15734,6 @@ "pinkie": "^2.0.0" } }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } - }, "pkg-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", @@ -13899,6 +15752,12 @@ "semver-compare": "^1.0.0" } }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, "portfinder": { "version": "1.0.24", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.24.tgz", @@ -14146,7 +16005,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -14261,15 +16120,15 @@ } }, "regjsgen": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", - "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", "dev": true }, "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.1.tgz", + "integrity": "sha512-7LutE94sz/NKSYegK+/4E77+8DipxF+Qn2Tmu362AcmsF2NYq/wx3+ObvU90TKEhjf7hQoFXo23ajjrXP7eUgg==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -14277,7 +16136,7 @@ "dependencies": { "jsesc": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true } @@ -14338,6 +16197,26 @@ "uuid": "^3.3.2" } }, + "request-promise-core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "request-promise-native": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "dev": true, + "requires": { + "request-promise-core": "1.1.3", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -14505,6 +16384,15 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "saxes": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", + "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", + "dev": true, + "requires": { + "xmlchars": "^2.1.1" + } + }, "schema-utils": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", @@ -14637,9 +16525,9 @@ } }, "serialize-javascript": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", - "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", "dev": true }, "serve-index": { @@ -14748,7 +16636,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -15108,9 +16996,9 @@ } }, "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -15281,6 +17169,12 @@ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, "stream-browserify": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", @@ -15315,9 +17209,9 @@ } }, "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, "streamroller": { @@ -15413,7 +17307,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -15460,8 +17354,7 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, - "optional": true + "dev": true }, "table": { "version": "5.4.6", @@ -15537,9 +17430,9 @@ } }, "terser": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.1.tgz", - "integrity": "sha512-pnzH6dnFEsR2aa2SJaKb1uSCl3QmIsJ8dEkj0Fky+2AwMMcC9doMqLOQIH6wVTEKaVfKVvLSk5qxPBEZT9mywg==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.4.3.tgz", + "integrity": "sha512-0ikKraVtRDKGzHrzkCv5rUNDzqlhmhowOBqC0XqUHFpW+vJ45+20/IFBcebwKfiS2Z9fJin6Eo+F1zLZsxi8RA==", "dev": true, "requires": { "commander": "^2.20.0", @@ -15556,28 +17449,22 @@ } }, "terser-webpack-plugin": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz", - "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", "dev": true, "requires": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", "is-wsl": "^1.1.0", "schema-utils": "^1.0.0", - "serialize-javascript": "^1.7.0", + "serialize-javascript": "^2.1.2", "source-map": "^0.6.1", "terser": "^4.1.2", "webpack-sources": "^1.4.0", "worker-farm": "^1.7.0" }, "dependencies": { - "ajv-keywords": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", - "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", - "dev": true - }, "find-cache-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", @@ -15891,7 +17778,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -15959,58 +17846,24 @@ "integrity": "sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==", "dev": true }, - "typescript-eslint-parser": { - "version": "21.0.2", - "resolved": "https://registry.npmjs.org/typescript-eslint-parser/-/typescript-eslint-parser-21.0.2.tgz", - "integrity": "sha512-u+pj4RVJBr4eTzj0n5npoXD/oRthvfUCjSKndhNI714MG0mQq2DJw5WP7qmonRNIFgmZuvdDOH3BHm9iOjIAfg==", - "dev": true, - "requires": { - "eslint-scope": "^4.0.0", - "eslint-visitor-keys": "^1.0.0", - "typescript-estree": "5.3.0" - }, - "dependencies": { - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - } - } - }, - "typescript-estree": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/typescript-estree/-/typescript-estree-5.3.0.tgz", - "integrity": "sha512-Vu0KmYdSCkpae+J48wsFC1ti19Hq3Wi/lODUaE+uesc3gzqhWbZ5itWbsjylLVbjNW4K41RqDzSfnaYNbmEiMQ==", - "dev": true, - "requires": { - "lodash.unescape": "4.0.1", - "semver": "5.5.0" - }, - "dependencies": { - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true - } - } - }, "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.2.tgz", + "integrity": "sha512-uhRwZcANNWVLrxLfNFEdltoPNhECUR3lc+UdJoG9CBpMcSnKyWA94tc3eAujB1GcMY5Uwq8ZMp4qWpxWYDQmaA==", "dev": true, "optional": true, "requires": { - "commander": "~2.20.0", + "commander": "~2.20.3", "source-map": "~0.6.1" }, "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "optional": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -16319,6 +18172,40 @@ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", "dev": true }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "w3c-xmlserializer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", + "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "dev": true, + "requires": { + "domexception": "^1.0.1", + "webidl-conversions": "^4.0.2", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + } + } + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", @@ -16758,6 +18645,49 @@ "integrity": "sha512-2akF8FIyUvbiBBdD+RoHpoTbHMQF2HwjcxfDvgztAX5YwbZNyrtfUMgvfgFVsgDhDPVTlkbb5vyasqDHfIDPQw==", "dev": true }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + }, + "dependencies": { + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + } + } + }, "whatwg-url-compat": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz", @@ -16880,6 +18810,12 @@ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "xmlhttprequest-ssl": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", diff --git a/package.json b/package.json index ca7a3fa735c..a478e21704a 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "test": "npm run test:unit && npm run test:func", "test:unit": "karma start karma.conf.js", "test:unit:watch": "karma start karma.conf.js --auto-watch --no-single-run", - "test:func": "BABEL_ENV=development mocha --require @babel/register tests/functional/auto/setup.js --timeout 40000 --exit", + "test:func": "BABEL_ENV=development mocha tests/functional/auto/setup.js --timeout 40000 --exit", "type-check": "tsc --noEmit", "type-check:watch": "npm run type-check -- --watch" }, @@ -48,27 +48,28 @@ "url-toolkit": "^2.1.6" }, "devDependencies": { - "@babel/core": "7.2.0", - "@babel/helper-module-imports": "7.0.0", - "@babel/plugin-proposal-class-properties": "^7.3.0", - "@babel/plugin-proposal-object-rest-spread": "^7.3.2", - "@babel/plugin-transform-object-assign": "^7.2.0", - "@babel/preset-env": "7.2.0", - "@babel/preset-typescript": "^7.1.0", - "@babel/register": "^7.0.0", + "@babel/core": "^7.7.7", + "@babel/helper-module-imports": "^7.7.4", + "@babel/plugin-proposal-class-properties": "^7.7.4", + "@babel/plugin-proposal-object-rest-spread": "^7.7.7", + "@babel/plugin-proposal-optional-chaining": "^7.7.5", + "@babel/plugin-transform-object-assign": "^7.7.4", + "@babel/preset-env": "^7.7.7", + "@babel/preset-typescript": "^7.7.7", + "@itsjamie/esdoc-cli": "^0.2.0", + "@itsjamie/esdoc-core": "^0.2.0", + "@itsjamie/esdoc-ecmascript-proposal-plugin": "^0.2.0", + "@itsjamie/esdoc-standard-plugin": "^0.2.0", + "@itsjamie/esdoc-typescript-plugin": "^0.2.0", "@types/chai": "^4.1.7", "@types/mocha": "^5.2.6", "@types/sinon-chai": "^3.2.2", - "@typescript-eslint/eslint-plugin": "^2.3.1", - "@typescript-eslint/parser": "^2.3.1", + "@typescript-eslint/eslint-plugin": "^2.12.0", + "@typescript-eslint/parser": "^2.12.0", "babel-loader": "8.0.4", "babel-plugin-transform-remove-console": "6.9.4", "chai": "4.2.0", - "chromedriver": "78.0.1", - "esdoc": "^1.1.0", - "esdoc-ecmascript-proposal-plugin": "^1.0.0", - "esdoc-standard-plugin": "^1.0.0", - "esdoc-typescript-plugin": "^1.0.1", + "chromedriver": "^79.0.0", "eslint": "^6.4.0", "eslint-config-standard": "^14.1.0", "eslint-plugin-import": "^2.18.2", @@ -93,7 +94,6 @@ "sinon": "7.1.1", "sinon-chai": "3.3.0", "typescript": "^3.7.4", - "typescript-eslint-parser": "^21.0.2", "webpack": "^4.27.1", "webpack-cli": "^3.1.2", "webpack-dev-server": "^3.1.4", diff --git a/src/config.ts b/src/config.ts index 624ffe8b7e0..c53278a3514 100644 --- a/src/config.ts +++ b/src/config.ts @@ -141,10 +141,10 @@ export type HlsConfig = // EME emeController?: typeof EMEController, - abrController: any, // TODO(typescript-abrcontroller): Type once file is done + abrController: typeof AbrController, bufferController: typeof BufferController, - capLevelController: any, // TODO(typescript-caplevelcontroller): Type once file is done - fpsController: any, // TODO(typescript-fpscontroller): Type once file is done + capLevelController: typeof CapLevelController, + fpsController: typeof FPSController, renderNatively: boolean, progressive: boolean } & diff --git a/src/controller/abr-controller.ts b/src/controller/abr-controller.ts index 515e65eedc5..33996998c6b 100644 --- a/src/controller/abr-controller.ts +++ b/src/controller/abr-controller.ts @@ -4,8 +4,7 @@ * - implement an abandon rules triggered if we have less than 2 frag buffered and if computed bw shows that we risk buffer stalling */ -import Event from '../events'; -import EventHandler from '../event-handler'; +import { Events } from '../events'; import { BufferHelper, Bufferable } from '../utils/buffer-helper'; import { ErrorDetails } from '../errors'; import { logger } from '../utils/logger'; @@ -13,39 +12,56 @@ import EwmaBandWidthEstimator from '../utils/ewma-bandwidth-estimator'; import Fragment from '../loader/fragment'; import { LoaderStats } from '../types/loader'; import LevelDetails from '../loader/level-details'; -import { LevelLoadedData } from '../types/events'; import Hls from '../hls'; +import { FragLoadingData, FragLoadedData, FragBufferedData, ErrorData, LevelLoadedData } from '../types/events'; +import { ComponentAPI } from '../types/component-api'; const { performance } = self; -class AbrController extends EventHandler { +class AbrController implements ComponentAPI { protected hls: Hls; private lastLoadedFragLevel: number = 0; private _nextAutoLevel: number = -1; private timer?: number; - private readonly _bwEstimator: EwmaBandWidthEstimator; private onCheck: Function = this._abandonRulesCheck.bind(this); private fragCurrent: Fragment | null = null; private bitrateTestDelay: number = 0; - constructor (hls) { - super(hls, Event.FRAG_LOADING, - Event.FRAG_LOADED, - Event.FRAG_BUFFERED, - Event.LEVEL_LOADED, - Event.ERROR); + public readonly bwEstimator: EwmaBandWidthEstimator; + + constructor (hls: Hls) { this.hls = hls; const config = hls.config; - this._bwEstimator = new EwmaBandWidthEstimator(config.abrEwmaSlowVoD, config.abrEwmaFastVoD, config.abrEwmaDefaultEstimate); + this.bwEstimator = new EwmaBandWidthEstimator(config.abrEwmaSlowVoD, config.abrEwmaFastVoD, config.abrEwmaDefaultEstimate); + + this.registerListeners(); + } + + protected registerListeners () { + const { hls } = this; + hls.on(Events.FRAG_LOADING, this.onFragLoading, this); + hls.on(Events.FRAG_LOADED, this.onFragLoaded, this); + hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this); + hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this); + hls.on(Events.ERROR, this.onError, this); + } + + protected unregisterListeners () { + const { hls } = this; + hls.off(Events.FRAG_LOADING, this.onFragLoading, this); + hls.off(Events.FRAG_LOADED, this.onFragLoaded, this); + hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this); + hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this); + hls.off(Events.ERROR, this.onError, this); } - destroy () { + public destroy () { + this.unregisterListeners(); this.clearTimer(); - super.destroy.call(this); } - protected onFragLoading (data: { frag: Fragment }) { + protected onFragLoading (event: Events.FRAG_LOADING, data: FragLoadingData) { const frag = data.frag; if (frag.type === 'main') { if (!this.timer) { @@ -55,12 +71,12 @@ class AbrController extends EventHandler { } } - protected onLevelLoaded (data: LevelLoadedData) { + protected onLevelLoaded (event: Events.LEVEL_LOADED, data: LevelLoadedData) { const config = this.hls.config; if (data.details.live) { - this._bwEstimator.update(config.abrEwmaSlowLive, config.abrEwmaFastLive); + this.bwEstimator.update(config.abrEwmaSlowLive, config.abrEwmaFastLive); } else { - this._bwEstimator.update(config.abrEwmaSlowVoD, config.abrEwmaFastVoD); + this.bwEstimator.update(config.abrEwmaSlowVoD, config.abrEwmaFastVoD); } } @@ -136,20 +152,20 @@ class AbrController extends EventHandler { if (fragLevelNextLoadedDelay >= fragLoadedDelay) { return; } - const bwEstimate: number = this._bwEstimator.getEstimate(); + const bwEstimate: number = this.bwEstimator.getEstimate(); logger.warn(`Fragment ${frag.sn} of level ${frag.level} is loading too slowly and will cause an underbuffer; aborting and switching to level ${nextLoadLevel} Current BW estimate: ${Number.isFinite(bwEstimate) ? (bwEstimate / 1024).toFixed(3) : 'Unknown'} Kb/s Estimated load time for current fragment: ${fragLoadedDelay.toFixed(3)} s Estimated load time for the next fragment: ${fragLevelNextLoadedDelay.toFixed(3)} s Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s`); hls.nextLoadLevel = nextLoadLevel; - this._bwEstimator.sample(requestDelay, stats.loaded); + this.bwEstimator.sample(requestDelay, stats.loaded); loader.abort(); this.clearTimer(); - hls.trigger(Event.FRAG_LOAD_EMERGENCY_ABORTED, { frag, stats }); + hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, { frag, stats }); } - protected onFragLoaded (data: { frag: Fragment }) { + protected onFragLoaded (event: Events.FRAG_LOADED, data: FragLoadedData) { const frag = data.frag; const stats = frag.stats; if (frag.type === 'main' && Number.isFinite(frag.sn as number)) { @@ -162,19 +178,20 @@ class AbrController extends EventHandler { // compute level average bitrate if (this.hls.config.abrMaxWithRealBitrate) { - const level = this.hls.levels[frag.level]; + const level = (this.hls.levels[frag.level] as any); + // TODO: stats on level don't match with types, but it's likely true. const loadedBytes = (level.loaded ? level.loaded.bytes : 0) + stats.loaded; const loadedDuration = (level.loaded ? level.loaded.duration : 0) + frag.duration; level.loaded = { bytes: loadedBytes, duration: loadedDuration }; level.realBitrate = Math.round(8 * loadedBytes / loadedDuration); } if (frag.bitrateTest) { - this.onFragBuffered(data); + this.onFragBuffered(Events.FRAG_BUFFERED, data); } } } - protected onFragBuffered (data: { frag: Fragment }) { + protected onFragBuffered (event: Events.FRAG_BUFFERED, data: Omit) { const frag = data.frag; const stats = frag.stats; @@ -190,8 +207,8 @@ class AbrController extends EventHandler { // rationale is that buffer appending only happens once media is attached. This can happen when config.startFragPrefetch // is used. If we used buffering in that case, our BW estimate sample will be very large. const fragLoadingProcessingMs = stats.parsing.end - stats.loading.start; - this._bwEstimator.sample(fragLoadingProcessingMs, stats.loaded); - stats.bwEstimate = this._bwEstimator.getEstimate(); + this.bwEstimator.sample(fragLoadingProcessingMs, stats.loaded); + stats.bwEstimate = this.bwEstimator.getEstimate(); if (frag.bitrateTest) { this.bitrateTestDelay = fragLoadingProcessingMs / 1000; } else { @@ -199,7 +216,7 @@ class AbrController extends EventHandler { } } - protected onError (data) { + protected onError (event: Events.ERROR, data: ErrorData) { // stop timer in case of frag loading error switch (data.details) { case ErrorDetails.FRAG_LOAD_ERROR: @@ -219,7 +236,7 @@ class AbrController extends EventHandler { // return next auto level get nextAutoLevel () { const forcedAutoLevel = this._nextAutoLevel; - const bwEstimator = this._bwEstimator; + const bwEstimator = this.bwEstimator; // in case next auto level has been forced, and bw not available or not reliable, return forced value if (forcedAutoLevel !== -1 && (!bwEstimator || !bwEstimator.canEstimate())) { return forcedAutoLevel; @@ -244,7 +261,7 @@ class AbrController extends EventHandler { // playbackRate is the absolute value of the playback rate; if media.playbackRate is 0, we use 1 to load as // if we're playing back at the normal rate. const playbackRate = ((media && (media.playbackRate !== 0)) ? Math.abs(media.playbackRate) : 1.0); - const avgbw = this._bwEstimator ? this._bwEstimator.getEstimate() : config.abrEwmaDefaultEstimate; + const avgbw = this.bwEstimator ? this.bwEstimator.getEstimate() : config.abrEwmaDefaultEstimate; // bufferStarvationDelay is the wall-clock time left until the playback buffer is exhausted. const bufferStarvationDelay = (BufferHelper.bufferInfo(media as Bufferable, pos, config.maxBufferHole).end - pos) / playbackRate; diff --git a/src/controller/audio-stream-controller.ts b/src/controller/audio-stream-controller.ts index 426b8f3b72c..b82c3916d3f 100644 --- a/src/controller/audio-stream-controller.ts +++ b/src/controller/audio-stream-controller.ts @@ -1,29 +1,31 @@ import { BufferHelper } from '../utils/buffer-helper'; import TransmuxerInterface from '../demux/transmuxer-interface'; -import Event from '../events'; +import { Events } from '../events'; import TimeRanges from '../utils/time-ranges'; import { ErrorDetails } from '../errors'; import { logger } from '../utils/logger'; -import { FragmentState } from './fragment-tracker'; +import { FragmentState, FragmentTracker } from './fragment-tracker'; import Fragment, { ElementaryStreamTypes } from '../loader/fragment'; import BaseStreamController, { State } from './base-stream-controller'; import FragmentLoader from '../loader/fragment-loader'; import ChunkCache from '../demux/chunk-cache'; import LevelDetails from '../loader/level-details'; import { ChunkMetadata, TransmuxerResult } from '../types/transmuxer'; -import { BufferAppendingEventPayload, TrackLoadedData, AudioTracksUpdated } from '../types/events'; +import { BufferAppendingData, TrackLoadedData, AudioTracksUpdatedData, MediaAttachingData, FragBufferedData, BufferCreatedData, AudioTrackSwitchingData } from '../types/events'; import { TrackSet } from '../types/track'; import { Level } from '../types/level'; +import Hls from '../hls'; +import { ComponentAPI } from '../types/component-api'; const { performance } = self; const TICK_INTERVAL = 100; // how often to tick in ms -class AudioStreamController extends BaseStreamController { +class AudioStreamController extends BaseStreamController implements ComponentAPI { private retryDate: number = 0; - private onvseeking: Function | null = null; - private onvseeked: Function | null = null; - private onvended: Function | null = null; + private onvseeking: EventListener | null = null; + private onvseeked: EventListener | null = null; + private onvended: EventListener | null = null; private videoBuffer: any | null = null; private initPTS: any = []; private videoTrackCC: number = -1; @@ -33,29 +35,53 @@ class AudioStreamController extends BaseStreamController { protected readonly logPrefix = '[audio-stream-controller]'; - constructor (hls, fragmentTracker) { - super(hls, - Event.MEDIA_ATTACHED, - Event.MEDIA_DETACHING, - Event.AUDIO_TRACKS_UPDATED, - Event.AUDIO_TRACK_SWITCHING, - Event.AUDIO_TRACK_LOADED, - Event.KEY_LOADED, - Event.ERROR, - Event.BUFFER_RESET, - Event.BUFFER_CREATED, - Event.BUFFER_FLUSHED, - Event.INIT_PTS_FOUND, - Event.FRAG_BUFFERED - ); - + constructor (hls: Hls, fragmentTracker: FragmentTracker) { + super(hls); this.config = hls.config; this.fragmentTracker = fragmentTracker; this.fragmentLoader = new FragmentLoader(hls.config); + + this._registerListeners(); + } + + protected onHandlerDestroying () { + this._unregisterListeners(); + } + + private _registerListeners () { + const { hls } = this; + hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this); + hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + hls.on(Events.AUDIO_TRACKS_UPDATED, this.onAudioTracksUpdated, this); + hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this); + hls.on(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this); + hls.on(Events.KEY_LOADED, this.onKeyLoaded, this); + hls.on(Events.ERROR, this.onError, this); + hls.on(Events.BUFFER_RESET, this.onBufferReset, this); + hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this); + hls.on(Events.BUFFER_FLUSHED, this.onBufferFlushed, this); + hls.on(Events.INIT_PTS_FOUND, this.onInitPtsFound, this); + hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this); + } + + private _unregisterListeners () { + const { hls } = this; + hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this); + hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + hls.off(Events.AUDIO_TRACKS_UPDATED, this.onAudioTracksUpdated, this); + hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this); + hls.off(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this); + hls.off(Events.KEY_LOADED, this.onKeyLoaded, this); + hls.off(Events.ERROR, this.onError, this); + hls.off(Events.BUFFER_RESET, this.onBufferReset, this); + hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this); + hls.off(Events.BUFFER_FLUSHED, this.onBufferFlushed, this); + hls.off(Events.INIT_PTS_FOUND, this.onInitPtsFound, this); + hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this); } // INIT_PTS_FOUND is triggered when the video track parsed in the stream-controller has a new PTS value - onInitPtsFound ({ frag, initPTS }) { + onInitPtsFound (event: Events.INIT_PTS_FOUND, { frag, initPTS }) { // Always update the new INIT PTS // Can change due level switch const cc = frag.cc; @@ -106,7 +132,7 @@ class AudioStreamController extends BaseStreamController { break; case State.WAITING_TRACK: { const { levels, trackId } = this; - if (levels && levels[trackId] && levels[trackId].details) { + if (levels?.[trackId]?.details) { // check if playlist is already loaded this.state = State.WAITING_INIT_PTS; } @@ -115,9 +141,8 @@ class AudioStreamController extends BaseStreamController { case State.FRAG_LOADING_WAITING_RETRY: { const now = performance.now(); const retryDate = this.retryDate; - const isSeeking = media && media.seeking; // if current time is gt than retryDate, or if media seeking let's switch to IDLE state to retry loading - if (!retryDate || (now >= retryDate) || isSeeking) { + if (!retryDate || (now >= retryDate) || media?.seeking) { this.log('RetryDate reached, switch back to IDLE state'); this.state = State.IDLE; } @@ -217,7 +242,7 @@ class AudioStreamController extends BaseStreamController { } if (!audioSwitch && this._streamEnded(bufferInfo, trackDetails)) { - hls.trigger(Event.BUFFER_EOS, { type: 'audio' }); + hls.trigger(Events.BUFFER_EOS, { type: 'audio' }); this.state = State.ENDED; return; } @@ -246,19 +271,19 @@ class AudioStreamController extends BaseStreamController { if (frag.encrypted) { this.log(`Loading key for ${frag.sn} of [${trackDetails.startSN} ,${trackDetails.endSN}],track ${trackId}`); this.state = State.KEY_LOADING; - hls.trigger(Event.KEY_LOADING, { frag: frag }); + hls.trigger(Events.KEY_LOADING, { frag: frag }); } else { this.log(`Loading ${frag.sn}, cc: ${frag.cc} of [${trackDetails.startSN} ,${trackDetails.endSN}],track ${trackId}, currentTime:${pos},bufferEnd:${bufferInfo.end.toFixed(3)}`); this.loadFragment(frag); } } - onMediaAttached (data) { + onMediaAttached (event: Events.MEDIA_ATTACHED, data: MediaAttachingData) { const media = this.media = this.mediaBuffer = data.media; this.onvseeking = this.onMediaSeeking.bind(this); this.onvended = this.onMediaEnded.bind(this); - media.addEventListener('seeking', this.onvseeking); - media.addEventListener('ended', this.onvended); + media.addEventListener('seeking', this.onvseeking as EventListener); + media.addEventListener('ended', this.onvended as EventListener); const config = this.config; if (this.levels && config.autoStartLoad) { this.startLoad(config.startPosition); @@ -267,7 +292,7 @@ class AudioStreamController extends BaseStreamController { onMediaDetaching () { const media = this.media; - if (media && media.ended) { + if (media?.ended) { this.log('MSE detaching and video ended, reset startPosition'); this.startPosition = this.lastCurrentTime = 0; } @@ -284,18 +309,18 @@ class AudioStreamController extends BaseStreamController { this.stopLoad(); } - onAudioTracksUpdated ({ audioTracks }: AudioTracksUpdated) { + onAudioTracksUpdated (event: Events.AUDIO_TRACKS_UPDATED, { audioTracks }: AudioTracksUpdatedData) { this.log('Audio tracks updated'); this.levels = audioTracks.map(mediaPlaylist => new Level(mediaPlaylist)); } - onAudioTrackSwitching (data) { + onAudioTrackSwitching (event: Events.AUDIO_TRACK_SWITCHING, data: AudioTrackSwitchingData) { // if any URL found on new audio track, it is an alternate audio track const altAudio = !!data.url; this.trackId = data.id; const { fragCurrent, transmuxer } = this; - if (fragCurrent && fragCurrent.loader) { + if (fragCurrent?.loader) { fragCurrent.loader.abort(); } this.fragCurrent = null; @@ -322,7 +347,7 @@ class AudioStreamController extends BaseStreamController { this.tick(); } - onAudioTrackLoaded (data: TrackLoadedData) { + onAudioTrackLoaded (event: Events.AUDIO_TRACK_LOADED, data: TrackLoadedData) { const { levels } = this; const { details: newDetails, id: trackId } = data; if (!levels) { @@ -409,7 +434,7 @@ class AudioStreamController extends BaseStreamController { this.loadedmetadata = false; } - onBufferCreated (data) { + onBufferCreated (event: Events.BUFFER_CREATED, data: BufferCreatedData) { const audioTrack = data.tracks.audio; if (audioTrack) { this.mediaBuffer = audioTrack.buffer; @@ -419,7 +444,7 @@ class AudioStreamController extends BaseStreamController { } } - onFragBuffered (data: { frag: Fragment }) { + onFragBuffered (event: Events.FRAG_BUFFERED, data: FragBufferedData) { const { frag } = data; if (frag && frag.type !== 'audio') { return; @@ -435,7 +460,7 @@ class AudioStreamController extends BaseStreamController { this.log(`Buffered fragment ${frag.sn} of level ${frag.level}. PTS:[${frag.startPTS},${frag.endPTS}],DTS:[${frag.startDTS}/${frag.endDTS}], Buffered: ${TimeRanges.toString(media.buffered)}`); if (this.audioSwitch && frag.sn !== 'initSegment') { this.audioSwitch = false; - this.hls.trigger(Event.AUDIO_TRACK_SWITCHED, { id: this.trackId }); + this.hls.trigger(Events.AUDIO_TRACK_SWITCHED, { id: this.trackId }); } this.state = State.IDLE; this.tick(); @@ -516,7 +541,7 @@ class AudioStreamController extends BaseStreamController { this.warn('Buffer full error also media.currentTime is not buffered, flush audio buffer'); this.fragCurrent = null; // flush everything - this.hls.trigger(Event.BUFFER_FLUSHING, { startOffset: 0, endOffset: Number.POSITIVE_INFINITY, type: 'audio' }); + this.hls.trigger(Events.BUFFER_FLUSHING, { startOffset: 0, endOffset: Number.POSITIVE_INFINITY, type: 'audio' }); } } break; @@ -558,9 +583,9 @@ class AudioStreamController extends BaseStreamController { this.completeAudioSwitch(); } - if (initSegment && initSegment.tracks) { + if (initSegment?.tracks) { this._bufferInitSegment(initSegment.tracks, frag, chunkMeta); - hls.trigger(Event.FRAG_PARSING_INIT_SEGMENT, { frag, id, tracks: initSegment.tracks }); + hls.trigger(Events.FRAG_PARSING_INIT_SEGMENT, { frag, id, tracks: initSegment.tracks }); // Only flush audio from old audio tracks when PTS is known on new audio track } if (audio) { @@ -572,13 +597,13 @@ class AudioStreamController extends BaseStreamController { const emittedID3: any = id3; emittedID3.frag = frag; emittedID3.id = id; - hls.trigger(Event.FRAG_PARSING_METADATA, emittedID3); + hls.trigger(Events.FRAG_PARSING_METADATA, emittedID3); } if (text) { const emittedText: any = text; emittedText.frag = frag; emittedText.id = id; - hls.trigger(Event.FRAG_PARSING_USERDATA, emittedText); + hls.trigger(Events.FRAG_PARSING_USERDATA, emittedText); } } @@ -599,12 +624,12 @@ class AudioStreamController extends BaseStreamController { track.levelCodec = track.codec; track.id = 'audio'; - this.hls.trigger(Event.BUFFER_CODECS, tracks); + this.hls.trigger(Events.BUFFER_CODECS, tracks); this.log(`Audio, container:${track.container}, codecs[level/parsed]=[${track.levelCodec}/${track.codec}]`); const initSegment = track.initSegment; if (initSegment) { - const segment: BufferAppendingEventPayload = { type: 'audio', data: initSegment, frag, chunkMeta }; - this.hls.trigger(Event.BUFFER_APPENDING, segment); + const segment: BufferAppendingData = { type: 'audio', data: initSegment, frag, chunkMeta }; + this.hls.trigger(Events.BUFFER_APPENDING, segment); } // trigger handler right now this.tick(); @@ -638,14 +663,14 @@ class AudioStreamController extends BaseStreamController { const { hls, media, trackId } = this; if (media) { this.warn('Switching audio track : flushing all audio'); - hls.trigger(Event.BUFFER_FLUSHING, { + hls.trigger(Events.BUFFER_FLUSHING, { startOffset: 0, endOffset: Number.POSITIVE_INFINITY, type: 'audio' }); } this.audioSwitch = false; - hls.trigger(Event.AUDIO_TRACK_SWITCHED, { id: trackId }); + hls.trigger(Events.AUDIO_TRACK_SWITCHED, { id: trackId }); } } export default AudioStreamController; diff --git a/src/controller/audio-track-controller.ts b/src/controller/audio-track-controller.ts index 6bd96d3baf0..3df523b49f6 100644 --- a/src/controller/audio-track-controller.ts +++ b/src/controller/audio-track-controller.ts @@ -1,17 +1,18 @@ -import Event from '../events'; +import { Events } from '../events'; import { logger } from '../utils/logger'; import { ErrorTypes, ErrorDetails } from '../errors'; import { computeReloadInterval } from './level-helper'; -import EventHandler from '../event-handler'; import { MediaPlaylist } from '../types/media-playlist'; import { TrackSwitchedData, - TrackLoadedData, ManifestParsedData, - LevelLoadedData, - AudioTracksUpdated, - ErrorData + AudioTracksUpdatedData, + ErrorData, + LevelLoadingData, + AudioTrackLoadedData } from '../types/events'; +import { NetworkComponentAPI } from '../types/component-api'; +import Hls from '../hls'; /** * @class AudioTrackController @@ -34,14 +35,14 @@ import { * @fires ERROR * */ -class AudioTrackController extends EventHandler { +class AudioTrackController implements NetworkComponentAPI { /** * @private * If should select tracks according to default track attribute * @member {boolean} _selectDefaultTrack */ private _selectDefaultTrack: boolean = true; - + private hls: Hls; private _trackId: number = -1; private canLoad: boolean = false; @@ -65,21 +66,35 @@ class AudioTrackController extends EventHandler { */ public audioGroupId: string | null = null; - constructor (hls) { - super(hls, - Event.MANIFEST_LOADING, - Event.MANIFEST_PARSED, - Event.AUDIO_TRACK_LOADED, - Event.AUDIO_TRACK_SWITCHED, - Event.LEVEL_LOADING, - Event.ERROR - ); - + constructor (hls: Hls) { + this.hls = hls; this.tracks = []; this.trackIdBlacklist = Object.create(null); + this._registerListeners(); + } + + private _registerListeners () { + const { hls } = this; + hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); + hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this); + hls.on(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this); + hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this); + hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this); + hls.on(Events.ERROR, this.onError, this); + } + + private _unregisterListeners () { + const { hls } = this; + hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); + hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this); + hls.off(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this); + hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this); + hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this); + hls.off(Events.ERROR, this.onError, this); } - protected onHandlerDestroying (): void { + public destroy () { + this._unregisterListeners(); this.clearTimer(); } @@ -97,10 +112,10 @@ class AudioTrackController extends EventHandler { * * Trigger AUDIO_TRACKS_UPDATED event. */ - protected onManifestParsed (data: ManifestParsedData): void { + protected onManifestParsed (event: Events.MANIFEST_PARSED, data: ManifestParsedData): void { const tracks = this.tracks = data.audioTracks || []; - const audioTracksUpdated: AudioTracksUpdated = { audioTracks: tracks }; - this.hls.trigger(Event.AUDIO_TRACKS_UPDATED, audioTracksUpdated); + const audioTracksUpdated: AudioTracksUpdatedData = { audioTracks: tracks }; + this.hls.trigger(Events.AUDIO_TRACKS_UPDATED, audioTracksUpdated); } /** @@ -110,7 +125,7 @@ class AudioTrackController extends EventHandler { * * @param {*} data */ - protected onAudioTrackLoaded (data: TrackLoadedData): void { + protected onAudioTrackLoaded (event: Events.AUDIO_TRACK_LOADED, data: AudioTrackLoadedData): void { const { id, details } = data; const currentTrack = this.tracks[id]; const curDetails = currentTrack.details; @@ -163,7 +178,7 @@ class AudioTrackController extends EventHandler { * * Quality-levels should update to that group ID in this case. */ - protected onAudioTrackSwitched (data: TrackSwitchedData): void { + protected onAudioTrackSwitched (event: Events.AUDIO_TRACK_SWITCHED, data: TrackSwitchedData): void { const audioGroupId = this.tracks[data.id].groupId; if (audioGroupId && (this.audioGroupId !== audioGroupId)) { this.audioGroupId = audioGroupId; @@ -177,7 +192,7 @@ class AudioTrackController extends EventHandler { * If group-ID got update, we re-select the appropriate audio-track with this group-ID matching the currently * selected one (based on NAME property). */ - protected onLevelLoading (data: LevelLoadedData): void { + protected onLevelLoading (event: Events.LEVEL_LOADING, data: LevelLoadingData): void { const levelInfo = this.hls.levels[data.level]; if (!levelInfo.audioGroupIds) { @@ -191,7 +206,7 @@ class AudioTrackController extends EventHandler { } } - protected onError (data: ErrorData): void { + protected onError (event: Events.ERROR, data: ErrorData): void { // Only handle network errors if (data.type !== ErrorTypes.NETWORK_ERROR) { return; @@ -247,7 +262,7 @@ class AudioTrackController extends EventHandler { this._trackId = newId; const { url, type, id } = audioTrack; - this.hls.trigger(Event.AUDIO_TRACK_SWITCHING, { id, type, url }); + this.hls.trigger(Events.AUDIO_TRACK_SWITCHING, { id, type, url }); this._loadTrackDetailsIfNeeded(audioTrack); } @@ -300,7 +315,7 @@ class AudioTrackController extends EventHandler { if (!trackFound) { logger.error(`[audio-track-controller]: No track found for running audio group-ID: ${this.audioGroupId}`); - this.hls.trigger(Event.ERROR, { + this.hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.AUDIO_TRACK_LOAD_ERROR, fatal: true @@ -319,7 +334,7 @@ class AudioTrackController extends EventHandler { const { url, id } = audioTrack; // track not retrieved yet, or live playlist we need to (re)load it logger.log(`[audio-track-controller]: loading audio-track playlist for id: ${id}`); - this.hls.trigger(Event.AUDIO_TRACK_LOADING, { url, id }); + this.hls.trigger(Events.AUDIO_TRACK_LOADING, { url, id }); } } diff --git a/src/controller/base-stream-controller.ts b/src/controller/base-stream-controller.ts index 3b01ccfe1fe..21c493d179d 100644 --- a/src/controller/base-stream-controller.ts +++ b/src/controller/base-stream-controller.ts @@ -2,7 +2,7 @@ import TaskLoop from '../task-loop'; import { FragmentState, FragmentTracker } from './fragment-tracker'; import { BufferHelper } from '../utils/buffer-helper'; import { logger } from '../utils/logger'; -import Event from '../events'; +import { Events } from '../events'; import { ErrorDetails } from '../errors'; import * as LevelHelper from './level-helper'; import { ChunkMetadata } from '../types/transmuxer'; @@ -13,9 +13,10 @@ import TransmuxerInterface from '../demux/transmuxer-interface'; import Fragment from '../loader/fragment'; import FragmentLoader, { FragLoadSuccessResult, FragmentLoadProgressCallback } from '../loader/fragment-loader'; import LevelDetails from '../loader/level-details'; -import { BufferAppendingEventPayload } from '../types/events'; +import { BufferAppendingData } from '../types/events'; import { Level } from '../types/level'; import { RemuxedTrack } from '../types/remuxer'; +import Hls from '../hls'; export const State = { STOPPED: 'STOPPED', @@ -34,6 +35,8 @@ export const State = { }; export default class BaseStreamController extends TaskLoop { + protected hls: Hls; + protected fragPrevious: Fragment | null = null; protected fragCurrent: Fragment | null = null; protected fragmentTracker!: FragmentTracker; @@ -55,12 +58,18 @@ export default class BaseStreamController extends TaskLoop { protected readonly logPrefix: string = ''; + constructor (hls: Hls) { + super(); + this.hls = hls; + } + protected doTick () { this.onTickEnd(); } protected onTickEnd () {} + // eslint-disable-next-line @typescript-eslint/no-unused-vars public startLoad (startPosition: number) : void {} public stopLoad () { @@ -179,7 +188,7 @@ export default class BaseStreamController extends TaskLoop { // For compatibility, emit the FRAG_LOADED with the same signature const compatibilityEventData: any = data; compatibilityEventData.frag = frag; - this.hls.trigger(Event.FRAG_LOADED, compatibilityEventData); + this.hls.trigger(Events.FRAG_LOADED, compatibilityEventData); // Pass through the whole payload; controllers not implementing progressive loading receive data from this callback this._handleFragmentLoadComplete(frag, data.payload); }); @@ -204,7 +213,11 @@ export default class BaseStreamController extends TaskLoop { stats.parsing.start = stats.buffering.start = self.performance.now(); stats.parsing.end = stats.buffering.end = self.performance.now(); // TODO: set id from calling class - hls.trigger(Event.FRAG_BUFFERED, { stats, frag: fragCurrent, id: frag.type }); + + // Silence FRAG_BUFFERED event if fragCurrent is null + if (fragCurrent) { + hls.trigger(Events.FRAG_BUFFERED, { stats, frag: fragCurrent, id: frag.type }); + } this.tick(); }); } @@ -217,6 +230,7 @@ export default class BaseStreamController extends TaskLoop { return frag.level !== fragCurrent.level || frag.sn !== fragCurrent.sn; } + // eslint-disable-next-line @typescript-eslint/no-unused-vars protected _handleFragmentLoadComplete (frag: Fragment, payload: ArrayBuffer | Uint8Array) { const { transmuxer } = this; if (!transmuxer) { @@ -227,11 +241,12 @@ export default class BaseStreamController extends TaskLoop { transmuxer.flush(chunkMeta); } + // eslint-disable-next-line @typescript-eslint/no-unused-vars protected _handleFragmentLoadProgress (frag: Fragment, payload: ArrayBuffer | Uint8Array) {} protected _doFragLoad (frag: Fragment, progressCallback?: FragmentLoadProgressCallback) { this.state = State.FRAG_LOADING; - this.hls.trigger(Event.FRAG_LOADING, { frag }); + this.hls.trigger(Events.FRAG_LOADING, { frag }); const errorHandler = (e) => { const errorData = e ? e.data : null; @@ -239,7 +254,7 @@ export default class BaseStreamController extends TaskLoop { this.handleFragLoadAborted(frag); return; } - this.hls.trigger(Event.ERROR, errorData); + this.hls.trigger(Events.ERROR, errorData); }; const level = (this.levels as Array)[frag.level]; @@ -280,10 +295,10 @@ export default class BaseStreamController extends TaskLoop { this.updateLevelTiming(frag, level); this.state = State.PARSED; - this.hls.trigger(Event.FRAG_PARSED, { frag }); + this.hls.trigger(Events.FRAG_PARSED, { frag }); } - protected getCurrentContext (chunkMeta: ChunkMetadata) : { frag: Fragment, level: any } | null { + protected getCurrentContext (chunkMeta: ChunkMetadata) : { frag: Fragment, level: Level } | null { const { fragCurrent, levels } = this; const { level, sn } = chunkMeta; if (!levels || !levels[level]) { @@ -320,8 +335,8 @@ export default class BaseStreamController extends TaskLoop { return; } - const segment: BufferAppendingEventPayload = { type: data.type, data: buffer, frag, chunkMeta }; - this.hls.trigger(Event.BUFFER_APPENDING, segment); + const segment: BufferAppendingData = { type: data.type, data: buffer, frag, chunkMeta }; + this.hls.trigger(Events.BUFFER_APPENDING, segment); this.tick(); } @@ -455,7 +470,7 @@ export default class BaseStreamController extends TaskLoop { } } else if (frag.backtracked) { // Only backtrack a max of 1 consecutive fragment to prevent sliding back too far when little or no frags start with keyframes - if (nextFrag && nextFrag.backtracked) { + if (nextFrag?.backtracked) { this.warn(`Already backtracked from fragment ${nextFrag.sn}, will not backtrack to fragment ${frag.sn}. Loading fragment ${nextFrag.sn}`); frag = nextFrag; } else { @@ -486,7 +501,7 @@ export default class BaseStreamController extends TaskLoop { const liveSyncPosition = this._liveSyncPosition = this.computeLivePosition(start, targetDuration, totalDuration); this.log(`Buffer end: ${bufferEnd.toFixed(3)} is located too far from the end of live sliding playlist, reset currentTime to : ${liveSyncPosition.toFixed(3)}`); this.nextLoadPosition = liveSyncPosition; - if (media && media.readyState && media.duration > liveSyncPosition) { + if (media?.readyState && media.duration > liveSyncPosition) { media.currentTime = liveSyncPosition; } return liveSyncPosition; @@ -584,13 +599,13 @@ export default class BaseStreamController extends TaskLoop { this.log(`Fragment ${frag.sn} of level ${frag.level} was aborted, flushing transmuxer & resetting nextLoadPosition to ${this.nextLoadPosition}`); } - private updateLevelTiming (frag: Fragment, currentLevel) { + private updateLevelTiming (frag: Fragment, currentLevel: Level) { const { details } = currentLevel; Object.keys(frag.elementaryStreams).forEach(type => { const info = frag.elementaryStreams[type]; if (info) { const drift = LevelHelper.updateFragPTSDTS(details, frag, info.startPTS, info.endPTS, info.startDTS, info.endDTS); - this.hls.trigger(Event.LEVEL_PTS_UPDATED, { + this.hls.trigger(Events.LEVEL_PTS_UPDATED, { details, level: currentLevel, drift, diff --git a/src/controller/buffer-controller.ts b/src/controller/buffer-controller.ts index 0f6464c6c20..5eaa43f44bf 100644 --- a/src/controller/buffer-controller.ts +++ b/src/controller/buffer-controller.ts @@ -2,12 +2,11 @@ * Buffer Controller */ -import Events from '../events'; -import EventHandler from '../event-handler'; +import { Events } from '../events'; import { logger } from '../utils/logger'; import { ErrorDetails, ErrorTypes } from '../errors'; import { getMediaSource } from '../utils/mediasource-helper'; -import Fragment, { ElementaryStreamTypes } from '../loader/fragment'; +import { ElementaryStreamTypes } from '../loader/fragment'; import { TrackSet } from '../types/track'; import BufferOperationQueue from './buffer-operation-queue'; import { @@ -16,11 +15,13 @@ import { SourceBufferName, SourceBufferListeners } from '../types/buffer'; -import { LevelUpdatedData, BufferAppendingEventPayload } from '../types/events'; +import { LevelUpdatedData, BufferAppendingData, MediaAttachingData, ManifestParsedData, BufferCodecsData, LevelPTSUpdatedData, BufferEOSData, BufferFlushingData, FragParsedData } from '../types/events'; +import { ComponentAPI } from '../types/component-api'; +import Hls from '../hls'; const MediaSource = getMediaSource(); -export default class BufferController extends EventHandler { +export default class BufferController implements ComponentAPI { // the value that we have set mediasource.duration to // (the actual duration may be tweaked slighly by the browser) private _msDuration: number | null = null; @@ -35,6 +36,8 @@ export default class BufferController extends EventHandler { // References to event listeners for each SourceBuffer, so that they can be referenced for event removal private listeners!: SourceBufferListeners; + private hls: Hls; + // The number of BUFFER_CODEC events received before any sourceBuffers are created public bufferCodecEventsExpected: number = 0; @@ -54,22 +57,44 @@ export default class BufferController extends EventHandler { public pendingTracks: TrackSet = {}; public sourceBuffer!: SourceBuffers; - constructor (hls: any) { - super(hls, - Events.MEDIA_ATTACHING, - Events.MEDIA_DETACHING, - Events.MANIFEST_PARSED, - Events.BUFFER_RESET, - Events.BUFFER_APPENDING, - Events.BUFFER_CODECS, - Events.BUFFER_EOS, - Events.BUFFER_FLUSHING, - Events.LEVEL_PTS_UPDATED, - Events.LEVEL_UPDATED, - Events.FRAG_PARSED - ); + constructor (hls: Hls) { this.hls = hls; this._initSourceBuffer(); + this.registerListeners(); + } + + public destroy () { + this.unregisterListeners(); + } + + protected registerListeners () { + const { hls } = this; + hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); + hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this); + hls.on(Events.BUFFER_RESET, this.onBufferReset, this); + hls.on(Events.BUFFER_APPENDING, this.onBufferAppending, this); + hls.on(Events.BUFFER_CODECS, this.onBufferCodecs, this); + hls.on(Events.BUFFER_EOS, this.onBufferEos, this); + hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this); + hls.on(Events.LEVEL_PTS_UPDATED, this.onLevelPtsUpdated, this); + hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this); + hls.on(Events.FRAG_PARSED, this.onFragParsed, this); + } + + protected unregisterListeners () { + const { hls } = this; + hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); + hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this); + hls.off(Events.BUFFER_RESET, this.onBufferReset, this); + hls.off(Events.BUFFER_APPENDING, this.onBufferAppending, this); + hls.off(Events.BUFFER_CODECS, this.onBufferCodecs, this); + hls.off(Events.BUFFER_EOS, this.onBufferEos, this); + hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this); + hls.off(Events.LEVEL_PTS_UPDATED, this.onLevelPtsUpdated, this); + hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this); + hls.off(Events.FRAG_PARSED, this.onFragParsed, this); } private _initSourceBuffer () { @@ -82,7 +107,7 @@ export default class BufferController extends EventHandler { }; } - onManifestParsed (data: { altAudio: boolean }) { + protected onManifestParsed (event: Events.MANIFEST_PARSED, data: ManifestParsedData) { // in case of alt audio 2 BUFFER_CODECS events will be triggered, one per stream controller // sourcebuffers will be created all at once when the expected nb of tracks will be reached // in case alt audio is not used, only one BUFFER_CODEC event will be fired from main stream controller @@ -91,7 +116,7 @@ export default class BufferController extends EventHandler { logger.log(`${this.bufferCodecEventsExpected} bufferCodec event(s) expected`); } - onMediaAttaching (data: { media: HTMLMediaElement }) { + protected onMediaAttaching (event: Events.MEDIA_ATTACHING, data: MediaAttachingData) { const media = this.media = data.media; if (media && MediaSource) { const ms = this.mediaSource = new MediaSource(); @@ -106,7 +131,7 @@ export default class BufferController extends EventHandler { } } - onMediaDetaching () { + protected onMediaDetaching () { logger.log('media source detaching'); const { media, mediaSource, _objectUrl } = this; if (mediaSource) { @@ -155,7 +180,7 @@ export default class BufferController extends EventHandler { this.hls.trigger(Events.MEDIA_DETACHED); } - onBufferReset () { + protected onBufferReset () { const sourceBuffer = this.sourceBuffer; this.getSourceBufferTypes().forEach(type => { const sb = sourceBuffer[type]; @@ -176,15 +201,15 @@ export default class BufferController extends EventHandler { this._initSourceBuffer(); } - onBufferCodecs (tracks: TrackSet) { + protected onBufferCodecs (event: Events.BUFFER_CODECS, data: BufferCodecsData) { // if source buffer(s) not created yet, appended buffer tracks in this.pendingTracks // if sourcebuffers already created, do nothing ... if (Object.keys(this.sourceBuffer).length) { return; } - Object.keys(tracks).forEach(trackName => { - this.pendingTracks[trackName] = tracks[trackName]; + Object.keys(data).forEach(trackName => { + this.pendingTracks[trackName] = data[trackName]; }); this.bufferCodecEventsExpected = Math.max(this.bufferCodecEventsExpected - 1, 0); @@ -193,7 +218,7 @@ export default class BufferController extends EventHandler { } } - onBufferAppending (eventData: BufferAppendingEventPayload) { + protected onBufferAppending (event: Events.BUFFER_APPENDING, eventData: BufferAppendingData) { const { hls, operationQueue } = this; const { data, type, frag, chunkMeta } = eventData; const chunkStats = chunkMeta.buffering[type]; @@ -231,7 +256,7 @@ export default class BufferController extends EventHandler { const event = { type: ErrorTypes.MEDIA_ERROR, parent: frag.type, - details: '', + details: ErrorDetails.BUFFER_APPEND_ERROR, err, fatal: false }; @@ -258,7 +283,7 @@ export default class BufferController extends EventHandler { operationQueue.append(operation, type as SourceBufferName); } - onBufferFlushing (data: { startOffset: number, endOffset: number, type?: SourceBufferName }) { + protected onBufferFlushing (event: Events.BUFFER_FLUSHING, data: BufferFlushingData) { const { operationQueue } = this; const flushOperation = (type): BufferOperation => ({ execute: this.removeExecutor.bind(this, type, data.startOffset, data.endOffset), @@ -278,7 +303,7 @@ export default class BufferController extends EventHandler { } } - onFragParsed (data: { frag: Fragment }) { + protected onFragParsed (event: Events.FRAG_PARSED, data: FragParsedData) { const { frag } = data; const buffersAppendedTo: Array = []; @@ -305,7 +330,7 @@ export default class BufferController extends EventHandler { // on BUFFER_EOS mark matching sourcebuffer(s) as ended and trigger checkEos() // an undefined data.type will mark all buffers as EOS. - onBufferEos (data: { type?: SourceBufferName }) { + protected onBufferEos (event: Events.BUFFER_EOS, data: BufferEOSData) { for (const type in this.sourceBuffer) { if (!data.type || data.type === type) { const sb = this.sourceBuffer[type as SourceBufferName]; @@ -330,7 +355,7 @@ export default class BufferController extends EventHandler { this.blockBuffers(endStream); } - onLevelUpdated ({ details }: LevelUpdatedData) { + protected onLevelUpdated (event: Events.LEVEL_UPDATED, { details }: LevelUpdatedData) { if (!details.fragments.length) { return; } @@ -352,7 +377,7 @@ export default class BufferController extends EventHandler { // `SourceBuffer.abort()` and adjusting `SourceBuffer.timestampOffset` if `SourceBuffer.updating` is false or awaiting `updateend` // event if SB is in updating state. // More info here: https://github.com/video-dev/hls.js/issues/332#issuecomment-257986486 - onLevelPtsUpdated (data: { type: SourceBufferName, start: number }) { + protected onLevelPtsUpdated (event: Events.LEVEL_PTS_UPDATED, data: LevelPTSUpdatedData) { const { operationQueue, sourceBuffer, tracks } = this; const type = data.type; const audioTrack = tracks.audio; @@ -409,7 +434,7 @@ export default class BufferController extends EventHandler { // time will lead to playback freezing) // credits for level target duration - https://github.com/videojs/http-streaming/blob/3132933b6aa99ddefab29c10447624efd6fd6e52/src/segment-loader.js#L91 logger.log(`[buffer-controller]: Enqueueing operation to flush ${type} back buffer`); - this.onBufferFlushing({ + this.onBufferFlushing(Events.BUFFER_FLUSHING, { startOffset: 0, endOffset: targetBackBufferPosition, type @@ -424,7 +449,7 @@ export default class BufferController extends EventHandler { * 'liveDurationInfinity` is set to `true` * More details: https://github.com/video-dev/hls.js/issues/355 */ - updateMediaElementDuration (levelDuration: number) { + private updateMediaElementDuration (levelDuration: number) { if (!this.media || !this.mediaSource || this.mediaSource.readyState !== 'open') { return; } @@ -451,7 +476,7 @@ export default class BufferController extends EventHandler { } } - private checkPendingTracks () { + protected checkPendingTracks () { const { bufferCodecEventsExpected, operationQueue, pendingTracks } = this; // Check if we've received all of the expected bufferCodec events. When none remain, create all the sourceBuffers at once. @@ -470,7 +495,7 @@ export default class BufferController extends EventHandler { } } - private createSourceBuffers (tracks: TrackSet) { + protected createSourceBuffers (tracks: TrackSet) { const { sourceBuffer, mediaSource } = this; if (!mediaSource) { throw Error('createSourceBuffers called when mediaSource was null'); @@ -504,7 +529,7 @@ export default class BufferController extends EventHandler { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_ADD_CODEC_ERROR, fatal: false, - err, + error: err, mimeType: mimeType }); } @@ -517,7 +542,12 @@ export default class BufferController extends EventHandler { private _onMediaSourceOpen = () => { const { hls, media, mediaSource } = this; logger.log('media source opened'); - hls.trigger(Events.MEDIA_ATTACHED, { media }); + if (media) { + hls.trigger(Events.MEDIA_ATTACHED, { media }); + } else { + logger.log('[buffer-controller]: Media source opened, and no media was attached'); + } + if (mediaSource) { // once received, don't listen anymore to sourceopen event mediaSource.removeEventListener('sourceopen', this._onMediaSourceOpen); diff --git a/src/controller/cap-level-controller.ts b/src/controller/cap-level-controller.ts index b7440e15403..791284ff6d7 100644 --- a/src/controller/cap-level-controller.ts +++ b/src/controller/cap-level-controller.ts @@ -2,13 +2,14 @@ * cap stream level to media size dimension controller */ -import Event from '../events'; -import EventHandler from '../event-handler'; +import { Events } from '../events'; import { Level } from '../types/level'; import { ManifestParsedData, BufferCodecsData, MediaAttachingData, FPSDropLevelCappingData, LevelsUpdatedData } from '../types/events'; import StreamController from './stream-controller'; +import { ComponentAPI } from '../types/component-api'; +import Hls from '../hls'; -class CapLevelController extends EventHandler { +class CapLevelController implements ComponentAPI { public autoLevelCapping: number; public firstLevel: number; public levels: Array; @@ -16,48 +17,65 @@ class CapLevelController extends EventHandler { public restrictedLevels: Array; public timer: number | undefined; + private hls: Hls; private streamController?: StreamController; - constructor (hls) { - super(hls, - Event.FPS_DROP_LEVEL_CAPPING, - Event.MEDIA_ATTACHING, - Event.MANIFEST_PARSED, - Event.LEVELS_UPDATED, - Event.BUFFER_CODECS, - Event.MEDIA_DETACHING); - + constructor (hls: Hls) { + this.hls = hls; this.autoLevelCapping = Number.POSITIVE_INFINITY; this.levels = []; this.firstLevel = -1; this.media = null; this.restrictedLevels = []; this.timer = undefined; + + this.registerListeners(); } - setStreamController (streamController: StreamController) { + public setStreamController (streamController: StreamController) { this.streamController = streamController; } - destroy () { + public destroy () { + this.unregisterListener(); if (this.hls.config.capLevelToPlayerSize) { this.media = null; this.stopCapping(); } } - onFpsDropLevelCapping (data: FPSDropLevelCappingData) { + protected registerListeners () { + const { hls } = this; + hls.on(Events.FPS_DROP_LEVEL_CAPPING, this.onFpsDropLevelCapping, this); + hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); + hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this); + hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this); + hls.on(Events.BUFFER_CODECS, this.onBufferCodecs, this); + hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + } + + protected unregisterListener () { + const { hls } = this; + hls.off(Events.FPS_DROP_LEVEL_CAPPING, this.onFpsDropLevelCapping, this); + hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); + hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this); + hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this); + hls.off(Events.BUFFER_CODECS, this.onBufferCodecs, this); + hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + } + + protected onFpsDropLevelCapping (event: Events.FPS_DROP_LEVEL_CAPPING, data: FPSDropLevelCappingData) { // Don't add a restricted level more than once if (CapLevelController.isLevelAllowed(data.droppedLevel, this.restrictedLevels)) { this.restrictedLevels.push(data.droppedLevel); } } - onMediaAttaching (data: MediaAttachingData) { + protected onMediaAttaching (event: Events.MEDIA_ATTACHING, data: MediaAttachingData) { this.media = data.media instanceof HTMLVideoElement ? data.media : null; } - onManifestParsed (data: ManifestParsedData) { + protected onManifestParsed (event: Events.MANIFEST_PARSED, data: ManifestParsedData) { const hls = this.hls; this.restrictedLevels = []; this.levels = data.levels; @@ -70,7 +88,7 @@ class CapLevelController extends EventHandler { // Only activate capping when playing a video stream; otherwise, multi-bitrate audio-only streams will be restricted // to the first level - onBufferCodecs (data: BufferCodecsData) { + protected onBufferCodecs (event: Events.BUFFER_CODECS, data: BufferCodecsData) { const hls = this.hls; if (hls.config.capLevelToPlayerSize && data.video) { // If the manifest did not signal a video codec capping has been deferred until we're certain video is present @@ -78,11 +96,11 @@ class CapLevelController extends EventHandler { } } - onLevelsUpdated (data: LevelsUpdatedData) { + protected onLevelsUpdated (event: Events.LEVELS_UPDATED, data: LevelsUpdatedData) { this.levels = data.levels; } - onMediaDetaching () { + protected onMediaDetaching () { this.stopCapping(); } diff --git a/src/controller/eme-controller.ts b/src/controller/eme-controller.ts index 3ef8c86e4ce..551ec8b918e 100644 --- a/src/controller/eme-controller.ts +++ b/src/controller/eme-controller.ts @@ -3,14 +3,15 @@ * * DRM support for Hls.js */ - -import EventHandler from '../event-handler'; -import Event from '../events'; +import { Events } from '../events'; import { ErrorTypes, ErrorDetails } from '../errors'; import { logger } from '../utils/logger'; import { EMEControllerConfig } from '../config'; import { KeySystems, MediaKeyFunc } from '../utils/mediakeys-helper'; +import Hls from '../hls'; +import { ComponentAPI } from '../types/component-api'; +import { MediaAttachedData, ManifestParsedData } from '../types/events'; const MAX_LICENSE_REQUEST_FAILURES = 3; @@ -79,7 +80,8 @@ interface MediaKeysListItem { * @class * @constructor */ -class EMEController extends EventHandler { +class EMEController implements ComponentAPI { + private hls: Hls; private _widevineLicenseUrl?: string; private _licenseXhrSetup?: (xhr: XMLHttpRequest, url: string) => void; private _emeEnabled: boolean; @@ -95,18 +97,32 @@ class EMEController extends EventHandler { * @constructs * @param {Hls} hls Our Hls.js instance */ - constructor (hls) { - super(hls, - Event.MEDIA_ATTACHED, - Event.MEDIA_DETACHED, - Event.MANIFEST_PARSED - ); + constructor (hls: Hls) { + this.hls = hls; this._config = hls.config; this._widevineLicenseUrl = this._config.widevineLicenseUrl; this._licenseXhrSetup = this._config.licenseXhrSetup; this._emeEnabled = this._config.emeEnabled; this._requestMediaKeySystemAccess = this._config.requestMediaKeySystemAccessFunc; + + this._registerListeners(); + } + + public destroy () { + this._unregisterListeners(); + } + + private _registerListeners () { + this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this); + this.hls.on(Events.MEDIA_DETACHED, this.onMediaDetached, this); + this.hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this); + } + + private _unregisterListeners () { + this.hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this); + this.hls.off(Events.MEDIA_DETACHED, this.onMediaDetached, this); + this.hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this); } /** @@ -258,7 +274,7 @@ class EMEController extends EventHandler { const keysListItem = this._mediaKeysList[0]; if (!keysListItem || !keysListItem.mediaKeys) { logger.error('Fatal: Media is encrypted but no CDM access or no keys have been obtained yet'); - this.hls.trigger(Event.ERROR, { + this.hls.trigger(Events.ERROR, { type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_NO_KEYS, fatal: true @@ -281,7 +297,7 @@ class EMEController extends EventHandler { const keysListItem = this._mediaKeysList[0]; if (!keysListItem) { logger.error('Fatal: Media is encrypted but not any key-system access has been obtained yet'); - this.hls.trigger(Event.ERROR, { + this.hls.trigger(Events.ERROR, { type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_NO_ACCESS, fatal: true @@ -297,7 +313,7 @@ class EMEController extends EventHandler { const keySession = keysListItem.mediaKeysSession; if (!keySession) { logger.error('Fatal: Media is encrypted but no key-session existing'); - this.hls.trigger(Event.ERROR, { + this.hls.trigger(Events.ERROR, { type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_NO_SESSION, fatal: true @@ -308,7 +324,7 @@ class EMEController extends EventHandler { // initData is null if the media is not CORS-same-origin if (!initData) { logger.warn('Fatal: initData required for generating a key session is null'); - this.hls.trigger(Event.ERROR, { + this.hls.trigger(Events.ERROR, { type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_NO_INIT_DATA, fatal: true @@ -325,7 +341,7 @@ class EMEController extends EventHandler { }) .catch((err) => { logger.error('Error generating key-session request:', err); - this.hls.trigger(Event.ERROR, { + this.hls.trigger(Events.ERROR, { type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_NO_SESSION, fatal: false @@ -393,7 +409,7 @@ class EMEController extends EventHandler { logger.error(`License Request XHR failed (${url}). Status: ${xhr.status} (${xhr.statusText})`); this._requestLicenseFailureCount++; if (this._requestLicenseFailureCount > MAX_LICENSE_REQUEST_FAILURES) { - this.hls.trigger(Event.ERROR, { + this.hls.trigger(Events.ERROR, { type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED, fatal: true @@ -459,7 +475,7 @@ class EMEController extends EventHandler { const keysListItem = this._mediaKeysList[0]; if (!keysListItem) { logger.error('Fatal error: Media is encrypted but no key-system access has been obtained yet'); - this.hls.trigger(Event.ERROR, { + this.hls.trigger(Events.ERROR, { type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_NO_ACCESS, fatal: true @@ -475,7 +491,7 @@ class EMEController extends EventHandler { xhr.send(challenge); } catch (e) { logger.error(`Failure requesting DRM license: ${e}`); - this.hls.trigger(Event.ERROR, { + this.hls.trigger(Events.ERROR, { type: ErrorTypes.KEY_SYSTEM_ERROR, details: ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED, fatal: true @@ -483,7 +499,7 @@ class EMEController extends EventHandler { } } - onMediaAttached (data: { media: HTMLMediaElement; }) { + onMediaAttached (event: Events.MEDIA_ATTACHED, data: MediaAttachedData) { if (!this._emeEnabled) { return; } @@ -503,14 +519,17 @@ class EMEController extends EventHandler { } } - // TODO: Use manifest types here when they are defined - onManifestParsed (data: any) { + onManifestParsed (event: Events.MANIFEST_PARSED, data: ManifestParsedData) { if (!this._emeEnabled) { return; } - const audioCodecs = data.levels.map((level) => level.audioCodec); - const videoCodecs = data.levels.map((level) => level.videoCodec); + const audioCodecs = data.levels.map((level) => level.audioCodec).filter( + (audioCodec: string | undefined): audioCodec is string => !!audioCodec + ); + const videoCodecs = data.levels.map((level) => level.videoCodec).filter( + (videoCodec: string | undefined): videoCodec is string => !!videoCodec + ); this._attemptKeySystemAccess(KeySystems.WIDEVINE, audioCodecs, videoCodecs); } diff --git a/src/controller/fps-controller.js b/src/controller/fps-controller.ts similarity index 50% rename from src/controller/fps-controller.js rename to src/controller/fps-controller.ts index bf1827baa21..e815d28f7d3 100644 --- a/src/controller/fps-controller.js +++ b/src/controller/fps-controller.ts @@ -2,15 +2,42 @@ * FPS Controller */ -import Event from '../events'; -import EventHandler from '../event-handler'; +import { Events } from '../events'; import { logger } from '../utils/logger'; +import { ComponentAPI } from '../types/component-api'; +import Hls from '../hls'; +import { MediaAttachingData } from '../types/events'; +import StreamController from './stream-controller'; const { performance } = self; -class FPSController extends EventHandler { - constructor (hls) { - super(hls, Event.MEDIA_ATTACHING); +class FPSController implements ComponentAPI { + private hls: Hls; + private isVideoPlaybackQualityAvailable: boolean = false; + private timer?: number; + private video: HTMLVideoElement | null = null; + private lastTime: any; + private lastDroppedFrames: number = 0; + private lastDecodedFrames: number = 0; + // stream controller must be provided as a dependency! + private streamController!: StreamController; + + constructor (hls: Hls) { + this.hls = hls; + + this.registerListeners(); + } + + public setStreamController (streamController: StreamController) { + this.streamController = streamController; + } + + protected registerListeners () { + this.hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); + } + + protected unregisterListeners () { + this.hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching); } destroy () { @@ -18,23 +45,25 @@ class FPSController extends EventHandler { clearInterval(this.timer); } + this.unregisterListeners(); this.isVideoPlaybackQualityAvailable = false; } - onMediaAttaching (data) { + protected onMediaAttaching (event: Events.MEDIA_ATTACHING, data: MediaAttachingData) { const config = this.hls.config; if (config.capLevelOnFPSDrop) { - const video = this.video = data.media instanceof self.HTMLVideoElement ? data.media : null; - if (typeof video.getVideoPlaybackQuality === 'function') { + const video = data.media instanceof self.HTMLVideoElement ? data.media : null; + this.video = video; + if (video && typeof video.getVideoPlaybackQuality === 'function') { this.isVideoPlaybackQualityAvailable = true; } - clearInterval(this.timer); + self.clearInterval(this.timer); this.timer = self.setTimeout(this.checkFPSInterval.bind(this), config.fpsDroppedMonitoringPeriod); } } - checkFPS (video, decodedFrames, droppedFrames) { + checkFPS (video: HTMLVideoElement, decodedFrames: number, droppedFrames: number) { const currentTime = performance.now(); if (decodedFrames) { if (this.lastTime) { @@ -43,7 +72,7 @@ class FPSController extends EventHandler { const currentDecoded = decodedFrames - this.lastDecodedFrames; const droppedFPS = 1000 * currentDropped / currentPeriod; const hls = this.hls; - hls.trigger(Event.FPS_DROP, { currentDropped: currentDropped, currentDecoded: currentDecoded, totalDroppedFrames: droppedFrames }); + hls.trigger(Events.FPS_DROP, { currentDropped: currentDropped, currentDecoded: currentDecoded, totalDroppedFrames: droppedFrames }); if (droppedFPS > 0) { // logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod)); if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) { @@ -51,9 +80,9 @@ class FPSController extends EventHandler { logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel); if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) { currentLevel = currentLevel - 1; - hls.trigger(Event.FPS_DROP_LEVEL_CAPPING, { level: currentLevel, droppedLevel: hls.currentLevel }); + hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, { level: currentLevel, droppedLevel: hls.currentLevel }); hls.autoLevelCapping = currentLevel; - hls.streamController.nextLevelSwitch(); + this.streamController.nextLevelSwitch(); } } } @@ -71,7 +100,8 @@ class FPSController extends EventHandler { const videoPlaybackQuality = video.getVideoPlaybackQuality(); this.checkFPS(video, videoPlaybackQuality.totalVideoFrames, videoPlaybackQuality.droppedVideoFrames); } else { - this.checkFPS(video, video.webkitDecodedFrameCount, video.webkitDroppedFrameCount); + // HTMLVideoElement doesn't include the webkit types + this.checkFPS(video, (video as any).webkitDecodedFrameCount as number, (video as any).webkitDroppedFrameCount as number); } } } diff --git a/src/controller/fragment-tracker.ts b/src/controller/fragment-tracker.ts index 9f507edab1d..c115f27b105 100644 --- a/src/controller/fragment-tracker.ts +++ b/src/controller/fragment-tracker.ts @@ -1,9 +1,11 @@ -import EventHandler from '../event-handler'; -import Event from '../events'; +import { Events } from '../events'; import Fragment from '../loader/fragment'; import { SourceBufferName } from '../types/buffer'; import { FragmentBufferedRange, FragmentEntity, FragmentTimeRange } from '../types/fragment-tracker'; import { PlaylistLevelType } from '../types/loader'; +import { ComponentAPI } from '../types/component-api'; +import Hls from '../hls'; +import { BufferAppendedData, FragBufferedData, FragLoadedData } from '../types/events'; export const FragmentState = { NOT_LOADED: 'NOT_LOADED', @@ -12,27 +14,40 @@ export const FragmentState = { OK: 'OK' }; -export class FragmentTracker extends EventHandler { +export class FragmentTracker implements ComponentAPI { private activeFragment: Fragment | null = null; private fragments: Partial> = Object.create(null); - private timeRanges: { [key in SourceBufferName]: TimeRanges } = Object.create(null); + private timeRanges: { + [key in SourceBufferName]?: TimeRanges + } | null = Object.create(null); + private bufferPadding: number = 0.2; - private config: any; - - constructor (hls) { - super(hls, - Event.BUFFER_APPENDED, - Event.FRAG_BUFFERED, - Event.FRAG_LOADED - ); - this.config = hls.config; + private hls: Hls; + + constructor (hls: Hls) { + this.hls = hls; + + this._registerListeners(); + } + + private _registerListeners () { + const { hls } = this; + hls.on(Events.BUFFER_APPENDED, this.onBufferAppended, this); + hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this); + hls.on(Events.FRAG_LOADED, this.onFragLoaded, this); } - destroy (): void { + private _unregisterListeners () { + const { hls } = this; + hls.off(Events.BUFFER_APPENDED, this.onBufferAppended, this); + hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this); + hls.off(Events.FRAG_LOADED, this.onFragLoaded, this); + } + + public destroy (): void { this.fragments = Object.create(null); this.timeRanges = Object.create(null); - this.config = null; - super.destroy(); + this._unregisterListeners(); } /** @@ -121,6 +136,10 @@ export class FragmentTracker extends EventHandler { */ detectPartialFragments (fragment: Fragment) : void { const { timeRanges, fragments } = this; + if (!timeRanges) { + return; + } + const fragKey = getFragmentKey(fragment); const fragmentEntity = fragments[fragKey]; if (!fragmentEntity) { @@ -248,11 +267,11 @@ export class FragmentTracker extends EventHandler { /** * Fires when a fragment loading is completed */ - onFragLoaded (e): void { - const fragment = e.frag; + onFragLoaded (event: Events.FRAG_LOADED, data: FragLoadedData): void { + const fragment = data.frag; // don't track initsegment (for which sn is not a number) // don't track frags used for bitrateTest, they're irrelevant. - if (!Number.isFinite(fragment.sn) || fragment.bitrateTest) { + if (!Number.isFinite(fragment.sn as number) || fragment.bitrateTest) { return; } @@ -266,8 +285,8 @@ export class FragmentTracker extends EventHandler { /** * Fires when the buffer is updated */ - onBufferAppended (e): void { - const { frag, timeRanges } = e; + onBufferAppended (event: Events.BUFFER_APPENDED, data: BufferAppendedData): void { + const { frag, timeRanges } = data; this.activeFragment = frag; // Store the latest timeRanges loaded in the buffer this.timeRanges = timeRanges; @@ -283,8 +302,8 @@ export class FragmentTracker extends EventHandler { /** * Fires after a fragment has been loaded into the source buffer */ - onFragBuffered (e): void { - this.detectPartialFragments(e.frag); + onFragBuffered (event: Events.FRAG_BUFFERED, data: FragBufferedData): void { + this.detectPartialFragments(data.frag); } /** @@ -316,8 +335,8 @@ export class FragmentTracker extends EventHandler { function isPartial (fragmentEntity: FragmentEntity): boolean { return fragmentEntity.buffered && - ((fragmentEntity.range.video !== undefined && fragmentEntity.range.video.partial) || - (fragmentEntity.range.audio !== undefined && fragmentEntity.range.audio.partial)); + (fragmentEntity.range.video?.partial || + fragmentEntity.range.audio?.partial); } function getFragmentKey (fragment: Fragment): string { diff --git a/src/controller/gap-controller.ts b/src/controller/gap-controller.ts index fa953956178..8e6e041ebe9 100644 --- a/src/controller/gap-controller.ts +++ b/src/controller/gap-controller.ts @@ -1,6 +1,6 @@ import { BufferHelper, BufferInfo } from '../utils/buffer-helper'; import { ErrorTypes, ErrorDetails } from '../errors'; -import Event from '../events'; +import { Events } from '../events'; import { logger } from '../utils/logger'; import Hls from '../hls'; import { HlsConfig } from '../config'; @@ -168,7 +168,7 @@ export default class GapController { // Report stalled error once this.stallReported = true; logger.warn(`Playback stalling at @${media.currentTime} due to low buffer`); - hls.trigger(Event.ERROR, { + hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_STALLED_ERROR, fatal: false, @@ -182,7 +182,7 @@ export default class GapController { * @param partial - The partial fragment found at the current time (where playback is stalling). * @private */ - private _trySkipBufferHole (partial: Fragment | null) { + private _trySkipBufferHole (partial: Fragment | null): number { const { config, hls, media } = this; const currentTime = media.currentTime; let lastEndTime = 0; @@ -196,7 +196,7 @@ export default class GapController { this.stalled = null; media.currentTime = targetTime; if (partial) { - hls.trigger(Event.ERROR, { + hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_SEEK_OVER_HOLE, fatal: false, @@ -226,15 +226,14 @@ export default class GapController { // playback stalled in buffered area ... let's nudge currentTime to try to overcome this logger.warn(`Nudging 'currentTime' from ${currentTime} to ${targetTime}`); media.currentTime = targetTime; - - hls.trigger(Event.ERROR, { + hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_NUDGE_ON_STALL, fatal: false }); } else { logger.error(`Playhead still not moving while enough data buffered @${currentTime} after ${config.nudgeMaxRetry} nudges`); - hls.trigger(Event.ERROR, { + hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_STALLED_ERROR, fatal: true diff --git a/src/controller/level-controller.ts b/src/controller/level-controller.ts index 0ccce845dda..753898d453d 100644 --- a/src/controller/level-controller.ts +++ b/src/controller/level-controller.ts @@ -11,18 +11,19 @@ import { ErrorData } from '../types/events'; import { Level, LevelParsed } from '../types/level'; -import Event from '../events'; -import EventHandler from '../event-handler'; +import { Events } from '../events'; import { logger } from '../utils/logger'; import { ErrorTypes, ErrorDetails } from '../errors'; import { isCodecSupportedInMp4 } from '../utils/codecs'; import { addGroupId, computeReloadInterval } from './level-helper'; import Fragment from '../loader/fragment'; import { MediaPlaylist } from '../types/media-playlist'; +import { NetworkComponentAPI } from '../types/component-api'; +import Hls from '../hls'; -let chromeOrFirefox: boolean; +const chromeOrFirefox: boolean = /chrome|firefox/.test(navigator.userAgent.toLowerCase()); -export default class LevelController extends EventHandler { +export default class LevelController implements NetworkComponentAPI { private _levels: Level[] | null = null; private _firstLevel: number = -1; private _startLevel?: number; @@ -31,21 +32,36 @@ export default class LevelController extends EventHandler { private levelRetryCount: number = 0; private manualLevelIndex: number = -1; private timer: number | null = null; + private hls: Hls; + public onParsedComplete!: Function; - constructor (hls) { - super(hls, - Event.MANIFEST_LOADED, - Event.LEVEL_LOADED, - Event.AUDIO_TRACK_SWITCHED, - Event.FRAG_LOADED, - Event.ERROR); + constructor (hls: Hls) { + this.hls = hls; + this._registerListeners(); + } + + private _registerListeners () { + const { hls } = this; + hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this); + hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this); + hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this); + hls.on(Events.FRAG_LOADED, this.onFragLoaded, this); + hls.on(Events.ERROR, this.onError, this); + } - chromeOrFirefox = /chrome|firefox/.test(navigator.userAgent.toLowerCase()); + private _unregisterListeners () { + const { hls } = this; + hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this); + hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this); + hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this); + hls.off(Events.FRAG_LOADED, this.onFragLoaded, this); + hls.off(Events.ERROR, this.onError, this); } - protected onHandlerDestroying (): void { + public destroy () { this.clearTimer(); + this._unregisterListeners(); this.manualLevelIndex = -1; } @@ -67,7 +83,7 @@ export default class LevelController extends EventHandler { levels.forEach(level => { level.loadError = 0; const levelDetails = level.details; - if (levelDetails && levelDetails.live) { + if (levelDetails?.live) { level.details = undefined; } }); @@ -83,7 +99,7 @@ export default class LevelController extends EventHandler { this.clearTimer(); } - protected onManifestLoaded (data: ManifestLoadedData): void { + protected onManifestLoaded (event: Events.MANIFEST_LOADED, data: ManifestLoadedData): void { let levels: Level[] = []; let audioTracks: MediaPlaylist[] = []; let bitrateStart: number | undefined; @@ -169,11 +185,11 @@ export default class LevelController extends EventHandler { video: videoCodecFound, altAudio: audioTracks.some(t => !!t.url) }; - this.hls.trigger(Event.MANIFEST_PARSED, edata); + this.hls.trigger(Events.MANIFEST_PARSED, edata); this.onParsedComplete(); } else { - this.hls.trigger(Event.ERROR, { + this.hls.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.MANIFEST_INCOMPATIBLE_CODECS_ERROR, fatal: true, @@ -205,7 +221,7 @@ export default class LevelController extends EventHandler { if (this.currentLevelIndex !== newLevel) { logger.log(`[level-controller]: switching to level ${newLevel}`); this.currentLevelIndex = newLevel; - hls.trigger(Event.LEVEL_SWITCHING, Object.assign({}, levels[newLevel], { + hls.trigger(Events.LEVEL_SWITCHING, Object.assign({}, levels[newLevel], { level: newLevel })); } @@ -219,7 +235,7 @@ export default class LevelController extends EventHandler { } } else { // invalid level id given, trigger error - hls.trigger(Event.ERROR, { + hls.trigger(Events.ERROR, { type: ErrorTypes.OTHER_ERROR, details: ErrorDetails.LEVEL_SWITCH_ERROR, level: newLevel, @@ -273,7 +289,7 @@ export default class LevelController extends EventHandler { this._startLevel = newLevel; } - protected onError (data: ErrorData) { + protected onError (event: Events.ERROR, data: ErrorData) { if (data.fatal) { if (data.type === ErrorTypes.NETWORK_ERROR) { this.clearTimer(); @@ -382,7 +398,7 @@ export default class LevelController extends EventHandler { } // reset errors on the successful load of a fragment - protected onFragLoaded ({ frag }: FragLoadedData) { + protected onFragLoaded (event: Events.FRAG_LOADED, { frag }: FragLoadedData) { if (frag !== undefined && frag.type === 'main') { if (!this._levels) { throw new Error('Levels are not set'); @@ -396,7 +412,7 @@ export default class LevelController extends EventHandler { } } - protected onLevelLoaded (data: LevelLoadedData) { + protected onLevelLoaded (event: Events.LEVEL_LOADED, data: LevelLoadedData) { const { level, details } = data; // only process level loaded events matching with expected level if (level !== this.currentLevelIndex) { @@ -423,7 +439,7 @@ export default class LevelController extends EventHandler { } } - protected onAudioTrackSwitched (data: TrackSwitchedData) { + protected onAudioTrackSwitched (event: Events.AUDIO_TRACK_SWITCHED, data: TrackSwitchedData) { const audioGroupId = this.hls.audioTracks[data.id].groupId; const currentLevel = this.hls.levels[this.currentLevelIndex as number]; @@ -464,7 +480,7 @@ export default class LevelController extends EventHandler { // console.log('Current audio track group ID:', this.hls.audioTracks[this.hls.audioTrack].groupId); // console.log('New video quality level audio group id:', levelObject.attrs.AUDIO, level); - this.hls.trigger(Event.LEVEL_LOADING, { url, level, id }); + this.hls.trigger(Events.LEVEL_LOADING, { url, level, id }); } } } @@ -501,7 +517,7 @@ export default class LevelController extends EventHandler { return false; }).map((level, index) => { const { details } = level; - if (details && details.fragments) { + if (details?.fragments) { details.fragments.forEach((fragment) => { fragment.level = index; }); @@ -510,6 +526,6 @@ export default class LevelController extends EventHandler { }); this._levels = levels; - this.hls.trigger(Event.LEVELS_UPDATED, { levels }); + this.hls.trigger(Events.LEVELS_UPDATED, { levels }); } } diff --git a/src/controller/level-helper.ts b/src/controller/level-helper.ts index 0c412004125..bdd1bc80c6e 100644 --- a/src/controller/level-helper.ts +++ b/src/controller/level-helper.ts @@ -58,7 +58,7 @@ export function updatePTS (fragments: Fragment[], fromIdx: number, toIdx: number } } -export function updateFragPTSDTS (details: LevelDetails, frag: Fragment, startPTS: number, endPTS: number, startDTS: number, endDTS: number): number { +export function updateFragPTSDTS (details: LevelDetails | undefined, frag: Fragment, startPTS: number, endPTS: number, startDTS: number, endDTS: number): number { let maxStartPTS = startPTS; if (Number.isFinite(frag.startPTS)) { // delta PTS between audio and video diff --git a/src/controller/stream-controller.ts b/src/controller/stream-controller.ts index 7e7d4523af6..2b331c401b4 100644 --- a/src/controller/stream-controller.ts +++ b/src/controller/stream-controller.ts @@ -1,7 +1,7 @@ import { BufferHelper } from '../utils/buffer-helper'; import TransmuxerInterface from '../demux/transmuxer-interface'; -import Event from '../events'; -import { FragmentState } from './fragment-tracker'; +import { Events } from '../events'; +import { FragmentState, FragmentTracker } from './fragment-tracker'; import Fragment, { ElementaryStreamTypes } from '../loader/fragment'; import PlaylistLoader from '../loader/playlist-loader'; import TimeRanges from '../utils/time-ranges'; @@ -15,11 +15,13 @@ import { Level } from '../types/level'; import LevelDetails from '../loader/level-details'; import { TrackSet } from '../types/track'; import { SourceBufferName } from '../types/buffer'; -import { LevelUpdatedData, BufferAppendingEventPayload } from '../types/events'; +import { LevelLoadedData, ManifestParsedData, MediaAttachedData, AudioTrackSwitchingData, LevelsUpdatedData, AudioTrackSwitchedData, BufferCreatedData, ErrorData } from '../types/events'; +import Hls from '../hls'; +import { NetworkComponentAPI } from '../types/component-api'; const TICK_INTERVAL = 100; // how often to tick in ms -export default class StreamController extends BaseStreamController { +export default class StreamController extends BaseStreamController implements NetworkComponentAPI { private audioCodecSwap: boolean = false; private bitrateTest: boolean = false; private gapController: GapController | null = null; @@ -30,10 +32,10 @@ export default class StreamController extends BaseStreamController { private fragPlaying: Fragment | null = null; private previouslyPaused: boolean = false; private immediateSwitch: boolean = false; - private onvplaying: Function | null = null; - private onvseeking: Function | null = null; - private onvseeked: Function | null = null; - private onvended: Function | null = null; + private onvplaying: EventListener | null = null; + private onvseeking: EventListener | null = null; + private onvseeked: EventListener | null = null; + private onvended: EventListener | null = null; private fragLastKbps: number = 0; private stalled: boolean = false; private audioCodecSwitch: boolean = false; @@ -41,32 +43,58 @@ export default class StreamController extends BaseStreamController { protected readonly logPrefix = '[stream-controller]'; - constructor (hls, fragmentTracker) { - super(hls, - Event.MEDIA_ATTACHED, - Event.MEDIA_DETACHING, - Event.MANIFEST_LOADING, - Event.MANIFEST_PARSED, - Event.LEVEL_LOADING, - Event.LEVEL_LOADED, - Event.KEY_LOADED, - Event.FRAG_LOAD_EMERGENCY_ABORTED, - Event.ERROR, - Event.AUDIO_TRACK_SWITCHING, - Event.AUDIO_TRACK_SWITCHED, - Event.BUFFER_CREATED, - Event.BUFFER_FLUSHED, - Event.LEVELS_UPDATED, - Event.FRAG_BUFFERED - ); - + constructor (hls: Hls, fragmentTracker: FragmentTracker) { + super(hls); this.fragmentLoader = new FragmentLoader(hls.config); this.config = hls.config; this.fragmentTracker = fragmentTracker; this.state = State.STOPPED; + + this._registerListeners(); } - startLoad (startPosition): void { + private _registerListeners () { + const { hls } = this; + hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this); + hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); + hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this); + hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this); + hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this); + hls.on(Events.KEY_LOADED, this.onKeyLoaded, this); + hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this); + hls.on(Events.ERROR, this.onError, this); + hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this); + hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this); + hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this); + hls.on(Events.BUFFER_FLUSHED, this.onBufferFlushed, this); + hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this); + hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this); + } + + protected _unregisterListeners () { + const { hls } = this; + hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this); + hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); + hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this); + hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this); + hls.off(Events.KEY_LOADED, this.onKeyLoaded, this); + hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this); + hls.off(Events.ERROR, this.onError, this); + hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this); + hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this); + hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this); + hls.off(Events.BUFFER_FLUSHED, this.onBufferFlushed, this); + hls.off(Events.LEVELS_UPDATED, this.onLevelsUpdated, this); + hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this); + } + + protected onHandlerDestroying () { + this._unregisterListeners(); + } + + startLoad (startPosition: number): void { if (this.levels) { const { lastCurrentTime, hls } = this; this.stopLoad(); @@ -116,7 +144,7 @@ export default class StreamController extends BaseStreamController { break; case State.WAITING_LEVEL: { const { levels, level } = this; - if (levels && levels[level] && levels[level].details) { + if (levels?.[level]?.details) { // Details is set after the playlist has been loaded this.state = State.IDLE; break; @@ -206,7 +234,7 @@ export default class StreamController extends BaseStreamController { data.type = 'video'; } - this.hls.trigger(Event.BUFFER_EOS, data); + this.hls.trigger(Events.BUFFER_EOS, data); this.state = State.ENDED; return; } @@ -227,7 +255,7 @@ export default class StreamController extends BaseStreamController { _loadKey (frag: Fragment) { this.state = State.KEY_LOADING; - this.hls.trigger(Event.KEY_LOADING, { frag }); + this.hls.trigger(Events.KEY_LOADING, { frag }); } _loadFragment (frag: Fragment) { @@ -297,7 +325,7 @@ export default class StreamController extends BaseStreamController { this.previouslyPaused = previouslyPaused; } const fragCurrent = this.fragCurrent; - if (fragCurrent && fragCurrent.loader) { + if (fragCurrent?.loader) { fragCurrent.loader.abort(); } @@ -313,7 +341,7 @@ export default class StreamController extends BaseStreamController { */ immediateLevelSwitchEnd () { const media = this.media; - if (media && media.buffered.length) { + if (media?.buffered.length) { this.immediateSwitch = false; if (BufferHelper.isBuffered(media, media.currentTime)) { // only nudge if currentTime is buffered @@ -334,7 +362,7 @@ export default class StreamController extends BaseStreamController { nextLevelSwitch () { const { levels, media } = this; // ensure that media is defined and that metadata are available (to retrieve currentTime) - if (media && media.readyState) { + if (media?.readyState) { let fetchdelay; let nextBufferedFrag; const fragPlayingCurrent = this.getAppendedFrag(media.currentTime); @@ -365,7 +393,7 @@ export default class StreamController extends BaseStreamController { if (nextBufferedFrag) { // if we are here, we can also cancel any loading/demuxing in progress, as they are useless const fragCurrent = this.fragCurrent; - if (fragCurrent && fragCurrent.loader) { + if (fragCurrent?.loader) { fragCurrent.loader.abort(); } @@ -385,19 +413,19 @@ export default class StreamController extends BaseStreamController { const flushScope: any = { startOffset: startOffset, endOffset: endOffset, type: this.altAudio ? 'video' : null }; // Reset load errors on flush this.fragLoadError = 0; - this.hls.trigger(Event.BUFFER_FLUSHING, flushScope); + this.hls.trigger(Events.BUFFER_FLUSHING, flushScope); } - onMediaAttached (data) { + onMediaAttached (event: Events.MEDIA_ATTACHED, data: MediaAttachedData) { const media = this.media = this.mediaBuffer = data.media; this.onvplaying = this.onMediaPlaying.bind(this); this.onvseeking = this.onMediaSeeking.bind(this); this.onvseeked = this.onMediaSeeked.bind(this); this.onvended = this.onMediaEnded.bind(this); - media.addEventListener('playing', this.onvplaying); - media.addEventListener('seeking', this.onvseeking); - media.addEventListener('seeked', this.onvseeked); - media.addEventListener('ended', this.onvended); + media.addEventListener('playing', this.onvplaying as EventListener); + media.addEventListener('seeking', this.onvseeking as EventListener); + media.addEventListener('seeked', this.onvseeked as EventListener); + media.addEventListener('ended', this.onvended as EventListener); const config = this.config; if (this.levels && config.autoStartLoad) { this.hls.startLoad(config.startPosition); @@ -408,7 +436,7 @@ export default class StreamController extends BaseStreamController { onMediaDetaching () { const { levels, media } = this; - if (media && media.ended) { + if (media?.ended) { this.log('MSE detaching and video ended, reset startPosition'); this.startPosition = this.lastCurrentTime = 0; } @@ -455,14 +483,14 @@ export default class StreamController extends BaseStreamController { onManifestLoading () { // reset buffer on manifest loading this.log('Trigger BUFFER_RESET'); - this.hls.trigger(Event.BUFFER_RESET); + this.hls.trigger(Events.BUFFER_RESET); this.fragmentTracker.removeAllFragments(); this.stalled = false; this.startPosition = this.lastCurrentTime = 0; this.fragPlaying = null; } - onManifestParsed (data) { + onManifestParsed (event: Events.MANIFEST_PARSED, data: ManifestParsedData) { let aac = false; let heaac = false; let codec; @@ -492,7 +520,7 @@ export default class StreamController extends BaseStreamController { this.state = State.WAITING_LEVEL; } - onLevelLoaded (data) { + onLevelLoaded (event: Events.LEVEL_LOADED, data: LevelLoadedData) { const { levels } = this; const newLevelId = data.level; const newDetails = data.details; @@ -517,8 +545,7 @@ export default class StreamController extends BaseStreamController { // override level info curLevel.details = newDetails; this.levelLastLoaded = newLevelId; - const levelUpdatedData: LevelUpdatedData = { details: newDetails, level: newLevelId }; - this.hls.trigger(Event.LEVEL_UPDATED, levelUpdatedData); + this.hls.trigger(Events.LEVEL_UPDATED, { details: newDetails, level: newLevelId }); if (!this.startFragRequested) { this.setStartPosition(newDetails, sliding); @@ -551,7 +578,7 @@ export default class StreamController extends BaseStreamController { const videoCodec = currentLevel.videoCodec; // time Offset is accurate if level PTS is known, or if playlist is not sliding (not live) and if media is not seeking (this is to overcome potential timestamp drifts between playlists and fragments) - const accurateTimeOffset = !(media && media.seeking) && (details.PTSKnown || !details.live); + const accurateTimeOffset = !(media?.seeking) && (details.PTSKnown || !details.live); const initSegmentData = details.initSegment ? details.initSegment.data : []; const audioCodec = this._getAudioCodec(currentLevel); @@ -575,7 +602,7 @@ export default class StreamController extends BaseStreamController { ); } - onAudioTrackSwitching (data) { + onAudioTrackSwitching (event: Events.AUDIO_TRACK_SWITCHING, data: AudioTrackSwitchingData) { // if any URL found on new audio track, it is an alternate audio track const altAudio = !!data.url; const trackId = data.id; @@ -588,7 +615,7 @@ export default class StreamController extends BaseStreamController { this.mediaBuffer = this.media; const fragCurrent = this.fragCurrent; // we need to refill audio buffer from main: cancel any frag loading to speed up audio switch - if (fragCurrent && fragCurrent.loader) { + if (fragCurrent?.loader) { this.log('Switching to main audio track, cancel main fragment load'); fragCurrent.loader.abort(); } @@ -604,13 +631,13 @@ export default class StreamController extends BaseStreamController { } const hls = this.hls; // switching to main audio, flush all audio and trigger track switched - hls.trigger(Event.BUFFER_FLUSHING, { startOffset: 0, endOffset: Number.POSITIVE_INFINITY, type: 'audio' }); - hls.trigger(Event.AUDIO_TRACK_SWITCHED, { id: trackId }); + hls.trigger(Events.BUFFER_FLUSHING, { startOffset: 0, endOffset: Number.POSITIVE_INFINITY, type: 'audio' }); + hls.trigger(Events.AUDIO_TRACK_SWITCHED, { id: trackId }); this.altAudio = false; } } - onAudioTrackSwitched (data) { + onAudioTrackSwitched (event: Events.AUDIO_TRACK_SWITCHED, data: AudioTrackSwitchedData) { const trackId = data.id; const altAudio = !!this.hls.audioTracks[trackId].url; if (altAudio) { @@ -625,7 +652,7 @@ export default class StreamController extends BaseStreamController { this.tick(); } - onBufferCreated (data) { + onBufferCreated (event: Events.BUFFER_CREATED, data: BufferCreatedData) { const tracks = data.tracks; let mediaTrack; let name; @@ -637,7 +664,10 @@ export default class StreamController extends BaseStreamController { mediaTrack = track; // keep video source buffer reference if (type === 'video') { - this.videoBuffer = tracks[type].buffer; + const videoTrack = tracks[type]; + if (videoTrack) { + this.videoBuffer = videoTrack.buffer; + } } } else { alternate = true; @@ -651,7 +681,7 @@ export default class StreamController extends BaseStreamController { } } - onFragBuffered (data: { frag: Fragment }) { + onFragBuffered (event: Events.FRAG_BUFFERED, data: { frag: Fragment }) { const { frag } = data; if (frag && frag.type !== 'main') { return; @@ -672,7 +702,7 @@ export default class StreamController extends BaseStreamController { this.tick(); } - onError (data) { + onError (event: Events.ERROR, data: ErrorData) { const frag = data.frag || this.fragCurrent; // don't handle frag error not related to main fragment if (frag && frag.type !== 'main') { @@ -692,6 +722,7 @@ export default class StreamController extends BaseStreamController { if ((this.fragLoadError + 1) <= this.config.fragLoadingMaxRetry) { // exponential backoff capped to config.fragLoadingMaxRetryTimeout const delay = Math.min(Math.pow(2, this.fragLoadError) * this.config.fragLoadingRetryDelay, this.config.fragLoadingMaxRetryTimeout); + // @ts-ignore - frag is potentially null according to TS here this.warn(`Fragment ${frag.sn} of level ${frag.level} failed to load, retrying in ${delay}ms`); this.retryDate = self.performance.now() + delay; // retry loading state @@ -728,7 +759,7 @@ export default class StreamController extends BaseStreamController { break; case ErrorDetails.BUFFER_FULL_ERROR: // if in appending state - if (data.parent === 'main' && (this.state === State.PARSING || this.state === State.PARSED)) { + if (data.parent === 'main' && (this.state === State.PARSING || this.state === State.PARSED)) { // reduce max buf len if current position is buffered if (mediaBuffered) { this._reduceMaxBufferLength(this.config.maxBufferLength); @@ -810,7 +841,7 @@ export default class StreamController extends BaseStreamController { this.fragPrevious = null; } - onLevelsUpdated (data) { + onLevelsUpdated (event: Events.LEVELS_UPDATED, data: LevelsUpdatedData) { this.levels = data.levels; } @@ -867,7 +898,7 @@ export default class StreamController extends BaseStreamController { const stats = frag.stats; // Bitrate tests fragments are neither parsed nor buffered stats.parsing.start = stats.parsing.end = stats.buffering.start = stats.buffering.end = self.performance.now(); - hls.trigger(Event.FRAG_BUFFERED, { stats, frag, id: 'main' }); + hls.trigger(Events.FRAG_BUFFERED, { stats, frag, id: 'main' }); this.tick(); }); } @@ -892,16 +923,18 @@ export default class StreamController extends BaseStreamController { if (initSegment) { if (initSegment.tracks) { this._bufferInitSegment(level, initSegment.tracks, frag, chunkMeta); - hls.trigger(Event.FRAG_PARSING_INIT_SEGMENT, { frag, id, tracks: initSegment.tracks }); + hls.trigger(Events.FRAG_PARSING_INIT_SEGMENT, { frag, id, tracks: initSegment.tracks }); } + + // This would be nice if Number.isFinite acted as a typeguard, but it doesn't. See: https://github.com/Microsoft/TypeScript/issues/10038 if (Number.isFinite(initSegment.initPTS as number)) { - hls.trigger(Event.INIT_PTS_FOUND, { frag, id, initPTS: initSegment.initPTS }); + hls.trigger(Events.INIT_PTS_FOUND, { frag, id, initPTS: initSegment.initPTS as number }); } } // Avoid buffering if backtracking this fragment if (video) { - if (_hasDroppedFrames(frag, video.dropped, level.details.startSN)) { + if (level.details && _hasDroppedFrames(frag, video.dropped, level.details.startSN)) { this.backtrack(frag, video.startPTS); return; } else { @@ -915,17 +948,17 @@ export default class StreamController extends BaseStreamController { this.bufferFragmentData(audio, frag, chunkMeta); } - if (id3 && id3.samples && id3.samples.length) { + if (id3?.samples?.length) { const emittedID3: any = id3; emittedID3.frag = frag; emittedID3.id = id; - hls.trigger(Event.FRAG_PARSING_METADATA, emittedID3); + hls.trigger(Events.FRAG_PARSING_METADATA, emittedID3); } if (text) { const emittedText: any = text; emittedText.frag = frag; emittedText.id = id; - hls.trigger(Event.FRAG_PARSING_USERDATA, emittedText); + hls.trigger(Events.FRAG_PARSING_USERDATA, emittedText); } } @@ -970,15 +1003,14 @@ export default class StreamController extends BaseStreamController { video.levelCodec = currentLevel.videoCodec; video.id = 'main'; } - this.hls.trigger(Event.BUFFER_CODECS, tracks); + this.hls.trigger(Events.BUFFER_CODECS, tracks); // loop through tracks that are going to be provided to bufferController Object.keys(tracks).forEach(trackName => { const track = tracks[trackName]; const initSegment = track.initSegment; this.log(`Main track:${trackName},container:${track.container},codecs[level/parsed]=[${track.levelCodec}/${track.codec}]`); if (initSegment) { - const segment: BufferAppendingEventPayload = { type: trackName as SourceBufferName, data: initSegment, frag, chunkMeta }; - this.hls.trigger(Event.BUFFER_APPENDING, segment); + this.hls.trigger(Events.BUFFER_APPENDING, { type: trackName as SourceBufferName, data: initSegment, frag, chunkMeta }); } }); // trigger handler right now @@ -1022,10 +1054,10 @@ export default class StreamController extends BaseStreamController { if (fragPlayingCurrent) { const fragPlaying = fragPlayingCurrent; if (fragPlaying !== this.fragPlaying) { - this.hls.trigger(Event.FRAG_CHANGED, { frag: fragPlaying }); + this.hls.trigger(Events.FRAG_CHANGED, { frag: fragPlaying }); const fragPlayingLevel = fragPlaying.level; if (!this.fragPlaying || this.fragPlaying.level !== fragPlayingLevel) { - this.hls.trigger(Event.LEVEL_SWITCHED, { level: fragPlayingLevel }); + this.hls.trigger(Events.LEVEL_SWITCHED, { level: fragPlayingLevel }); } this.fragPlaying = fragPlaying; diff --git a/src/controller/subtitle-stream-controller.ts b/src/controller/subtitle-stream-controller.ts index 86cf8a446d1..b1087f20809 100644 --- a/src/controller/subtitle-stream-controller.ts +++ b/src/controller/subtitle-stream-controller.ts @@ -2,12 +2,12 @@ * @class SubtitleStreamController */ -import Event from '../events'; +import { Events } from '../events'; import { logger } from '../utils/logger'; import Decrypter from '../crypt/decrypter'; import { BufferHelper } from '../utils/buffer-helper'; import { findFragmentByPDT, findFragmentByPTS } from './fragment-finders'; -import { FragmentState } from './fragment-tracker'; +import { FragmentState, FragmentTracker } from './fragment-tracker'; import BaseStreamController, { State } from './base-stream-controller'; import FragmentLoader from '../loader/fragment-loader'; import { mergeSubtitlePlaylists } from './level-helper'; @@ -16,13 +16,15 @@ import { LevelUpdatedData, MediaAttachedData, SubtitleFragProcessed, - SubtitleTracksUpdated, + SubtitleTracksUpdatedData, TrackLoadedData, TrackSwitchedData } from '../types/events'; import { Level } from '../types/level'; import Fragment from '../loader/fragment'; import LevelDetails from '../loader/level-details'; +import { ComponentAPI } from '../types/component-api'; +import Hls from '../hls'; const { performance } = self; @@ -33,8 +35,9 @@ interface TimeRange { end: number } -export class SubtitleStreamController extends BaseStreamController { +export class SubtitleStreamController extends BaseStreamController implements ComponentAPI { protected levels: Array = []; + private currentTrackId: number = -1; private decrypter: Decrypter; private tracksBuffered: Array; @@ -42,18 +45,8 @@ export class SubtitleStreamController extends BaseStreamController { private lastAVStart: number = 0; private readonly _onMediaSeeking: () => void; - constructor (hls, fragmentTracker) { - super(hls, - Event.MEDIA_ATTACHED, - Event.MEDIA_DETACHING, - Event.ERROR, - Event.KEY_LOADED, - Event.SUBTITLE_TRACKS_UPDATED, - Event.SUBTITLE_TRACK_SWITCH, - Event.SUBTITLE_TRACK_LOADED, - Event.SUBTITLE_FRAG_PROCESSED, - Event.LEVEL_UPDATED); - + constructor (hls: Hls, fragmentTracker: FragmentTracker) { + super(hls); this.config = hls.config; this.decrypter = new Decrypter(hls, hls.config); this.fragCurrent = null; @@ -64,15 +57,44 @@ export class SubtitleStreamController extends BaseStreamController { this.tracksBuffered = []; this.fragmentLoader = new FragmentLoader(hls.config); this._onMediaSeeking = this.onMediaSeeking.bind(this); + + this._registerListeners(); + } + + private _registerListeners () { + const { hls } = this; + hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this); + hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + hls.on(Events.ERROR, this.onError, this); + hls.on(Events.KEY_LOADED, this.onKeyLoaded, this); + hls.on(Events.SUBTITLE_TRACKS_UPDATED, this.onSubtitleTracksUpdated, this); + hls.on(Events.SUBTITLE_TRACK_SWITCH, this.onSubtitleTrackSwitch, this); + hls.on(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this); + hls.on(Events.SUBTITLE_FRAG_PROCESSED, this.onSubtitleFragProcessed, this); + hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this); + } + + private _unregisterListeners () { + const { hls } = this; + hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this); + hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + hls.off(Events.ERROR, this.onError, this); + hls.off(Events.KEY_LOADED, this.onKeyLoaded, this); + hls.off(Events.SUBTITLE_TRACKS_UPDATED, this.onSubtitleTracksUpdated, this); + hls.off(Events.SUBTITLE_TRACK_SWITCH, this.onSubtitleTrackSwitch, this); + hls.off(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this); + hls.off(Events.SUBTITLE_FRAG_PROCESSED, this.onSubtitleFragProcessed, this); + hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this); } onHandlerDestroyed () { delete this.fragmentTracker; this.state = State.STOPPED; + this._unregisterListeners(); super.onHandlerDestroyed(); } - onSubtitleFragProcessed (data: SubtitleFragProcessed) { + onSubtitleFragProcessed (event: Events.SUBTITLE_FRAG_PROCESSED, data: SubtitleFragProcessed) { const { frag, success } = data; this.fragPrevious = frag; this.state = State.IDLE; @@ -108,7 +130,7 @@ export class SubtitleStreamController extends BaseStreamController { } } - onMediaAttached ({ media }: MediaAttachedData) { + onMediaAttached (event: Events.MEDIA_ATTACHED, { media }: MediaAttachedData) { this.media = media; media.addEventListener('seeking', this._onMediaSeeking); this.state = State.IDLE; @@ -129,7 +151,7 @@ export class SubtitleStreamController extends BaseStreamController { } // If something goes wrong, proceed to next frag, if we were processing one. - onError (data: ErrorData) { + onError (event: Events.ERROR, data: ErrorData) { const frag = data.frag; // don't handle error not related to subtitle fragment if (!frag || frag.type !== 'subtitle') { @@ -139,7 +161,7 @@ export class SubtitleStreamController extends BaseStreamController { } // Got all new subtitle levels. - onSubtitleTracksUpdated ({ subtitleTracks }: SubtitleTracksUpdated) { + onSubtitleTracksUpdated (event: Events.SUBTITLE_TRACKS_UPDATED, { subtitleTracks }: SubtitleTracksUpdatedData) { logger.log('subtitle levels updated'); this.tracksBuffered = []; this.levels = subtitleTracks.map(mediaPlaylist => new Level(mediaPlaylist)); @@ -148,7 +170,7 @@ export class SubtitleStreamController extends BaseStreamController { }); } - onSubtitleTrackSwitch (data: TrackSwitchedData) { + onSubtitleTrackSwitch (event: Events.SUBTITLE_TRACK_SWITCH, data: TrackSwitchedData) { this.currentTrackId = data.id; if (!this.levels.length || this.currentTrackId === -1) { @@ -158,13 +180,13 @@ export class SubtitleStreamController extends BaseStreamController { // Check if track has the necessary details to load fragments const currentTrack = this.levels[this.currentTrackId]; - if (currentTrack && currentTrack.details) { + if (currentTrack?.details) { this.setInterval(TICK_INTERVAL); } } // Got a new set of subtitle fragments. - onSubtitleTrackLoaded (data: TrackLoadedData) { + onSubtitleTrackLoaded (event: Events.SUBTITLE_TRACK_LOADED, data: TrackLoadedData) { const { id, details } = data; const { currentTrackId, levels } = this; if (!levels.length || !details) { @@ -201,7 +223,7 @@ export class SubtitleStreamController extends BaseStreamController { // decrypt the subtitles this.decrypter.webCryptoDecrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).then((decryptedData) => { const endTime = performance.now(); - hls.trigger(Event.FRAG_DECRYPTED, { + hls.trigger(Events.FRAG_DECRYPTED, { frag, payload: decryptedData, stats: { @@ -213,7 +235,7 @@ export class SubtitleStreamController extends BaseStreamController { } } - onLevelUpdated ({ details }: LevelUpdatedData) { + onLevelUpdated (event: Events.LEVEL_UPDATED, { details }: LevelUpdatedData) { const frags = details.fragments; this.lastAVStart = frags.length ? frags[0].start : 0; } @@ -258,10 +280,10 @@ export class SubtitleStreamController extends BaseStreamController { foundFrag = fragments[fragLen - 1]; } - if (foundFrag && foundFrag.encrypted) { + if (foundFrag?.encrypted) { logger.log(`Loading key for ${foundFrag.sn}`); this.state = State.KEY_LOADING; - this.hls.trigger(Event.KEY_LOADING, { frag: foundFrag }); + this.hls.trigger(Events.KEY_LOADING, { frag: foundFrag }); } else if (foundFrag && fragmentTracker.getState(foundFrag) === FragmentState.NOT_LOADED) { // only load if fragment is not loaded this.fragCurrent = foundFrag; diff --git a/src/controller/subtitle-track-controller.ts b/src/controller/subtitle-track-controller.ts index 0e4209cdfff..4dedc39014c 100644 --- a/src/controller/subtitle-track-controller.ts +++ b/src/controller/subtitle-track-controller.ts @@ -1,34 +1,53 @@ -import Event from '../events'; -import EventHandler from '../event-handler'; +import { Events } from '../events'; import { logger } from '../utils/logger'; import { computeReloadInterval } from './level-helper'; import { clearCurrentCues } from '../utils/texttrack-utils'; import { MediaPlaylist } from '../types/media-playlist'; -import { TrackLoadedData, ManifestLoadedData, MediaAttachedData, SubtitleTracksUpdated } from '../types/events'; +import { TrackLoadedData, ManifestLoadedData, MediaAttachedData, SubtitleTracksUpdatedData } from '../types/events'; +import { ComponentAPI } from '../types/component-api'; +import Hls from '../hls'; -class SubtitleTrackController extends EventHandler { +class SubtitleTrackController implements ComponentAPI { + private hls: Hls; private tracks: MediaPlaylist[]; private trackId: number = -1; - private media: HTMLVideoElement | null = null; + private media: HTMLMediaElement | null = null; private stopped: boolean = true; - private subtitleDisplay: boolean = true; // Enable/disable subtitle display rendering private queuedDefaultTrack?: number; private trackChangeListener: () => void = () => this._onTextTracksChanged(); private useTextTrackPolling: boolean = false; private subtitlePollingInterval: number = -1; private timer: number | null = null; - constructor (hls) { - super(hls, - Event.MEDIA_ATTACHED, - Event.MEDIA_DETACHING, - Event.MANIFEST_LOADED, - Event.SUBTITLE_TRACK_LOADED); + public subtitleDisplay: boolean = true; // Enable/disable subtitle display rendering + + constructor (hls: Hls) { + this.hls = hls; this.tracks = []; + + this._registerListeners(); + } + + public destroy () { + this._unregisterListeners(); + } + + private _registerListeners () { + this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this); + this.hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + this.hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this); + this.hls.on(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this); + } + + private _unregisterListeners () { + this.hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this); + this.hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + this.hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this); + this.hls.off(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this); } // Listen for subtitle track change, then extract the current track ID. - protected onMediaAttached (data: MediaAttachedData): void { + protected onMediaAttached (event: Events.MEDIA_ATTACHED, data: MediaAttachedData): void { this.media = data.media; if (!this.media) { return; @@ -75,11 +94,11 @@ class SubtitleTrackController extends EventHandler { } // Fired whenever a new manifest is loaded. - protected onManifestLoaded (data: ManifestLoadedData): void { + protected onManifestLoaded (event: Events.MANIFEST_LOADED, data: ManifestLoadedData): void { const subtitleTracks = data.subtitles || []; this.tracks = subtitleTracks; - const subtitleTracksUpdated: SubtitleTracksUpdated = { subtitleTracks }; - this.hls.trigger(Event.SUBTITLE_TRACKS_UPDATED, subtitleTracksUpdated); + const subtitleTracksUpdated: SubtitleTracksUpdatedData = { subtitleTracks }; + this.hls.trigger(Events.SUBTITLE_TRACKS_UPDATED, subtitleTracksUpdated); // loop through available subtitle tracks and autoselect default if needed // TODO: improve selection logic to handle forced, etc @@ -98,7 +117,7 @@ class SubtitleTrackController extends EventHandler { }); } - protected onSubtitleTrackLoaded (data: TrackLoadedData): void { + protected onSubtitleTrackLoaded (event: Events.SUBTITLE_TRACK_LOADED, data: TrackLoadedData): void { const { id, details } = data; const { trackId, tracks } = this; const currentTrack = tracks[trackId]; @@ -166,7 +185,7 @@ class SubtitleTrackController extends EventHandler { return; } logger.log(`[subtitle-track-controller]: Loading subtitle track ${trackId}`); - hls.trigger(Event.SUBTITLE_TRACK_LOADING, { url: currentTrack.url, id: trackId }); + hls.trigger(Events.SUBTITLE_TRACK_LOADING, { url: currentTrack.url, id: trackId }); } /** @@ -210,7 +229,7 @@ class SubtitleTrackController extends EventHandler { this.trackId = newId; logger.log(`[subtitle-track-controller]: Switching to subtitle track ${newId}`); - hls.trigger(Event.SUBTITLE_TRACK_SWITCH, { id: newId }); + hls.trigger(Events.SUBTITLE_TRACK_SWITCH, { id: newId }); this._loadCurrentTrack(); } diff --git a/src/controller/timeline-controller.ts b/src/controller/timeline-controller.ts index 5ea7d1d9809..d7833ed9ba5 100644 --- a/src/controller/timeline-controller.ts +++ b/src/controller/timeline-controller.ts @@ -1,5 +1,4 @@ -import Event from '../events'; -import EventHandler from '../event-handler'; +import { Events } from '../events'; import Cea608Parser, { CaptionScreen } from '../utils/cea-608-parser'; import OutputFilter from '../utils/output-filter'; import WebVTTParser from '../utils/webvtt-parser'; @@ -8,8 +7,10 @@ import { sendAddTrackEvent, clearCurrentCues } from '../utils/texttrack-utils'; import Fragment from '../loader/fragment'; import { HlsConfig } from '../config'; import { parseIMSC1, IMSC1_CODEC } from '../utils/imsc1-ttml-parser'; -import { ManifestLoadedData } from '../types/events'; import { MediaPlaylist } from '../types/media-playlist'; +import Hls from '../hls'; +import { FragParsingUserdataData, FragLoadedData, FragDecryptedData, MediaAttachingData, ManifestLoadedData, InitPTSFoundData } from '../types/events'; +import { ComponentAPI } from '../types/component-api'; function canReuseVttTextTrack (inUseTrack, manifestTrack) { return inUseTrack && inUseTrack.label === manifestTrack.name && !(inUseTrack.textTrack1 || inUseTrack.textTrack2); @@ -19,7 +20,8 @@ function intersection (x1, x2, y1, y2) { return Math.min(x2, y2) - Math.max(x1, y1); } -class TimelineController extends EventHandler { +class TimelineController implements ComponentAPI { + private hls: Hls; private media: HTMLMediaElement | null = null; private config: HlsConfig; private enabled: boolean = true; @@ -27,7 +29,7 @@ class TimelineController extends EventHandler { private textTracks: Array = []; private tracks: Array = []; private initPTS: Array = []; - private unparsedVttFrags: Array<{frag: Fragment, payload: any}> = []; + private unparsedVttFrags: Array = []; private cueRanges: { [trackName: string]: Array } = {}; private captionsTracks: { [trackName: string]: any } = {}; private captionsProperties: any; @@ -36,19 +38,7 @@ class TimelineController extends EventHandler { private prevCC: number = -1; private vttCCs: any = null; - constructor (hls) { - super(hls, Event.MEDIA_ATTACHING, - Event.MEDIA_DETACHING, - Event.FRAG_PARSING_USERDATA, - Event.FRAG_DECRYPTED, - Event.MANIFEST_LOADING, - Event.MANIFEST_LOADED, - Event.FRAG_LOADED, - Event.INIT_PTS_FOUND, - Event.FRAG_PARSING_INIT_SEGMENT, - Event.SUBTITLE_TRACKS_CLEARED - ); - + constructor (hls: Hls) { this.hls = hls; this.config = hls.config; this.Cues = hls.config.cueHandler; @@ -79,6 +69,36 @@ class TimelineController extends EventHandler { const channel4 = new OutputFilter(this, 'textTrack4'); this.cea608Parser = new Cea608Parser(channel1, channel2, channel3, channel4); } + + this._registerListeners(); + } + + private _registerListeners (): void { + const { hls } = this; + hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); + hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + hls.on(Events.FRAG_PARSING_USERDATA, this.onFragParsingUserdata, this); + hls.on(Events.FRAG_DECRYPTED, this.onFragDecrypted, this); + hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); + hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this); + hls.on(Events.FRAG_LOADED, this.onFragLoaded, this); + hls.on(Events.INIT_PTS_FOUND, this.onInitPtsFound, this); + hls.on(Events.FRAG_PARSING_INIT_SEGMENT, this.onFragParsingInitSegment, this); + hls.on(Events.SUBTITLE_TRACKS_CLEARED, this.onSubtitleTracksCleared, this); + } + + private _unregisterListeners (): void { + const { hls } = this; + hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this); + hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this); + hls.off(Events.FRAG_PARSING_USERDATA, this.onFragParsingUserdata, this); + hls.off(Events.FRAG_DECRYPTED, this.onFragDecrypted, this); + hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); + hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this); + hls.off(Events.FRAG_LOADED, this.onFragLoaded, this); + hls.off(Events.INIT_PTS_FOUND, this.onInitPtsFound, this); + hls.off(Events.FRAG_PARSING_INIT_SEGMENT, this.onFragParsingInitSegment, this); + hls.off(Events.SUBTITLE_TRACKS_CLEARED, this.onSubtitleTracksCleared, this); } addCues (trackName: string, startTime: number, endTime: number, screen: CaptionScreen) { @@ -110,12 +130,12 @@ class TimelineController extends EventHandler { this.captionsTracks[trackName].addCue(cue); }); } else { - this.hls.trigger(Event.CUES_PARSED, { type: 'captions', cues: cues, track: trackName }); + this.hls.trigger(Events.CUES_PARSED, { type: 'captions', cues: cues, track: trackName }); } } // Triggered when an initial PTS is found; used for synchronisation of WebVTT. - onInitPtsFound (data: { id: string, frag: Fragment, initPTS: number}) { + onInitPtsFound (event: Events.INIT_PTS_FOUND, data: InitPTSFoundData) { const { frag, id, initPTS } = data; const { unparsedVttFrags } = this; if (id === 'main') { @@ -127,7 +147,8 @@ class TimelineController extends EventHandler { if (unparsedVttFrags.length) { this.unparsedVttFrags = []; unparsedVttFrags.forEach(frag => { - this.onFragLoaded(frag); + // TODO: This can be either FragLoadedData or FragDecryptedData + this.onFragLoaded(Events.FRAG_LOADED, frag as FragLoadedData); }); } } @@ -184,13 +205,12 @@ class TimelineController extends EventHandler { } const label = props.label; const track = { - _id: trackName, label, kind: 'captions', default: false }; captionsTracks[trackName] = track; - this.hls.trigger(Event.NON_NATIVE_TEXT_TRACKS_FOUND, { tracks: [track] }); + this.hls.trigger(Events.NON_NATIVE_TEXT_TRACKS_FOUND, { tracks: [track] }); } createTextTrack (kind: TextTrackKind, label?: string, lang?: string): TextTrack | undefined { @@ -202,10 +222,10 @@ class TimelineController extends EventHandler { } destroy () { - super.destroy(); + this._unregisterListeners(); } - onMediaAttaching (data: { media: HTMLMediaElement }) { + onMediaAttaching (event: Events.MEDIA_ATTACHING, data: MediaAttachingData) { this.media = data.media; this._cleanTracks(); } @@ -252,7 +272,7 @@ class TimelineController extends EventHandler { } } - onManifestLoaded (data: ManifestLoadedData) { + onManifestLoaded (event: Events.MANIFEST_LOADED, data: ManifestLoadedData) { this.textTracks = []; this.unparsedVttFrags = this.unparsedVttFrags || []; this.initPTS = []; @@ -303,7 +323,7 @@ class TimelineController extends EventHandler { default: track.default }; }); - this.hls.trigger(Event.NON_NATIVE_TEXT_TRACKS_FOUND, { tracks: tracksList }); + this.hls.trigger(Events.NON_NATIVE_TEXT_TRACKS_FOUND, { tracks: tracksList }); } } @@ -325,28 +345,26 @@ class TimelineController extends EventHandler { } } - onFragLoaded (data: { frag: Fragment, payload: any }) { + onFragLoaded (event: Events.FRAG_LOADED, data: FragLoadedData) { const { frag, payload } = data; - const { cea608Parser, initPTS, unparsedVttFrags } = this; + const { cea608Parser, initPTS, lastSn, unparsedVttFrags } = this; if (frag.type === 'main') { const sn = frag.sn; // if this frag isn't contiguous, clear the parser so cues with bad start/end times aren't added to the textTrack - if (sn !== this.lastSn + 1) { + if (sn !== lastSn + 1) { if (cea608Parser) { cea608Parser.reset(); } } this.lastSn = sn as number; - } // eslint-disable-line brace-style - // If fragment is subtitle type, parse as WebVTT. - else if (frag.type === 'subtitle') { + } else if (frag.type === 'subtitle') { // If fragment is subtitle type, parse as WebVTT. if (payload.byteLength) { // We need an initial synchronisation PTS. Store fragments as long as none has arrived. if (!Number.isFinite(initPTS[frag.cc])) { unparsedVttFrags.push(data); if (this.initPTS.length) { // finish unsuccessfully, otherwise the subtitle-stream-controller could be blocked from loading new frags. - this.hls.trigger(Event.SUBTITLE_FRAG_PROCESSED, { success: false, frag, error: new Error('Missing initial subtitle PTS') }); + this.hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, { success: false, frag, error: new Error('Missing initial subtitle PTS') }); } return; } @@ -368,37 +386,37 @@ class TimelineController extends EventHandler { } } else { // In case there is no payload, finish unsuccessfully. - this.hls.trigger(Event.SUBTITLE_FRAG_PROCESSED, { success: false, frag, error: new Error('Empty subtitle payload') }); + this.hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, { success: false, frag, error: new Error('Empty subtitle payload') }); } } } - _parseIMSC1 (frag, payload) { + private _parseIMSC1 (frag: Fragment, payload: ArrayBuffer) { const hls = this.hls; parseIMSC1(payload, this.initPTS[frag.cc], (cues) => { this._appendCues(cues, frag.level); - hls.trigger(Event.SUBTITLE_FRAG_PROCESSED, { success: true, frag: frag }); + hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, { success: true, frag: frag }); }, (error) => { logger.log(`Failed to parse IMSC1: ${error}`); - hls.trigger(Event.SUBTITLE_FRAG_PROCESSED, { success: false, frag: frag, error }); + hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, { success: false, frag: frag, error }); }); } - _parseVTTs (frag, payload, vttCCs) { + private _parseVTTs (frag: Fragment, payload: ArrayBuffer, vttCCs: any) { const hls = this.hls; // Parse the WebVTT file contents. WebVTTParser.parse(payload, this.initPTS[frag.cc], vttCCs, frag.cc, (cues) => { this._appendCues(cues, frag.level); - hls.trigger(Event.SUBTITLE_FRAG_PROCESSED, { success: true, frag: frag }); + hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, { success: true, frag: frag }); }, (error) => { this._fallbackToIMSC1(frag, payload); // Something went wrong while parsing. Trigger event with success false. logger.log(`Failed to parse VTT cue: ${error}`); - hls.trigger(Event.SUBTITLE_FRAG_PROCESSED, { success: false, frag: frag, error }); + hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, { success: false, frag: frag, error }); }); } - _fallbackToIMSC1 (frag, payload) { + private _fallbackToIMSC1 (frag: Fragment, payload: ArrayBuffer) { // If textCodec is unknown, try parsing as IMSC1. Set textCodec based on the result const trackPlaylistMedia = this.tracks[frag.level]; if (!trackPlaylistMedia.textCodec) { @@ -411,7 +429,7 @@ class TimelineController extends EventHandler { } } - _appendCues (cues, fragLevel) { + private _appendCues (cues, fragLevel) { const hls = this.hls; if (this.config.renderNatively) { const textTrack = this.textTracks[fragLevel]; @@ -421,19 +439,19 @@ class TimelineController extends EventHandler { } else { const currentTrack = this.tracks[fragLevel]; const track = currentTrack.default ? 'default' : 'subtitles' + fragLevel; - hls.trigger(Event.CUES_PARSED, { type: 'subtitles', cues, track }); + hls.trigger(Events.CUES_PARSED, { type: 'subtitles', cues, track }); } } - onFragDecrypted (data: { frag: Fragment, payload: any}) { + onFragDecrypted (event: Events.FRAG_DECRYPTED, data: FragDecryptedData) { const { frag } = data; if (frag.type === 'subtitle') { if (!Number.isFinite(this.initPTS[frag.cc])) { - this.unparsedVttFrags.push(data); + this.unparsedVttFrags.push(data as unknown as FragLoadedData); return; } - this.onFragLoaded(data); + this.onFragLoaded(Events.FRAG_LOADED, data as unknown as FragLoadedData); } } @@ -442,7 +460,7 @@ class TimelineController extends EventHandler { this.captionsTracks = {}; } - onFragParsingUserdata (data: { samples: Array }) { + onFragParsingUserdata (event: Events.FRAG_PARSING_USERDATA, data: FragParsingUserdataData) { if (!this.enabled || !this.cea608Parser) { return; } @@ -464,7 +482,7 @@ class TimelineController extends EventHandler { // If we receive this event, we have not received an onInitPtsFound event. This happens when the video track has no samples (but has audio) // In order to have captions display, which requires an initPTS, we assume one of 90000 if (typeof this.initPTS === 'undefined') { - this.onInitPtsFound({ id: '', frag: new Fragment(), initPTS: 90000 }); + this.onInitPtsFound(Events.INIT_PTS_FOUND, { id: '', frag: new Fragment(), initPTS: 90000 }); } } diff --git a/src/crypt/aes-crypto.ts b/src/crypt/aes-crypto.ts index 80d6aba8ffa..30b409e40e0 100644 --- a/src/crypt/aes-crypto.ts +++ b/src/crypt/aes-crypto.ts @@ -1,13 +1,13 @@ export default class AESCrypto { - private subtle: any; + private subtle: SubtleCrypto; private aesIV: ArrayBuffer; - constructor (subtle, iv) { + constructor (subtle: SubtleCrypto, iv: ArrayBuffer) { this.subtle = subtle; this.aesIV = iv; } - decrypt (data: ArrayBuffer, key) { + decrypt (data: ArrayBuffer, key: CryptoKey) { return this.subtle.decrypt({ name: 'AES-CBC', iv: this.aesIV }, key, data); } } diff --git a/src/crypt/decrypter.ts b/src/crypt/decrypter.ts index 5bc81d045f1..0d855a958a6 100644 --- a/src/crypt/decrypter.ts +++ b/src/crypt/decrypter.ts @@ -113,6 +113,10 @@ export default class Decrypter { return this.fastAesKey.expandKey() .then((aesKey) => { // decrypt using web crypto + if (!subtle) { + return Promise.reject(new Error('web crypto not initialized')); + } + const crypto = new AESCrypto(subtle, iv); return crypto.decrypt(data.buffer, aesKey); }) diff --git a/src/demux/adts.js b/src/demux/adts.js index 34f9b4da897..11b674a2eff 100644 --- a/src/demux/adts.js +++ b/src/demux/adts.js @@ -5,7 +5,7 @@ import { logger } from '../utils/logger'; import { ErrorTypes, ErrorDetails } from '../errors'; -import Event from '../events'; +import { Events } from '../events'; export function getAudioConfig (observer, data, offset, audioCodec) { let adtsObjectType; // :int @@ -26,7 +26,7 @@ export function getAudioConfig (observer, data, offset, audioCodec) { adtsObjectType = ((data[offset + 2] & 0xC0) >>> 6) + 1; const adtsSampleingIndex = ((data[offset + 2] & 0x3C) >>> 2); if (adtsSampleingIndex > adtsSampleingRates.length - 1) { - observer.trigger(Event.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: true, reason: `invalid ADTS sampling index:${adtsSampleingIndex}` }); + observer.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: true, reason: `invalid ADTS sampling index:${adtsSampleingIndex}` }); return; } adtsChanelConfig = ((data[offset + 2] & 0x01) << 2); diff --git a/src/demux/transmuxer-interface.ts b/src/demux/transmuxer-interface.ts index bfd2e6950f3..deba91c2608 100644 --- a/src/demux/transmuxer-interface.ts +++ b/src/demux/transmuxer-interface.ts @@ -1,19 +1,27 @@ import * as work from 'webworkify-webpack'; -import Event from '../events'; +import { Events } from '../events'; import Transmuxer, { TransmuxConfig, TransmuxState, isPromise } from '../demux/transmuxer'; import { logger } from '../utils/logger'; import { ErrorTypes, ErrorDetails } from '../errors'; import { getMediaSource } from '../utils/mediasource-helper'; -import { Observer } from '../observer'; +import { EventEmitter } from 'eventemitter3'; import Fragment from '../loader/fragment'; import { ChunkMetadata, TransmuxerResult } from '../types/transmuxer'; +import Hls from '../hls'; const MediaSource = getMediaSource() || { isTypeSupported: () => false }; +// TOOD: Refactor this out +class Observer extends EventEmitter { + trigger (event: any, ...args: any[]) { + this.emit(event, args); + } +} + export default class TransmuxerInterface { - private hls: any; + private hls: Hls; private id: any; - private observer: any; + private observer: Observer | null; private frag?: Fragment; private worker: any; private onwmsg?: Function; @@ -23,13 +31,12 @@ export default class TransmuxerInterface { private currentTransmuxSession: ChunkMetadata | null = null; - constructor (hls, id, onTransmuxComplete, onFlush) { + constructor (hls: Hls, id, onTransmuxComplete, onFlush) { this.hls = hls; this.id = id; this.onTransmuxComplete = onTransmuxComplete; this.onFlush = onFlush; - const observer = this.observer = new Observer(); const config = hls.config; const forwardMessage = (ev, data) => { @@ -40,8 +47,9 @@ export default class TransmuxerInterface { }; // forward events to main thread - observer.on(Event.FRAG_DECRYPTED, forwardMessage); - observer.on(Event.ERROR, forwardMessage); + this.observer = new Observer(); + this.observer.on(Events.FRAG_DECRYPTED, forwardMessage); + this.observer.on(Events.ERROR, forwardMessage); const typeSupported = { mp4: MediaSource.isTypeSupported('video/mp4'), @@ -59,7 +67,7 @@ export default class TransmuxerInterface { this.onwmsg = this.onWorkerMessage.bind(this); worker.addEventListener('message', this.onwmsg); worker.onerror = (event) => { - hls.trigger(Event.ERROR, { type: ErrorTypes.OTHER_ERROR, details: ErrorDetails.INTERNAL_EXCEPTION, fatal: true, event: 'demuxerWorker', err: { message: event.message + ' (' + event.filename + ':' + event.lineno + ')' } }); + hls.trigger(Events.ERROR, { type: ErrorTypes.OTHER_ERROR, details: ErrorDetails.INTERNAL_EXCEPTION, fatal: true, event: 'demuxerWorker', err: { message: event.message + ' (' + event.filename + ':' + event.lineno + ')' } }); }; worker.postMessage({ cmd: 'init', typeSupported: typeSupported, vendor: vendor, id: id, config: JSON.stringify(config) }); } catch (err) { @@ -69,11 +77,11 @@ export default class TransmuxerInterface { // revoke the Object URL that was used to create transmuxer worker, so as not to leak it self.URL.revokeObjectURL(worker.objectURL); } - this.transmuxer = new Transmuxer(observer, typeSupported, config, vendor); + this.transmuxer = new Transmuxer(this.observer, typeSupported, config, vendor); this.worker = null; } } else { - this.transmuxer = new Transmuxer(observer, typeSupported, config, vendor); + this.transmuxer = new Transmuxer(this.observer, typeSupported, config, vendor); } } diff --git a/src/demux/transmuxer-worker.ts b/src/demux/transmuxer-worker.ts index 1f8a4c7d046..de5ec1f29ee 100644 --- a/src/demux/transmuxer-worker.ts +++ b/src/demux/transmuxer-worker.ts @@ -1,27 +1,19 @@ import Transmuxer, { isPromise } from '../demux/transmuxer'; -import Event from '../events'; +import { Events } from '../events'; import { enableLogs } from '../utils/logger'; import { EventEmitter } from 'eventemitter3'; import { RemuxedTrack, RemuxerResult } from '../types/remuxer'; import { TransmuxerResult, ChunkMetadata } from '../types/transmuxer'; export default function TransmuxerWorker (self) { - const observer = new EventEmitter() as any; - observer.trigger = (event, data) => { - observer.emit(event, event, ...data); - }; - - observer.off = (event, ...data) => { - observer.removeListener(event, ...data); - }; - + const observer = new EventEmitter(); const forwardMessage = (ev, data) => { self.postMessage({ event: ev, data: data }); }; // forward events to main thread - observer.on(Event.FRAG_DECRYPTED, forwardMessage); - observer.on(Event.ERROR, forwardMessage); + observer.on(Events.FRAG_DECRYPTED, forwardMessage); + observer.on(Events.ERROR, forwardMessage); self.addEventListener('message', (ev) => { const data = ev.data; diff --git a/src/demux/transmuxer.ts b/src/demux/transmuxer.ts index 967d164e743..9b6f725edbf 100644 --- a/src/demux/transmuxer.ts +++ b/src/demux/transmuxer.ts @@ -1,4 +1,4 @@ -import Event from '../events'; +import { Events, HlsEventEmitter } from '../events'; import { ErrorTypes, ErrorDetails } from '../errors'; import Decrypter from '../crypt/decrypter'; import AACDemuxer from '../demux/aacdemuxer'; @@ -37,7 +37,7 @@ muxConfig.forEach(({ demux }) => { }); export default class Transmuxer { - private observer: any; + private observer: HlsEventEmitter; private typeSupported: any; private config: any; private vendor: any; @@ -50,7 +50,7 @@ export default class Transmuxer { private currentTransmuxState!: TransmuxState; private cache: ChunkCache = new ChunkCache(); - constructor (observer, typeSupported, config, vendor) { + constructor (observer: HlsEventEmitter, typeSupported, config, vendor) { this.observer = observer; this.typeSupported = typeSupported; this.config = config; @@ -176,7 +176,7 @@ export default class Transmuxer { if (!demuxer || !remuxer) { // If probing failed, and each demuxer saw enough bytes to be able to probe, then Hls.js has been given content its not able to handle if (bytesSeen >= minProbeByteLength) { - observer.trigger(Event.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: true, reason: 'no demux matching with content found' }); + observer.emit(Events.ERROR, Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: true, reason: 'no demux matching with content found' }); } stats.executeEnd = now(); return [emptyResult(chunkMeta)]; diff --git a/src/demux/tsdemuxer.ts b/src/demux/tsdemuxer.ts index 2938a229e5b..4d4faa7a834 100644 --- a/src/demux/tsdemuxer.ts +++ b/src/demux/tsdemuxer.ts @@ -11,7 +11,7 @@ import * as ADTS from './adts'; import * as MpegAudio from './mpegaudio'; -import Event from '../events'; +import { Events } from '../events'; import ExpGolomb from './exp-golomb'; import SampleAesDecrypter from './sample-aes'; import { logger } from '../utils/logger'; @@ -327,7 +327,7 @@ class TSDemuxer implements Demuxer { break; } } else { - this.observer.trigger(Event.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: false, reason: 'TS packet did not start with 0x47' }); + this.observer.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: false, reason: 'TS packet did not start with 0x47' }); } } @@ -388,7 +388,7 @@ class TSDemuxer implements Demuxer { audioTrack.pesData = null; } else { - if (audioData && audioData.size) { + if (audioData?.size) { logger.log('last AAC PES packet truncated,might overlap between fragments'); } @@ -732,7 +732,7 @@ class TSDemuxer implements Demuxer { const samples = this._avcTrack.samples; avcSample = samples[samples.length - 1]; } - if (avcSample && avcSample.units) { + if (avcSample?.units) { const units = avcSample.units; lastUnit = units[units.length - 1]; } @@ -923,7 +923,7 @@ class TSDemuxer implements Demuxer { fatal = true; } logger.warn(`parsing error:${reason}`); - this.observer.trigger(Event.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: fatal, reason: reason }); + this.observer.trigger(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_PARSING_ERROR, fatal: fatal, reason: reason }); if (fatal) { return; } @@ -1037,10 +1037,8 @@ function parsePMT (data, offset, mpegSupported, isSampleAes) { logger.log('unknown stream type:' + data[offset]); break; } - /* falls through */ - - // ISO/IEC 13818-7 ADTS AAC (MPEG-2 lower bit-rate audio) - case 0x0f: + /* falls through */ + case 0x0f: // ISO/IEC 13818-7 ADTS AAC (MPEG-2 lower bit-rate audio) // logger.log('AAC PID:' + pid); if (result.audio === -1) { result.audio = pid; @@ -1063,9 +1061,7 @@ function parsePMT (data, offset, mpegSupported, isSampleAes) { break; } /* falls through */ - - // ITU-T Rec. H.264 and ISO/IEC 14496-10 (lower bit-rate video) - case 0x1b: + case 0x1b: // ITU-T Rec. H.264 and ISO/IEC 14496-10 (lower bit-rate video) // logger.log('AVC PID:' + pid); if (result.avc === -1) { result.avc = pid; diff --git a/src/event-handler.ts b/src/event-handler.ts deleted file mode 100644 index 7d0db41eff4..00000000000 --- a/src/event-handler.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* -* -* All objects in the event handling chain should inherit from this class -* -*/ - -import { logger } from './utils/logger'; -import { ErrorTypes, ErrorDetails } from './errors'; -import Event from './events'; -import Hls from './hls'; - -const FORBIDDEN_EVENT_NAMES = { - hlsEventGeneric: true, - hlsHandlerDestroying: true, - hlsHandlerDestroyed: true -}; - -class EventHandler { - protected hls: Hls; - private handledEvents: any[]; - private useGenericHandler: boolean; - - constructor (hls: Hls, ...events: any[]) { - this.hls = hls; - this.onEvent = this.onEvent.bind(this); - this.handledEvents = events; - this.useGenericHandler = true; - - this.registerListeners(); - } - - protected destroy () { - this.onHandlerDestroying(); - this.unregisterListeners(); - this.onHandlerDestroyed(); - } - - protected onHandlerDestroying () {} - protected onHandlerDestroyed () {} - - private isEventHandler () { - return typeof this.handledEvents === 'object' && this.handledEvents.length && typeof this.onEvent === 'function'; - } - - private registerListeners () { - if (this.isEventHandler()) { - this.handledEvents.forEach(function (event) { - if (FORBIDDEN_EVENT_NAMES[event]) { - throw new Error('Forbidden event-name: ' + event); - } - - this.hls.on(event, this.onEvent); - }, this); - } - } - - private unregisterListeners () { - if (this.isEventHandler()) { - this.handledEvents.forEach(function (event) { - this.hls.off(event, this.onEvent); - }, this); - } - } - - /** - * arguments: event (string), data (any) - */ - private onEvent (event: string, data: any) { - this.onEventGeneric(event, data); - } - - private onEventGeneric (event: string, data: any) { - const eventToFunction = function (event: string, data: any) { - const funcName = 'on' + event.replace('hls', ''); - if (typeof this[funcName] !== 'function') { - throw new Error(`Event ${event} has no generic handler in this ${this.constructor.name} class (tried ${funcName})`); - } - - return this[funcName].bind(this, data); - }; - try { - eventToFunction.call(this, event, data).call(); - } catch (err) { - logger.error(`An internal error happened while handling event ${event}. Error message: "${err.message}". Here is a stacktrace:`, err); - this.hls.trigger(Event.ERROR, { type: ErrorTypes.OTHER_ERROR, details: ErrorDetails.INTERNAL_EXCEPTION, fatal: false, event: event, err: err }); - } - } -} - -export default EventHandler; diff --git a/src/events.ts b/src/events.ts index 4c40063a438..5899d73a341 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,118 +1,188 @@ +import { ManifestLoadedData, ManifestLoadingData, MediaAttachedData, MediaAttachingData, LevelLoadingData, LevelLoadedData, ManifestParsedData, LevelUpdatedData, LevelsUpdatedData, FragParsingUserdataData, FragDecryptedData, FragLoadedData, InitPTSFoundData, CuesParsedData, SubtitleFragProcessedData, NonNativeTextTracksData, FragLoadingData, AudioTrackLoadingData, AudioTrackLoadedData, SubtitleTrackLoadedData, SubtitleTrackLoadingData, ErrorData, AudioTrackSwitchingData, AudioTrackSwitchedData, KeyLoadedData, KeyLoadingData, SubtitleTrackSwitchData, SubtitleTracksUpdatedData, LevelSwitchedData, FragChangedData, BufferAppendingData, BufferCodecsData, FragParsingMetadataData, FragParsingInitSegmentData, FragBufferedData, BufferFlushingData, BufferEOSData, LevelSwitchingData, FPSDropLevelCappingData, FPSDropData, BufferCreatedData, BufferAppendedData, LevelPTSUpdatedData, FragParsedData, AudioTracksUpdatedData, FragLoadEmergencyAbortedData, LiveBackBufferData } from './types/events'; +import { Tail } from './types/tuples'; + /** * @readonly * @enum {string} */ -enum HlsEvents { - // fired before MediaSource is attaching to media element - data = { media } +export enum Events { + // Fired before MediaSource is attaching to media element MEDIA_ATTACHING = 'hlsMediaAttaching', - // fired when MediaSource has been succesfully attached to media element - data = { } + // Fired when MediaSource has been successfully attached to media element MEDIA_ATTACHED = 'hlsMediaAttached', - // fired before detaching MediaSource from media element - data = { } + // Fired before deatching MediaSource from media element MEDIA_DETACHING = 'hlsMediaDetaching', - // fired when MediaSource has been detached from media element - data = { } + // Fired when MediaSource has been detached from media element MEDIA_DETACHED = 'hlsMediaDetached', - // fired when we buffer is going to be reset - data = { } + // Fired when the buffer is going to be reset BUFFER_RESET = 'hlsBufferReset', - // fired when we know about the codecs that we need buffers for to push into - data = {tracks = { container, codec, levelCodec, initSegment, metadata }} + // Fired when we know about the codecs that we need buffers for to push into - data: {tracks : { container, codec, levelCodec, initSegment, metadata }} BUFFER_CODECS = 'hlsBufferCodecs', - // fired when sourcebuffers have been created - data = { tracks = tracks } + // fired when sourcebuffers have been created - data: { tracks : tracks } BUFFER_CREATED = 'hlsBufferCreated', - // fired when we append a segment to the buffer - data = { segment = segment object } + // fired when we append a segment to the buffer - data: { segment: segment object } BUFFER_APPENDING = 'hlsBufferAppending', - // fired when we are done with appending a media segment to the buffer - data = { parent = segment parent that triggered BUFFER_APPENDING, pending = nb of segments waiting for appending for this segment parent} + // fired when we are done with appending a media segment to the buffer - data : { parent : segment parent that triggered BUFFER_APPENDING, pending : nb of segments waiting for appending for this segment parent} BUFFER_APPENDED = 'hlsBufferAppended', - // fired when the stream is finished and we want to notify the media buffer that there will be no more data - data = { } + // fired when the stream is finished and we want to notify the media buffer that there will be no more data - data: { } BUFFER_EOS = 'hlsBufferEos', // fired when the media buffer should be flushed - data { startOffset, endOffset } BUFFER_FLUSHING = 'hlsBufferFlushing', - // fired when the media buffer has been flushed - data = { } + // fired when the media buffer has been flushed - data: { } BUFFER_FLUSHED = 'hlsBufferFlushed', - // fired to signal that a manifest loading starts - data = { url = manifestURL} + // fired to signal that a manifest loading starts - data: { url : manifestURL} MANIFEST_LOADING = 'hlsManifestLoading', - // fired after manifest has been loaded - data = { levels = [available quality levels], audioTracks = [ available audio tracks], url = manifestURL, stats = { trequest, tfirst, tload, mtime}} + // fired after manifest has been loaded - data: { levels : [available quality levels], audioTracks : [ available audio tracks], url : manifestURL, stats : { trequest, tfirst, tload, mtime}} MANIFEST_LOADED = 'hlsManifestLoaded', - // fired after manifest has been parsed - data = { levels = [available quality levels], firstLevel = index of first quality level appearing in Manifest} + // fired after manifest has been parsed - data: { levels : [available quality levels], firstLevel : index of first quality level appearing in Manifest} MANIFEST_PARSED = 'hlsManifestParsed', - // fired when a level switch is requested - data = { level = id of new level } + // fired when a level switch is requested - data: { level : id of new level } LEVEL_SWITCHING = 'hlsLevelSwitching', - // fired when a level switch is effective - data = { level = id of new level } + // fired when a level switch is effective - data: { level : id of new level } LEVEL_SWITCHED = 'hlsLevelSwitched', - // fired when a level playlist loading starts - data = { url = level URL, level = id of level being loaded} + // fired when a level playlist loading starts - data: { url : level URL, level : id of level being loaded} LEVEL_LOADING = 'hlsLevelLoading', - // fired when a level playlist loading finishes - data = { details = levelDetails object, level = id of loaded level, stats = { trequest, tfirst, tload, mtime} } + // fired when a level playlist loading finishes - data: { details : levelDetails object, level : id of loaded level, stats : { trequest, tfirst, tload, mtime} } LEVEL_LOADED = 'hlsLevelLoaded', - // fired when a level's details have been updated based on previous details, after it has been loaded - data = { details = levelDetails object, level = id of updated level } + // fired when a level's details have been updated based on previous details, after it has been loaded - data: { details : levelDetails object, level : id of updated level } LEVEL_UPDATED = 'hlsLevelUpdated', - // fired when a level's PTS information has been updated after parsing a fragment - data = { details = levelDetails object, level = id of updated level, drift = PTS drift observed when parsing last fragment } + // fired when a level's PTS information has been updated after parsing a fragment - data: { details : levelDetails object, level : id of updated level, drift: PTS drift observed when parsing last fragment } LEVEL_PTS_UPDATED = 'hlsLevelPtsUpdated', - // fired to notify that audio track lists has been updated - data = { audioTracks = audioTracks } + // fired to notify that audio track lists has been updated - data: { audioTracks : audioTracks } LEVELS_UPDATED = 'hlsLevelsUpdated', - // fired to notify that levels have changed outside of a manifest parsing event - data = { levels } + // fired to notify that audio track lists has been updated - data: { audioTracks : audioTracks } AUDIO_TRACKS_UPDATED = 'hlsAudioTracksUpdated', - // fired when an audio track switching is requested - data = { id = audio track id } + // fired when an audio track switching is requested - data: { id : audio track id } AUDIO_TRACK_SWITCHING = 'hlsAudioTrackSwitching', - // fired when an audio track switch actually occurs - data = { id = audio track id } + // fired when an audio track switch actually occurs - data: { id : audio track id } AUDIO_TRACK_SWITCHED = 'hlsAudioTrackSwitched', - // fired when an audio track loading starts - data = { url = audio track URL, id = audio track id } + // fired when an audio track loading starts - data: { url : audio track URL, id : audio track id } AUDIO_TRACK_LOADING = 'hlsAudioTrackLoading', - // fired when an audio track loading finishes - data = { details = levelDetails object, id = audio track id, stats = { trequest, tfirst, tload, mtime } } + // fired when an audio track loading finishes - data: { details : levelDetails object, id : audio track id, stats : { trequest, tfirst, tload, mtime } } AUDIO_TRACK_LOADED = 'hlsAudioTrackLoaded', - // fired to notify that subtitle track lists has been updated - data = { subtitleTracks = subtitleTracks } + // fired to notify that subtitle track lists has been updated - data: { subtitleTracks : subtitleTracks } SUBTITLE_TRACKS_UPDATED = 'hlsSubtitleTracksUpdated', // fired to notify that subtitle tracks were cleared as a result of stopping the media SUBTITLE_TRACKS_CLEARED = 'hlsSubtitleTracksCleared', - // fired when an subtitle track switch occurs - data = { id = subtitle track id } + // fired when an subtitle track switch occurs - data: { id : subtitle track id } SUBTITLE_TRACK_SWITCH = 'hlsSubtitleTrackSwitch', - // fired when a subtitle track loading starts - data = { url = subtitle track URL, id = subtitle track id } + // fired when a subtitle track loading starts - data: { url : subtitle track URL, id : subtitle track id } SUBTITLE_TRACK_LOADING = 'hlsSubtitleTrackLoading', - // fired when a subtitle track loading finishes - data = { details = levelDetails object, id = subtitle track id, stats = { trequest, tfirst, tload, mtime } } + // fired when a subtitle track loading finishes - data: { details : levelDetails object, id : subtitle track id, stats : { trequest, tfirst, tload, mtime } } SUBTITLE_TRACK_LOADED = 'hlsSubtitleTrackLoaded', - // fired when a subtitle fragment has been processed - data = { success = boolean, frag = the processed frag } + // fired when a subtitle fragment has been processed - data: { success : boolean, frag : the processed frag } SUBTITLE_FRAG_PROCESSED = 'hlsSubtitleFragProcessed', - // fired when a set of VTTCues to be managed externally has been parsed - data = { type = string, track = string, cues = [ VTTCue ] } + // fired when a set of VTTCues to be managed externally has been parsed - data: { type: string, track: string, cues: [ VTTCue ] } CUES_PARSED = 'hlsCuesParsed', - // fired when a text track to be managed externally is found - data = { tracks = [ { label = string, kind = string, default = boolean } ] } + // fired when a text track to be managed externally is found - data: { tracks: [ { label: string, kind: string, default: boolean } ] } NON_NATIVE_TEXT_TRACKS_FOUND = 'hlsNonNativeTextTracksFound', - // fired when the first timestamp is found - data = { id = demuxer id, initPTS = initPTS, frag = fragment object } + // fired when the first timestamp is found - data: { id : demuxer id, initPTS: initPTS, frag : fragment object } INIT_PTS_FOUND = 'hlsInitPtsFound', - // fired when a fragment loading starts - data = { frag = fragment object } + // fired when a fragment loading starts - data: { frag : fragment object } FRAG_LOADING = 'hlsFragLoading', - // fired when a fragment loading is progressing - data = { frag = fragment object, { trequest, tfirst, loaded } } - FRAG_LOAD_PROGRESS = 'hlsFragLoadProgress', - // Identifier for fragment load aborting for emergency switch down - data = { frag = fragment object } + // fired when a fragment loading is progressing - data: { frag : fragment object, { trequest, tfirst, loaded } } + // FRAG_LOAD_PROGRESS = 'hlsFragLoadProgress', + // Identifier for fragment load aborting for emergency switch down - data: { frag : fragment object } FRAG_LOAD_EMERGENCY_ABORTED = 'hlsFragLoadEmergencyAborted', - // fired when a fragment loading is completed - data = { frag = fragment object, payload = fragment payload, stats = { trequest, tfirst, tload, length } } + // fired when a fragment loading is completed - data: { frag : fragment object, payload : fragment payload, stats : { trequest, tfirst, tload, length } } FRAG_LOADED = 'hlsFragLoaded', - // fired when a fragment has finished decrypting - data = { id = demuxer id, frag = fragment object, payload = fragment payload, stats = { tstart, tdecrypt } } + // fired when a fragment has finished decrypting - data: { id : demuxer id, frag: fragment object, payload : fragment payload, stats : { tstart, tdecrypt } } FRAG_DECRYPTED = 'hlsFragDecrypted', - // fired when Init Segment has been extracted from fragment - data = { id = demuxer id, frag = fragment object, moov = moov MP4 box, codecs = codecs found while parsing fragment } + // fired when Init Segment has been extracted from fragment - data: { id : demuxer id, frag: fragment object, moov : moov MP4 box, codecs : codecs found while parsing fragment } FRAG_PARSING_INIT_SEGMENT = 'hlsFragParsingInitSegment', - // fired when parsing sei text is completed - data = { id = demuxer id, frag = fragment object, samples = [ sei samples pes ] } + // fired when parsing sei text is completed - data: { id : demuxer id, frag: fragment object, samples : [ sei samples pes ] } FRAG_PARSING_USERDATA = 'hlsFragParsingUserdata', - // fired when parsing id3 is completed - data = { id = demuxer id, frag = fragment object, samples = [ id3 samples pes ] } + // fired when parsing id3 is completed - data: { id : demuxer id, frag: fragment object, samples : [ id3 samples pes ] } FRAG_PARSING_METADATA = 'hlsFragParsingMetadata', - // fired when data have been extracted from fragment - data = { id = demuxer id, frag = fragment object, data1 = moof MP4 box or TS fragments, data2 = mdat MP4 box or null} - FRAG_PARSING_DATA = 'hlsFragParsingData', - // fired when fragment parsing is completed - data = { id = demuxer id, frag = fragment object } + // fired when data have been extracted from fragment - data: { id : demuxer id, frag: fragment object, data1 : moof MP4 box or TS fragments, data2 : mdat MP4 box or null} + // FRAG_PARSING_DATA = 'hlsFragParsingData', + // fired when fragment parsing is completed - data: { id : demuxer id, frag: fragment object } FRAG_PARSED = 'hlsFragParsed', - // fired when fragment remuxed MP4 boxes have all been appended into SourceBuffer - data = { id = demuxer id, frag = fragment object, stats = { trequest, tfirst, tload, tparsed, tbuffered, length, bwEstimate } } + // fired when fragment remuxed MP4 boxes have all been appended into SourceBuffer - data: { id : demuxer id, frag : fragment object, stats : { trequest, tfirst, tload, tparsed, tbuffered, length, bwEstimate } } FRAG_BUFFERED = 'hlsFragBuffered', - // fired when fragment matching with current media position is changing - data = { id = demuxer id, frag = fragment object } + // fired when fragment matching with current media position is changing - data : { id : demuxer id, frag : fragment object } FRAG_CHANGED = 'hlsFragChanged', - // Identifier for a FPS drop event - data = { curentDropped, currentDecoded, totalDroppedFrames } + // Identifier for a FPS drop event - data: { curentDropped, currentDecoded, totalDroppedFrames } FPS_DROP = 'hlsFpsDrop', - // triggered when FPS drop triggers auto level capping - data = { level, droppedlevel } + // triggered when FPS drop triggers auto level capping - data: { level, droppedlevel } FPS_DROP_LEVEL_CAPPING = 'hlsFpsDropLevelCapping', - // Identifier for an error event - data = { type = error type, details = error details, fatal = if true, hls.js cannot/will not try to recover, if false, hls.js will try to recover,other error specific data } + // Identifier for an error event - data: { type : error type, details : error details, fatal : if true, hls.js cannot/will not try to recover, if false, hls.js will try to recover,other error specific data } ERROR = 'hlsError', - // fired when hls.js instance starts destroying. Different from MEDIA_DETACHED as one could want to detach and reattach a media to the instance of hls.js to handle mid-rolls for example - data = { } + // fired when hls.js instance starts destroying. Different from MEDIA_DETACHED as one could want to detach and reattach a media to the instance of hls.js to handle mid-rolls for example - data: { } DESTROYING = 'hlsDestroying', - // fired when a decrypt key loading starts - data = { frag = fragment object } + // fired when a decrypt key loading starts - data: { frag : fragment object } KEY_LOADING = 'hlsKeyLoading', - // fired when a decrypt key loading is completed - data = { frag = fragment object, payload = key payload, stats = { trequest, tfirst, tload, length } } + // fired when a decrypt key loading is completed - data: { frag : fragment object, payload : key payload, stats : { trequest, tfirst, tload, length } } KEY_LOADED = 'hlsKeyLoaded', // fired when the live back buffer is reached defined by the liveBackBufferLength config option - data : { bufferEnd: number } - LIVE_BACK_BUFFER_REACHED = 'hlsLiveBackBufferReached' + LIVE_BACK_BUFFER_REACHED = 'hlsLiveBackBufferReached', +} + +export interface HlsListeners { + [Events.MEDIA_ATTACHING]: (event: Events.MEDIA_ATTACHING, data: MediaAttachingData) => void + [Events.MEDIA_ATTACHED]: (event: Events.MEDIA_ATTACHED, data: MediaAttachedData) => void + [Events.MEDIA_DETACHING]: (event: Events.MEDIA_DETACHING) => void + [Events.MEDIA_DETACHED]: (event: Events.MEDIA_DETACHED) => void + [Events.BUFFER_RESET]: (event: Events.BUFFER_RESET) => void + [Events.BUFFER_CODECS]: (event: Events.BUFFER_CODECS, data: BufferCodecsData) => void + [Events.BUFFER_CREATED]: (event: Events.BUFFER_CREATED, data: BufferCreatedData) => void + [Events.BUFFER_APPENDING]: (event: Events.BUFFER_APPENDING, data: BufferAppendingData) => void + [Events.BUFFER_APPENDED]: (event: Events.BUFFER_APPENDED, data: BufferAppendedData) => void + [Events.BUFFER_EOS]: (event: Events.BUFFER_EOS, data: BufferEOSData) => void + [Events.BUFFER_FLUSHING]: (event: Events.BUFFER_FLUSHING, data: BufferFlushingData) => void + [Events.BUFFER_FLUSHED]: (event: Events.BUFFER_FLUSHED) => void + [Events.MANIFEST_LOADING]: (event: Events.MANIFEST_LOADING, data: ManifestLoadingData) => void + [Events.MANIFEST_LOADED]: (event: Events.MANIFEST_LOADED, data: ManifestLoadedData) => void + [Events.MANIFEST_PARSED]: (event: Events.MANIFEST_PARSED, data: ManifestParsedData) => void + [Events.LEVEL_SWITCHING]: (event: Events.LEVEL_SWITCHING, data: LevelSwitchingData) => void + [Events.LEVEL_SWITCHED]: (event: Events.LEVEL_SWITCHED, data: LevelSwitchedData) => void + [Events.LEVEL_LOADING]: (event: Events.LEVEL_LOADING, data: LevelLoadingData) => void + [Events.LEVEL_LOADED]: (event: Events.LEVEL_LOADED, data: LevelLoadedData) => void + [Events.LEVEL_UPDATED]: (event: Events.LEVEL_UPDATED, data: LevelUpdatedData) => void + [Events.LEVEL_PTS_UPDATED]: (event: Events.LEVEL_PTS_UPDATED, data: LevelPTSUpdatedData) => void + [Events.LEVELS_UPDATED]: (event: Events.LEVELS_UPDATED, data: LevelsUpdatedData) => void + [Events.AUDIO_TRACKS_UPDATED]: (event: Events.AUDIO_TRACKS_UPDATED, data: AudioTracksUpdatedData) => void + [Events.AUDIO_TRACK_SWITCHING]: (event: Events.AUDIO_TRACK_SWITCHING, data: AudioTrackSwitchingData) => void + [Events.AUDIO_TRACK_SWITCHED]: (event: Events.AUDIO_TRACK_SWITCHED, data: AudioTrackSwitchedData) => void + [Events.AUDIO_TRACK_LOADING]: (event: Events.AUDIO_TRACK_LOADING, data: AudioTrackLoadingData) => void + [Events.AUDIO_TRACK_LOADED]: (event: Events.AUDIO_TRACK_LOADED, data: AudioTrackLoadedData) => void + [Events.SUBTITLE_TRACKS_UPDATED]: (event: Events.SUBTITLE_TRACKS_UPDATED, data: SubtitleTracksUpdatedData) => void + [Events.SUBTITLE_TRACKS_CLEARED]: (event: Events.SUBTITLE_TRACKS_CLEARED) => void + [Events.SUBTITLE_TRACK_SWITCH]: (event: Events.SUBTITLE_TRACK_SWITCH, data: SubtitleTrackSwitchData) => void + [Events.SUBTITLE_TRACK_LOADING]: (event: Events.SUBTITLE_TRACK_LOADING, data: SubtitleTrackLoadingData) => void + [Events.SUBTITLE_TRACK_LOADED]: (event: Events.SUBTITLE_TRACK_LOADED, data: SubtitleTrackLoadedData) => void + [Events.SUBTITLE_FRAG_PROCESSED]: (event: Events.SUBTITLE_FRAG_PROCESSED, data: SubtitleFragProcessedData) => void + [Events.CUES_PARSED]: (event: Events.CUES_PARSED, data: CuesParsedData) => void + [Events.NON_NATIVE_TEXT_TRACKS_FOUND]: (event: Events.NON_NATIVE_TEXT_TRACKS_FOUND, data: NonNativeTextTracksData) => void + [Events.INIT_PTS_FOUND]: (event: Events.INIT_PTS_FOUND, data: InitPTSFoundData) => void + [Events.FRAG_LOADING]: (event: Events.FRAG_LOADING, data: FragLoadingData) => void + // [Events.FRAG_LOAD_PROGRESS]: TodoEventType + [Events.FRAG_LOAD_EMERGENCY_ABORTED]: (event: Events.FRAG_LOAD_EMERGENCY_ABORTED, data: FragLoadEmergencyAbortedData) => void + [Events.FRAG_LOADED]: (event: Events.FRAG_LOADED, data: FragLoadedData) => void + [Events.FRAG_DECRYPTED]: (event: Events.FRAG_DECRYPTED, data: FragDecryptedData) => void + [Events.FRAG_PARSING_INIT_SEGMENT]: (event: Events.FRAG_PARSING_INIT_SEGMENT, data: FragParsingInitSegmentData) => void + [Events.FRAG_PARSING_USERDATA]: (event: Events.FRAG_PARSING_USERDATA, data: FragParsingUserdataData) => void + [Events.FRAG_PARSING_METADATA]: (event: Events.FRAG_PARSING_METADATA, data: FragParsingMetadataData) => void + // [Events.FRAG_PARSING_DATA]: TodoEventType + [Events.FRAG_PARSED]: (event: Events.FRAG_PARSED, data: FragParsedData) => void + [Events.FRAG_BUFFERED]: (event: Events.FRAG_BUFFERED, data: FragBufferedData) => void + [Events.FRAG_CHANGED]: (event: Events.FRAG_CHANGED, data: FragChangedData) => void + [Events.FPS_DROP]: (event: Events.FPS_DROP, data: FPSDropData) => void + [Events.FPS_DROP_LEVEL_CAPPING]: (event: Events.FPS_DROP_LEVEL_CAPPING, data: FPSDropLevelCappingData) => void + [Events.ERROR]: (event: Events.ERROR, data: ErrorData) => void + [Events.DESTROYING]: (event: Events.DESTROYING) => void + [Events.KEY_LOADING]: (event: Events.KEY_LOADING, data: KeyLoadingData) => void + [Events.KEY_LOADED]: (event: Events.KEY_LOADED, data: KeyLoadedData) => void + [Events.LIVE_BACK_BUFFER_REACHED]: (event: Events.LIVE_BACK_BUFFER_REACHED, data: LiveBackBufferData) => void } +export interface HlsEventEmitter { + on (event: E, listener: HlsListeners[E], context?: Context): void + once (event: E, listener: HlsListeners[E], context?: Context): void -export default HlsEvents; + removeAllListeners (event?: E): void + off (event: E, listener?: HlsListeners[E], context?: Context, once?: boolean): void + + listeners (event: E): HlsListeners[E][] + emit (event: E, name: E, ...args: Tail>): boolean + listenerCount (event: E): number +} diff --git a/src/hls.ts b/src/hls.ts index ca83a1a9730..f0bc0a35e82 100644 --- a/src/hls.ts +++ b/src/hls.ts @@ -16,31 +16,40 @@ import { isSupported } from './is-supported'; import { logger, enableLogs } from './utils/logger'; import { HlsConfig, hlsDefaultConfig, mergeConfig, setStreamingMode } from './config'; -import HlsEvents from './events'; - -import { Observer } from './observer'; +import { Events, HlsEventEmitter, HlsListeners } from './events'; +import { EventEmitter } from 'eventemitter3'; import { Level } from './types/level'; import { MediaPlaylist } from './types/media-playlist'; +import AudioTrackController from './controller/audio-track-controller'; +import SubtitleTrackController from './controller/subtitle-track-controller'; +import EMEController from './controller/eme-controller'; +import CapLevelController from './controller/cap-level-controller'; +import AbrController from './controller/abr-controller'; +import { ComponentAPI, NetworkComponentAPI } from './types/component-api'; +import { Tail } from './types/tuples'; /** * @module Hls * @class * @constructor */ -export default class Hls extends Observer { +export default class Hls { public static defaultConfig?: HlsConfig; public config: HlsConfig; + private coreComponents: ComponentAPI[]; + private networkControllers: NetworkComponentAPI[]; + + private _emitter: HlsEventEmitter = new EventEmitter(); private _autoLevelCapping: number; - private abrController: any; - private capLevelController: any; - private levelController: any; - private streamController: any; - private networkControllers: any[]; - private audioTrackController: any; - private subtitleTrackController: any; - private emeController: any; - private coreComponents: any[]; + private abrController: AbrController; + private capLevelController: CapLevelController; + private levelController: LevelController; + private streamController: StreamController; + private audioTrackController: AudioTrackController; + private subtitleTrackController: SubtitleTrackController; + private emeController: EMEController; + private _media: HTMLMediaElement | null = null; private url: string | null = null; @@ -53,7 +62,7 @@ export default class Hls extends Observer { } static get Events () { - return HlsEvents; + return Events; } static get ErrorTypes () { @@ -86,8 +95,6 @@ export default class Hls extends Observer { * @param {HlsConfig} config */ constructor (userConfig: Partial = {}) { - super(); - const defaultConfig = Hls.DefaultConfig; mergeConfig(defaultConfig, userConfig); const config = this.config = userConfig as HlsConfig; @@ -120,6 +127,8 @@ export default class Hls extends Observer { // Cap level controller uses streamController to flush the buffer capLevelController.setStreamController(streamController); + // fpsController uses streamController to switch when frames are being dropped + fpsController.setStreamController(streamController); const networkControllers = [ levelController, @@ -159,12 +168,75 @@ export default class Hls extends Observer { return null; } + // Delegate the EventEmitter through the public API of Hls.js + on (event: E, listener: HlsListeners[E], context: Context | this = this) { + this._emitter.on(event, (...args: unknown[]) => { + if (this.config.debug) { + listener.apply(context, args); + } else { + try { + listener.apply(context, args); + } catch (e) { + logger.error('An internal error happened while handling event ' + event + '. Error message: "' + e.message + '". Here is a stacktrace:', e); + this.trigger(Events.ERROR, { + type: ErrorTypes.OTHER_ERROR, + details: ErrorDetails.INTERNAL_EXCEPTION, + fatal: false, + event: event, + error: e + }); + } + } + }, context); + } + + once (event: E, listener: HlsListeners[E], context: Context | this = this) { + this._emitter.once(event, (...args: unknown[]) => { + if (this.config.debug) { + listener.apply(context, args); + } else { + try { + listener.apply(context, args); + } catch (e) { + logger.error('An internal error happened while handling event ' + event + '. Error message: "' + e.message + '". Here is a stacktrace:', e); + this.trigger(Events.ERROR, { + type: ErrorTypes.OTHER_ERROR, + details: ErrorDetails.INTERNAL_EXCEPTION, + fatal: false, + event: event, + error: e + }); + } + } + }, context); + } + + removeAllListeners (event?: E | undefined) { + this._emitter.removeAllListeners(event); + } + + off (event: E, listener?: HlsListeners[E] | undefined, context?: Context, once?: boolean | undefined) { + this._emitter.off(event, listener, context, once); + } + + listeners (event: E): HlsListeners[E][] { + return this._emitter.listeners(event); + } + + trigger (event: E, ...args: Tail>): boolean { + return this._emitter.emit(event, event, ...args); + } + + listenerCount (event: E): number { + return this._emitter.listenerCount(event); + } + /** * Dispose of the instance */ destroy () { logger.log('destroy'); - this.trigger(HlsEvents.DESTROYING); + this.trigger(Events.DESTROYING); this.detachMedia(); this.coreComponents.concat(this.networkControllers).forEach(component => { component.destroy(); @@ -181,7 +253,7 @@ export default class Hls extends Observer { attachMedia (media: HTMLMediaElement) { logger.log('attachMedia'); this._media = media; - this.trigger(HlsEvents.MEDIA_ATTACHING, { media: media }); + this.trigger(Events.MEDIA_ATTACHING, { media: media }); } /** @@ -189,7 +261,7 @@ export default class Hls extends Observer { */ detachMedia () { logger.log('detachMedia'); - this.trigger(HlsEvents.MEDIA_DETACHING); + this.trigger(Events.MEDIA_DETACHING); this._media = null; } @@ -202,7 +274,7 @@ export default class Hls extends Observer { logger.log(`loadSource:${url}`); this.url = url; // when attaching to a source URL, trigger a playlist load - this.trigger(HlsEvents.MANIFEST_LOADING, { url: url }); + this.trigger(Events.MANIFEST_LOADING, { url: url }); } /** @@ -260,7 +332,7 @@ export default class Hls extends Observer { * @type {Level[]} */ get levels (): Array { - return this.levelController.levels; + return this.levelController.levels ? this.levelController.levels : []; } /** @@ -419,7 +491,7 @@ export default class Hls extends Observer { * @type {number} */ get bandwidthEstimate (): number { - return this.abrController._bwEstimator.getEstimate(); + return this.abrController.bwEstimator.getEstimate(); } /** @@ -455,8 +527,9 @@ export default class Hls extends Observer { */ get minAutoLevel (): number { const { levels, config: { minAutoBitrate } } = this; - const len = levels ? levels.length : 0; + if (!levels) return 0; + const len = levels.length; for (let i = 0; i < len; i++) { if (levels[i].maxBitrate > minAutoBitrate) { return i; @@ -535,7 +608,7 @@ export default class Hls extends Observer { /** * @type {Seconds} */ - get liveSyncPosition (): number { + get liveSyncPosition (): number | null { return this.streamController.liveSyncPosition; } diff --git a/src/loader/fragment.ts b/src/loader/fragment.ts index e062e685ebc..b975bf047da 100644 --- a/src/loader/fragment.ts +++ b/src/loader/fragment.ts @@ -206,7 +206,7 @@ export default class Fragment { setDecryptDataFromLevelKey (levelkey: LevelKey, segmentNumber: number): LevelKey { let decryptdata = levelkey; - if (levelkey && levelkey.method && levelkey.uri && !levelkey.iv) { + if (levelkey?.method && levelkey.uri && !levelkey.iv) { decryptdata = new LevelKey(levelkey.baseuri, levelkey.reluri); decryptdata.method = levelkey.method; decryptdata.iv = this.createInitializationVector(segmentNumber); diff --git a/src/loader/key-loader.ts b/src/loader/key-loader.ts index 963185bac8a..74dfadeb9be 100644 --- a/src/loader/key-loader.ts +++ b/src/loader/key-loader.ts @@ -1,33 +1,41 @@ /* * Decrypt key Loader */ - -import Event from '../events'; -import EventHandler from '../event-handler'; +import { Events } from '../events'; import { ErrorTypes, ErrorDetails } from '../errors'; import { logger } from '../utils/logger'; import Hls from '../hls'; import Fragment from './fragment'; import { LoaderStats, LoaderResponse, LoaderContext, LoaderConfiguration, LoaderCallbacks } from '../types/loader'; - -interface OnKeyLoadingPayload { - frag: Fragment -} +import { ComponentAPI } from '../types/component-api'; +import { KeyLoadingData } from '../types/events'; interface KeyLoaderContext extends LoaderContext { frag: Fragment } -export default class KeyLoader extends EventHandler { +export default class KeyLoader implements ComponentAPI { + private hls: Hls; public loaders = {}; public decryptkey: Uint8Array | null = null; public decrypturl: string | null = null; constructor (hls: Hls) { - super(hls, Event.KEY_LOADING); + this.hls = hls; + + this._registerListeners(); + } + + private _registerListeners () { + this.hls.on(Events.KEY_LOADING, this.onKeyLoading, this); + } + + private _unregisterListeners () { + this.hls.off(Events.KEY_LOADING, this.onKeyLoading); } destroy (): void { + this._unregisterListeners(); for (const loaderName in this.loaders) { const loader = this.loaders[loaderName]; if (loader) { @@ -35,11 +43,9 @@ export default class KeyLoader extends EventHandler { } } this.loaders = {}; - - super.destroy(); } - onKeyLoading (data: OnKeyLoadingPayload) { + onKeyLoading (event: Events.KEY_LOADING, data: KeyLoadingData) { const { frag } = data; const type = frag.type; const loader = this.loaders[type]; @@ -92,7 +98,7 @@ export default class KeyLoader extends EventHandler { } else if (this.decryptkey) { // Return the key if it's already been loaded frag.decryptdata.key = this.decryptkey; - this.hls.trigger(Event.KEY_LOADED, { frag: frag }); + this.hls.trigger(Events.KEY_LOADED, { frag: frag }); } } @@ -107,7 +113,7 @@ export default class KeyLoader extends EventHandler { // detach fragment loader on load success frag.loader = undefined; delete this.loaders[frag.type]; - this.hls.trigger(Event.KEY_LOADED, { frag: frag }); + this.hls.trigger(Events.KEY_LOADED, { frag: frag }); } loaderror (response: LoaderResponse, context: KeyLoaderContext) { @@ -118,7 +124,7 @@ export default class KeyLoader extends EventHandler { } delete this.loaders[frag.type]; - this.hls.trigger(Event.ERROR, { type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.KEY_LOAD_ERROR, fatal: false, frag, response }); + this.hls.trigger(Events.ERROR, { type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.KEY_LOAD_ERROR, fatal: false, frag, response }); } loadtimeout (stats: LoaderStats, context: KeyLoaderContext) { @@ -129,6 +135,6 @@ export default class KeyLoader extends EventHandler { } delete this.loaders[frag.type]; - this.hls.trigger(Event.ERROR, { type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.KEY_LOAD_TIMEOUT, fatal: false, frag }); + this.hls.trigger(Events.ERROR, { type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.KEY_LOAD_TIMEOUT, fatal: false, frag }); } } diff --git a/src/loader/m3u8-parser.ts b/src/loader/m3u8-parser.ts index 7aaaf3ee9d6..82f59a7eefc 100644 --- a/src/loader/m3u8-parser.ts +++ b/src/loader/m3u8-parser.ts @@ -394,7 +394,7 @@ function backfillProgramDateTimes (fragments, startIndex) { function assignProgramDateTime (frag, prevFrag) { if (frag.rawProgramDateTime) { frag.programDateTime = Date.parse(frag.rawProgramDateTime); - } else if (prevFrag && prevFrag.programDateTime) { + } else if (prevFrag?.programDateTime) { frag.programDateTime = prevFrag.endProgramDateTime; } diff --git a/src/loader/playlist-loader.ts b/src/loader/playlist-loader.ts index af3a3b79b42..0867fe443aa 100644 --- a/src/loader/playlist-loader.ts +++ b/src/loader/playlist-loader.ts @@ -9,8 +9,7 @@ * */ -import Event from '../events'; -import EventHandler from '../event-handler'; +import { Events } from '../events'; import { ErrorTypes, ErrorDetails } from '../errors'; import { logger } from '../utils/logger'; import { parseSegmentIndex } from '../utils/mp4-tools'; @@ -25,9 +24,10 @@ import { PlaylistLevelType, PlaylistLoaderContext } from '../types/loader'; -import { ManifestLoadingData, LevelLoadingData, TrackLoadingData } from '../types/events'; +import { ManifestLoadingData, LevelLoadingData, AudioTrackLoadingData, SubtitleTrackLoadingData } from '../types/events'; import LevelDetails from './level-details'; import Fragment from './fragment'; +import Hls from '../hls'; const { performance } = self; @@ -72,20 +72,35 @@ function getResponseUrl (response: LoaderResponse, context: PlaylistLoaderContex /** * @constructor */ -class PlaylistLoader extends EventHandler { - private readonly loaders: { [key: string]: Loader }; +class PlaylistLoader { + private readonly hls: Hls; + private readonly loaders: { + [key: string]: Loader + } = Object.create(null) + /** * @constructs * @param {Hls} hls */ - constructor (hls) { - super(hls, - Event.MANIFEST_LOADING, - Event.LEVEL_LOADING, - Event.AUDIO_TRACK_LOADING, - Event.SUBTITLE_TRACK_LOADING); - - this.loaders = Object.create(null); + constructor (hls: Hls) { + this.hls = hls; + this._registerListeners(); + } + + private _registerListeners () { + const { hls } = this; + hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this); + hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this); + hls.on(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this); + hls.on(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this); + } + + private _unregisterListeners () { + const { hls } = this; + hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this); + hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this); + hls.off(Events.AUDIO_TRACK_LOADING, this.onAudioTrackLoading, this); + hls.off(Events.SUBTITLE_TRACK_LOADING, this.onSubtitleTrackLoading, this); } // TODO: export as enum once fragment-tracker and stream-controller typed @@ -135,12 +150,11 @@ class PlaylistLoader extends EventHandler { } public destroy (): void { + this._unregisterListeners(); this.destroyInternalLoaders(); - - super.destroy(); } - protected onManifestLoading (data: ManifestLoadingData): void { + private onManifestLoading (event: Events.MANIFEST_LOADING, data: ManifestLoadingData) { const { url } = data; this.load({ id: null, @@ -151,7 +165,7 @@ class PlaylistLoader extends EventHandler { }); } - protected onLevelLoading (data: LevelLoadingData): void { + private onLevelLoading (event: Events.LEVEL_LOADING, data: LevelLoadingData) { const { id, level, url } = data; this.load({ id, @@ -162,7 +176,7 @@ class PlaylistLoader extends EventHandler { }); } - protected onAudioTrackLoading (data: TrackLoadingData): void { + private onAudioTrackLoading (event: Events.AUDIO_TRACK_LOADING, data: AudioTrackLoadingData) { const { id, url } = data; this.load({ id, @@ -173,7 +187,7 @@ class PlaylistLoader extends EventHandler { }); } - protected onSubtitleTrackLoading (data: TrackLoadingData): void { + private onSubtitleTrackLoading (event: Events.SUBTITLE_TRACK_LOADING, data: SubtitleTrackLoadingData) { const { id, url } = data; this.load({ id, @@ -335,7 +349,7 @@ class PlaylistLoader extends EventHandler { } } - hls.trigger(Event.MANIFEST_LOADED, { + hls.trigger(Events.MANIFEST_LOADED, { levels, audioTracks, subtitles, @@ -368,13 +382,13 @@ class PlaylistLoader extends EventHandler { levelDetails.lastModified = Math.max(+(mtime as Date), +(encoded as Date)); if (!levelDetails.fragments.length) { - hls.trigger(Event.ERROR, { + hls.trigger(Events.ERROR, { type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.LEVEL_EMPTY_ERROR, fatal: false, url: url, reason: 'no fragments found in level', - level: context.level + level: typeof context.level === 'number' ? context.level : undefined }); return; } @@ -392,7 +406,7 @@ class PlaylistLoader extends EventHandler { url }; - hls.trigger(Event.MANIFEST_LOADED, { + hls.trigger(Events.MANIFEST_LOADED, { levels: [singleLevel], audioTracks: [], url, @@ -449,7 +463,7 @@ class PlaylistLoader extends EventHandler { } private _handleManifestParsingError (response: LoaderResponse, context, reason, networkDetails): void { - this.hls.trigger(Event.ERROR, { + this.hls.trigger(Events.ERROR, { type: ErrorTypes.NETWORK_ERROR, details: ErrorDetails.MANIFEST_PARSING_ERROR, fatal: context.type === PlaylistContextType.MANIFEST, @@ -505,7 +519,7 @@ class PlaylistLoader extends EventHandler { errorData.response = response; } - this.hls.trigger(Event.ERROR, errorData); + this.hls.trigger(Events.ERROR, errorData); } private _handlePlaylistLoaded (response: LoaderResponse, stats: LoaderStats, context, networkDetails): void { @@ -518,7 +532,7 @@ class PlaylistLoader extends EventHandler { const canHaveLevels = canHaveQualityLevels(context.type); if (canHaveLevels) { - this.hls.trigger(Event.LEVEL_LOADED, { + this.hls.trigger(Events.LEVEL_LOADED, { details: levelDetails, level: level || 0, id: id || 0, @@ -528,7 +542,7 @@ class PlaylistLoader extends EventHandler { } else { switch (type) { case PlaylistContextType.AUDIO_TRACK: - this.hls.trigger(Event.AUDIO_TRACK_LOADED, { + this.hls.trigger(Events.AUDIO_TRACK_LOADED, { details: levelDetails, id, stats, @@ -536,7 +550,7 @@ class PlaylistLoader extends EventHandler { }); break; case PlaylistContextType.SUBTITLE_TRACK: - this.hls.trigger(Event.SUBTITLE_TRACK_LOADED, { + this.hls.trigger(Events.SUBTITLE_TRACK_LOADED, { details: levelDetails, id, stats, diff --git a/src/observer.ts b/src/observer.ts deleted file mode 100644 index 33d265eb752..00000000000 --- a/src/observer.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { EventEmitter } from 'eventemitter3'; - -/** - * Simple adapter sub-class of Nodejs-like EventEmitter. - */ -export class Observer extends EventEmitter { - /** - * We simply want to pass along the event-name itself - * in every call to a handler, which is the purpose of our `trigger` method - * extending the standard API. - */ - trigger (event: string, ...data: Array): void { - this.emit(event, event, ...data); - } -} diff --git a/src/performance/performance-monitor.ts b/src/performance/performance-monitor.ts index 507235c1d38..74d05fead95 100644 --- a/src/performance/performance-monitor.ts +++ b/src/performance/performance-monitor.ts @@ -7,20 +7,25 @@ * TODO: Add this to the demo page or a performance test page */ -import EventHandler from '../event-handler'; -import Events from '../events'; +import { Events } from '../events'; import Fragment from '../loader/fragment'; import { logger } from '../utils/logger'; +import Hls from '../hls'; +import { FragBufferedData } from '../types/events'; -export default class PerformanceMonitor extends EventHandler { - constructor (hls) { - super(hls, - Events.FRAG_BUFFERED - ); +export default class PerformanceMonitor { + private hls: Hls; + + constructor (hls: Hls) { this.hls = hls; + this.hls.on(Events.FRAG_BUFFERED, this.onFragBuffered); + } + + destroy () { + this.hls.off(Events.FRAG_BUFFERED); } - onFragBuffered (data: { frag: Fragment }) { + onFragBuffered (event: Events.FRAG_BUFFERED, data: FragBufferedData) { logFragStats(data.frag); } } @@ -35,7 +40,7 @@ function logFragStats (frag: Fragment) { logger.log(`[performance-monitor]: Stats for fragment ${frag.sn} of level ${frag.level}: Size: ${((stats.total / 1024)).toFixed(3)} kB Chunk Count: ${stats.chunkCount} - + Request: ${stats.loading.start.toFixed(3)} ms First Byte: ${stats.loading.first.toFixed(3)} ms Parse Start ${stats.parsing.start.toFixed(3)} ms diff --git a/src/polyfills/number-isFinite.js b/src/polyfills/number-isFinite.ts similarity index 100% rename from src/polyfills/number-isFinite.js rename to src/polyfills/number-isFinite.ts diff --git a/src/remux/mp4-generator.js b/src/remux/mp4-generator.ts similarity index 96% rename from src/remux/mp4-generator.js rename to src/remux/mp4-generator.ts index 70800f9857a..1858745a97e 100644 --- a/src/remux/mp4-generator.js +++ b/src/remux/mp4-generator.ts @@ -2,9 +2,26 @@ * Generate MP4 Box */ +type HdlrTypes = { + video: Uint8Array, + audio: Uint8Array +} + const UINT32_MAX = Math.pow(2, 32) - 1; class MP4 { + public static types: Record; + private static HDLR_TYPES: HdlrTypes; + private static STTS: Uint8Array; + private static STSC: Uint8Array; + private static STCO: Uint8Array; + private static STSZ: Uint8Array; + private static VMHD: Uint8Array; + private static SMHD: Uint8Array; + private static STSD: Uint8Array; + private static FTYP: Uint8Array; + private static DINF: Uint8Array; + static init () { MP4.types = { avc1: [], // codingname @@ -45,7 +62,7 @@ class MP4 { smhd: [] }; - let i; + let i: string; for (i in MP4.types) { if (MP4.types.hasOwnProperty(i)) { MP4.types[i] = [ @@ -140,8 +157,7 @@ class MP4 { MP4.DINF = MP4.box(MP4.types.dinf, MP4.box(MP4.types.dref, dref)); } - static box (type) { - const payload = Array.prototype.slice.call(arguments, 1); + static box (type, ...payload: Uint8Array[]) { let size = 8; let i = payload.length; const len = i; @@ -231,7 +247,7 @@ class MP4 { */ static moov (tracks) { let i = tracks.length; - const boxes = []; + const boxes: Uint8Array[] = []; while (i--) { boxes[i] = MP4.trak(tracks[i]); @@ -242,13 +258,13 @@ class MP4 { static mvex (tracks) { let i = tracks.length; - const boxes = []; + const boxes: Uint8Array[] = []; while (i--) { boxes[i] = MP4.trex(tracks[i]); } - return MP4.box.apply(null, [MP4.types.mvex].concat(boxes)); + return MP4.box.apply(null, [MP4.types.mvex, ...boxes]); } static mvhd (timescale, duration) { @@ -320,8 +336,8 @@ class MP4 { } static avc1 (track) { - let sps = []; - let pps = []; + let sps: number[] = []; + let pps: number[] = []; let i; let data; let len; diff --git a/src/remux/mp4-remuxer.ts b/src/remux/mp4-remuxer.ts index 7c988074758..fe96f92c782 100644 --- a/src/remux/mp4-remuxer.ts +++ b/src/remux/mp4-remuxer.ts @@ -1,6 +1,6 @@ import AAC from './aac-helper'; import MP4 from './mp4-generator'; -import Event from '../events'; +import { Events } from '../events'; import { ErrorTypes, ErrorDetails } from '../errors'; import { logger } from '../utils/logger'; import { InitSegmentData, Remuxer, RemuxerResult, RemuxedMetadata, RemuxedTrack } from '../types/remuxer'; @@ -334,7 +334,7 @@ export default class MP4Remuxer implements Remuxer { try { mdat = new Uint8Array(mdatSize); } catch (err) { - this.observer.trigger(Event.ERROR, { type: ErrorTypes.MUX_ERROR, details: ErrorDetails.REMUX_ALLOC_ERROR, fatal: false, bytes: mdatSize, reason: `fail allocating video mdat ${mdatSize}` }); + this.observer.trigger(Events.ERROR, { type: ErrorTypes.MUX_ERROR, details: ErrorDetails.REMUX_ALLOC_ERROR, fatal: false, bytes: mdatSize, reason: `fail allocating video mdat ${mdatSize}` }); return; } const view = new DataView(mdat.buffer); @@ -593,7 +593,7 @@ export default class MP4Remuxer implements Remuxer { try { mdat = new Uint8Array(mdatSize); } catch (err) { - this.observer.trigger(Event.ERROR, { + this.observer.trigger(Events.ERROR, { type: ErrorTypes.MUX_ERROR, details: ErrorDetails.REMUX_ALLOC_ERROR, fatal: false, diff --git a/src/task-loop.ts b/src/task-loop.ts index 8a64fc4e941..1848add0548 100644 --- a/src/task-loop.ts +++ b/src/task-loop.ts @@ -1,6 +1,3 @@ -import EventHandler from './event-handler'; -import Hls from './hls'; - /** * Sub-class specialization of EventHandler base class. * @@ -29,27 +26,29 @@ import Hls from './hls'; * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo). */ - -export default class TaskLoop extends EventHandler { +export default class TaskLoop { private readonly _boundTick: () => void; private _tickTimer: number | null = null; private _tickInterval: number | null = null; private _tickCallCount = 0; - constructor (hls: Hls, ...events: string[]) { - super(hls, ...events); + constructor () { this._boundTick = this.tick.bind(this); } - /** - * @override - */ + public destroy () { + this.onHandlerDestroying(); + this.onHandlerDestroyed(); + } + protected onHandlerDestroying () { // clear all timers before unregistering from event bus this.clearNextTick(); this.clearInterval(); } + protected onHandlerDestroyed () {} + /** * @returns {boolean} */ diff --git a/src/types/component-api.ts b/src/types/component-api.ts new file mode 100644 index 00000000000..046c0f29ef3 --- /dev/null +++ b/src/types/component-api.ts @@ -0,0 +1,8 @@ +export interface ComponentAPI { + destroy(): void; +} + +export interface NetworkComponentAPI extends ComponentAPI { + startLoad(startPosition: number): void; + stopLoad(): void; +} diff --git a/src/types/events.ts b/src/types/events.ts index 3c10c3af425..d8f3b6057c9 100644 --- a/src/types/events.ts +++ b/src/types/events.ts @@ -2,10 +2,57 @@ import Fragment from '../loader/fragment'; import LevelDetails from '../loader/level-details'; import { Level, LevelParsed } from './level'; import { MediaPlaylist } from './media-playlist'; -import { LoaderStats } from './loader'; -import { Track } from './track'; +import { LoaderStats, PlaylistLevelType } from './loader'; +import { Track, TrackSet } from './track'; import { SourceBufferName } from './buffer'; import { ChunkMetadata } from './transmuxer'; +import LoadStats from '../loader/load-stats'; +import { ErrorDetails, ErrorTypes } from '../errors'; + +export interface MediaAttachingData { + media: HTMLMediaElement +} + +export interface MediaAttachedData { + media: HTMLMediaElement; +} + +export interface BufferCodecsData { + video?: Track + audio?: Track +} + +export interface BufferCreatedData { + tracks: TrackSet +} + +export interface BufferAppendingData { + type: SourceBufferName; + data: Uint8Array; + frag: Fragment; + chunkMeta: ChunkMetadata +} + +export interface BufferAppendedData { + chunkMeta: ChunkMetadata + frag: Fragment + parent: PlaylistLevelType + timeRanges: { + audio?: TimeRanges + video?: TimeRanges + audiovideo?: TimeRanges + } +} + +export interface BufferEOSData { + type: SourceBufferName +} + +export interface BufferFlushingData { + startOffset: number + endOffset: number + type: SourceBufferName +} export interface ManifestLoadingData { url: string @@ -31,6 +78,14 @@ export interface ManifestParsedData { altAudio: boolean } +export interface LevelSwitchingData extends Level { + level: number; +} + +export interface LevelSwitchedData { + level: any +} + export interface TrackLoadingData { id: number url: string @@ -56,23 +111,63 @@ export interface LevelUpdatedData { level: number } -export interface AudioTracksUpdated { +export interface LevelPTSUpdatedData { + details: any, + level: Level, + drift: number, + type: string, + start: any, + end: any +} + +export interface AudioTrackSwitchingData { + url: any + type: any + id: any +} + +export interface AudioTrackSwitchedData { + id: any +} + +export interface AudioTrackLoadingData { + url: string; + id: number | null; +} + +export interface AudioTrackLoadedData { + details: any; // LevelDetails type? + id: number; + stats: LoaderStats; + networkDetails: unknown; +} + +export interface AudioTracksUpdatedData { audioTracks: MediaPlaylist[] } -export interface SubtitleTracksUpdated { +export interface SubtitleTracksUpdatedData { subtitleTracks: MediaPlaylist[] } -export interface TrackSwitchedData { +export interface SubtitleTrackSwitchData { id: number } -export interface FragLoadedData { - frag: Fragment - networkDetails: any - payload: ArrayBuffer - stats: LoaderStats +export interface SubtitleTrackLoadingData { + url: string; + id: number | null; +} + +export interface SubtitleTrackLoadedData { + details: any; // LevelDetails type? + id: number | null; + stats: LoaderStats; + networkDetails: unknown; +} + +export interface TrackSwitchedData { + id: number } export interface SubtitleFragProcessed { @@ -80,20 +175,24 @@ export interface SubtitleFragProcessed { frag: Fragment } -export interface MediaAttachedData { - media: HTMLVideoElement; +export interface FragChangedData { + frag: any; } -export interface BufferAppendingEventPayload { - type: SourceBufferName; - data: Uint8Array; - frag: Fragment; - chunkMeta: ChunkMetadata +export interface FPSDropData { + currentDropped: number + currentDecoded: number + totalDroppedFrames: number +} + +export interface FPSDropLevelCappingData { + droppedLevel: number + level: number } export interface ErrorData { - type: string // TODO: string enum of ErrorTypes values - details: string // TODO: string enum of ErrorDetails values + type: ErrorTypes + details: ErrorDetails fatal: boolean buffer?: number bytes?: number @@ -104,23 +203,104 @@ export interface ErrorData { level?: number levelRetry?: boolean networkDetails?: any + mimeType?: string reason?: string response?: any url?: string + parent?: PlaylistLevelType + err?: { // comes from transmuxer interface + message: string; + } } -export interface MediaAttachingData { - media: HTMLVideoElement +export interface SubtitleFragProcessedData { + success: boolean + frag: Fragment + error?: Error } -export interface BufferCodecsData { - video: Track +export interface CuesParsedData { + type: 'captions' | 'subtitles', + cues: any, + track: string } -export interface FPSDropLevelCappingData { - droppedLevel: number +interface NonNativeTextTrack { + label: any + kind: string + default: boolean +} + +export interface NonNativeTextTracksData { + tracks: Array +} + +export interface InitPTSFoundData { + id: string + frag: Fragment + initPTS: number +} + +export interface FragLoadingData { + frag: Fragment +} + +export interface FragLoadEmergencyAbortedData { + frag: Fragment + stats: LoaderStats +} + +export interface FragLoadedData { + frag: Fragment + networkDetails: any + payload: ArrayBuffer + stats: LoaderStats +} + +export interface FragDecryptedData { + frag: Fragment + payload: ArrayBuffer + stats: { + tstart: number + tdecrypt: number + } +} + +export interface FragParsingInitSegmentData { + +} + +// TODO: What are samples type? +export interface FragParsingUserdataData { + samples: Array +} + +export interface FragParsingMetadataData { + frag: Fragment +} + +export interface FragParsedData { + frag: Fragment +} + +export interface FragBufferedData { + stats: LoadStats + frag: Fragment + id: string } export interface LevelsUpdatedData { levels: Array } + +export interface KeyLoadingData { + frag: Fragment +} + +export interface KeyLoadedData { + frag: Fragment +} + +export interface LiveBackBufferData { + bufferEnd: number +} diff --git a/src/types/tuples.ts b/src/types/tuples.ts new file mode 100644 index 00000000000..7b11d867ce7 --- /dev/null +++ b/src/types/tuples.ts @@ -0,0 +1,4 @@ +export type Tail = + ((...t: T) => any) extends ((_: any, ...tail: infer U) => any) + ? U + : []; diff --git a/src/utils/buffer-helper.ts b/src/utils/buffer-helper.ts index 0bde46e34dd..a34fde1126c 100644 --- a/src/utils/buffer-helper.ts +++ b/src/utils/buffer-helper.ts @@ -50,7 +50,7 @@ export class BufferHelper { } static bufferInfo ( - media: Bufferable, + media: Bufferable | null, pos: number, maxHoleDuration: number ): BufferInfo { diff --git a/src/utils/chunker.ts b/src/utils/chunker.ts index e05a85ab361..adfb876cbf4 100644 --- a/src/utils/chunker.ts +++ b/src/utils/chunker.ts @@ -13,7 +13,7 @@ export default class Chunker { const result: Array = []; let temp: Uint8Array | null = null; - if (cache && cache.length) { + if (cache?.length) { temp = appendUint8Array(cache, data); this.cache = null; } else { diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 282d6909898..dffab0fe327 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -11,7 +11,7 @@ interface ILogger { error: ILogFunction } -const noop: ILogFunction = function (...args: any[]): void { }; +const noop: ILogFunction = function () {}; const fakeLogger: ILogger = { trace: noop, diff --git a/src/utils/mp4-tools.ts b/src/utils/mp4-tools.ts index 1f6453729a6..8148e6841c6 100644 --- a/src/utils/mp4-tools.ts +++ b/src/utils/mp4-tools.ts @@ -358,7 +358,7 @@ export function getDuration (data, initData) { if (totalDuration === 0) { // If duration samples are not available in the traf use sidx subsegment_duration const sidx = parseSegmentIndex(data); - if (sidx && sidx.references) { + if (sidx?.references) { return sidx.references.reduce((dur, ref) => dur + ref.info.duration || 0, 0); } } diff --git a/src/utils/timescale-conversion.ts b/src/utils/timescale-conversion.ts index 7591545ec6a..e03927946e3 100644 --- a/src/utils/timescale-conversion.ts +++ b/src/utils/timescale-conversion.ts @@ -1,7 +1,7 @@ const MPEG_TS_CLOCK_FREQ_HZ = 90000; export function toTimescaleFromScale (value, destScale: number, srcScale: number = 1, round: boolean = false): number { - return toTimescaleFromBase(value, destScale, 1 / srcScale); + return toTimescaleFromBase(value, destScale, 1 / srcScale, round); } export function toTimescaleFromBase (value, destScale: number, srcBase: number = 1, round: boolean = false): number { diff --git a/tests/functional/issues/617.html b/tests/functional/issues/617.html index a1590663b5f..0a789909213 100644 --- a/tests/functional/issues/617.html +++ b/tests/functional/issues/617.html @@ -23,7 +23,7 @@ enableCEA708Captions: true }); - hls.on(Hls.Events.ERROR, function(event, data) { + hls.on(Hls.Events.ERROR, function(data) { console.warn('ERROR', data); }); diff --git a/tests/unit/controller/audio-stream-controller.js b/tests/unit/controller/audio-stream-controller.js index fb715abddc3..016bb56ff3d 100644 --- a/tests/unit/controller/audio-stream-controller.js +++ b/tests/unit/controller/audio-stream-controller.js @@ -1,5 +1,6 @@ import AudioStreamController from '../../../src/controller/audio-stream-controller'; import Hls from '../../../src/hls'; +import { Events } from '../../../src/events'; describe('AudioStreamController', function () { const tracks = [{ @@ -55,7 +56,7 @@ describe('AudioStreamController', function () { audioStreamController.levels = tracks; audioStreamController.tick = () => {}; - audioStreamController.onAudioTrackLoaded({ + audioStreamController.onAudioTrackLoaded(Events.AUDIO_TRACK_LOADED, { id: 0, details }); diff --git a/tests/unit/controller/audio-track-controller.js b/tests/unit/controller/audio-track-controller.js index 9aac23019d8..0f3082bb94f 100644 --- a/tests/unit/controller/audio-track-controller.js +++ b/tests/unit/controller/audio-track-controller.js @@ -1,5 +1,6 @@ import AudioTrackController from '../../../src/controller/audio-track-controller'; import Hls from '../../../src/hls'; +import { Events } from '../../../src/events'; const sinon = require('sinon'); @@ -62,7 +63,7 @@ describe('AudioTrackController', function () { done(); }); - audioTrackController.onManifestParsed({ + audioTrackController.onManifestParsed(Events.MANIFEST_PARSED, { audioTracks: tracks }); }); @@ -74,7 +75,7 @@ describe('AudioTrackController', function () { done(); }); - audioTrackController.onManifestParsed({ + audioTrackController.onManifestParsed(Events.MANIFEST_PARSED, { audioTracks: null }); }); @@ -96,7 +97,7 @@ describe('AudioTrackController', function () { it('should update the current audioGroupId', function () { audioTrackController.tracks = tracks; audioTrackController.audioGroupId = '2'; - audioTrackController.onAudioTrackSwitched({ + audioTrackController.onAudioTrackSwitched(Events.AUDIO_TRACK_SWITCHED, { id: 1 }); @@ -135,7 +136,7 @@ describe('AudioTrackController', function () { // current track name const audioTrackName = tracks[audioTrackController.audioTrack].name; - audioTrackController.onLevelLoading(levelLoadedEvent); + audioTrackController.onLevelLoading(Events.LEVEL_LOADING, levelLoadedEvent); // group has switched expect(audioTrackController.audioGroupId).to.equal(newGroupId); @@ -165,7 +166,7 @@ describe('AudioTrackController', function () { audioTrackController.tracks = [trackWithUrl]; - audioTrackController.onLevelLoading({ + audioTrackController.onLevelLoading(Events.LEVEL_LOADING, { level: 0 }); @@ -192,7 +193,7 @@ describe('AudioTrackController', function () { audioTrackController.tracks = tracks; - audioTrackController.onLevelLoading({ + audioTrackController.onLevelLoading(Events.LEVEL_LOADING, { level: 0 }); @@ -207,24 +208,24 @@ describe('AudioTrackController', function () { it('should clear interval (only) on fatal network errors', function () { audioTrackController.timer = 1000; - audioTrackController.onError({ + audioTrackController.onError(Events.ERROR, { type: Hls.ErrorTypes.MEDIA_ERROR }); expect(audioTrackController.timer).to.equal(1000); - audioTrackController.onError({ + audioTrackController.onError(Events.ERROR, { type: Hls.ErrorTypes.MEDIA_ERROR, fatal: true }); expect(audioTrackController.timer).to.equal(1000); - audioTrackController.onError({ + audioTrackController.onError(Events.ERROR, { type: Hls.ErrorTypes.NETWORK_ERROR, fatal: false }); expect(audioTrackController.timer).to.equal(1000); - audioTrackController.onError({ + audioTrackController.onError(Events.ERROR, { type: Hls.ErrorTypes.NETWORK_ERROR, fatal: true }); @@ -237,19 +238,19 @@ describe('AudioTrackController', function () { const currentTrackId = 4; audioTrackController._trackId = currentTrackId; audioTrackController.tracks = tracks; - audioTrackController.onError({ + audioTrackController.onError(Events.ERROR, { type: Hls.ErrorTypes.MEDIA_ERROR, fatal: true }); expect(!!audioTrackController.trackIdBlacklist[currentTrackId]).to.be.false; - audioTrackController.onError({ + audioTrackController.onError(Events.ERROR, { type: Hls.ErrorTypes.NETWORK_ERROR, fatal: true }); expect(!!audioTrackController.trackIdBlacklist[currentTrackId]).to.be.false; - audioTrackController.onError({ + audioTrackController.onError(Events.ERROR, { type: Hls.ErrorTypes.NETWORK_ERROR, details: Hls.ErrorDetails.AUDIO_TRACK_LOAD_ERROR, fatal: true, diff --git a/tests/unit/controller/buffer-controller-operations.ts b/tests/unit/controller/buffer-controller-operations.ts index f483b7b341c..bc04bf68303 100644 --- a/tests/unit/controller/buffer-controller-operations.ts +++ b/tests/unit/controller/buffer-controller-operations.ts @@ -6,8 +6,8 @@ import Hls from '../../../src/hls'; import BufferOperationQueue from '../../../src/controller/buffer-operation-queue'; import BufferController from '../../../src/controller/buffer-controller'; import { BufferOperation, SourceBufferName } from '../../../src/types/buffer'; -import { BufferAppendingEventPayload } from '../../../src/types/events'; -import Events from '../../../src/events'; +import { BufferAppendingData } from '../../../src/types/events'; +import { Events } from '../../../src/events'; import { ErrorDetails, ErrorTypes } from '../../../src/errors'; import Fragment, { ElementaryStreamTypes } from '../../../src/loader/fragment'; import { PlaylistLevelType } from '../../../src/types/loader'; @@ -143,14 +143,14 @@ describe('BufferController SourceBuffer operation queueing', function () { const frag = new Fragment(); frag.type = PlaylistLevelType.MAIN; const chunkMeta = new ChunkMetadata(0, 0, 0, 0); - const data: BufferAppendingEventPayload = { + const data: BufferAppendingData = { type: name, data: segmentData, frag, chunkMeta }; - bufferController.onBufferAppending(data); + bufferController.onBufferAppending(Events.BUFFER_APPENDING, data); expect(queueAppendSpy, 'The append operation should have been enqueued').to.have.callCount(i + 1); buffer.dispatchEvent(new Event('updateend')); @@ -173,7 +173,7 @@ describe('BufferController SourceBuffer operation queueing', function () { const queueAppendSpy = sandbox.spy(operationQueue, 'append'); queueNames.forEach((name, i) => { bufferController.sourceBuffer = {}; - bufferController.onBufferAppending({ + bufferController.onBufferAppending(Events.BUFFER_APPENDING, { type: name, data: new Uint8Array(), frag: new Fragment(), @@ -194,7 +194,7 @@ describe('BufferController SourceBuffer operation queueing', function () { frag.setElementaryStreamInfo(ElementaryStreamTypes.AUDIO, 0, 0, 0, 0); frag.setElementaryStreamInfo(ElementaryStreamTypes.VIDEO, 0, 0, 0, 0); - bufferController.onFragParsed({ frag }); + bufferController.onFragParsed(Events.FRAG_PARSED, { frag }); expect(queueAppendBlockerSpy).to.have.been.calledTwice; expect(flushLiveBackBufferSpy).to.have.been.calledOnce; return new Promise((resolve, reject) => { @@ -227,7 +227,7 @@ describe('BufferController SourceBuffer operation queueing', function () { }); it('flushes audio and video buffers if no type arg is specified', function () { - bufferController.onBufferFlushing({ + bufferController.onBufferFlushing(Events.BUFFER_FLUSHING, { startOffset: 0, endOffset: 10 }); @@ -247,7 +247,7 @@ describe('BufferController SourceBuffer operation queueing', function () { it('dequeues the remove operation if the SourceBuffer does not exist during the operation', function () { bufferController.sourceBuffer = {}; - bufferController.onBufferFlushing({ + bufferController.onBufferFlushing(Events.BUFFER_FLUSHING, { startOffset: 0, endOffset: Infinity }); @@ -258,7 +258,7 @@ describe('BufferController SourceBuffer operation queueing', function () { it('dequeues the remove operation if the requested remove range is not valid', function () { // Does not flush if start greater than end - bufferController.onBufferFlushing({ + bufferController.onBufferFlushing(Events.BUFFER_FLUSHING, { startOffset: 9001, endOffset: 9000 }); @@ -314,7 +314,7 @@ describe('BufferController SourceBuffer operation queueing', function () { bufferController.flushLiveBackBuffer(); expect(bufferFlushingSpy).to.have.been.calledTwice; queueNames.forEach(name => { - expect(bufferFlushingSpy, `onBufferFlushing should have been called for the ${name} SourceBuffer`).to.have.been.calledWith({ startOffset: 0, endOffset: 20, type: name }); + expect(bufferFlushingSpy, `onBufferFlushing should have been called for the ${name} SourceBuffer`).to.have.been.calledWith(Events.BUFFER_FLUSHING, { startOffset: 0, endOffset: 20, type: name }); }); }); @@ -323,7 +323,7 @@ describe('BufferController SourceBuffer operation queueing', function () { hls.config.liveBackBufferLength = 5; bufferController.flushLiveBackBuffer(); queueNames.forEach(name => { - expect(bufferFlushingSpy, `onBufferFlushing should have been called for the ${name} SourceBuffer`).to.have.been.calledWith({ startOffset: 0, endOffset: 15, type: name }); + expect(bufferFlushingSpy, `onBufferFlushing should have been called for the ${name} SourceBuffer`).to.have.been.calledWith(Events.BUFFER_FLUSHING, { startOffset: 0, endOffset: 15, type: name }); }); }); @@ -366,13 +366,13 @@ describe('BufferController SourceBuffer operation queueing', function () { it('exits early if the fragments array is empty', function () { data.details.fragments = []; - bufferController.onLevelUpdated(data); + bufferController.onLevelUpdated(Events.LEVEL_UPDATED, data); expect(bufferController._levelTargetDuration, '_levelTargetDuration').to.be.null; expect(bufferController._live, '_live').to.be.false; }); it('updates class properties based on level data', function () { - bufferController.onLevelUpdated(data); + bufferController.onLevelUpdated(Events.LEVEL_UPDATED, data); expect(bufferController._levelTargetDuration, '_levelTargetDuration').to.equal(6); expect(bufferController._live, '_live').to.be.true; @@ -380,25 +380,25 @@ describe('BufferController SourceBuffer operation queueing', function () { delete data.details.averagetargetduration; data.details.targetduration = 7; data.details.live = false; - bufferController.onLevelUpdated(data); + bufferController.onLevelUpdated(Events.LEVEL_UPDATED, data); expect(bufferController._levelTargetDuration, '_levelTargetDuration').to.equal(7); expect(bufferController._live, '_live').to.be.false; // Defaults to 10 if no duration is provided delete data.details.targetduration; - bufferController.onLevelUpdated(data); + bufferController.onLevelUpdated(Events.LEVEL_UPDATED, data); expect(bufferController._levelTargetDuration, '_levelTargetDuration').to.equal(10); }); it('enqueues a blocking operation which updates the MediaSource duration', function () { - bufferController.onLevelUpdated(data); + bufferController.onLevelUpdated(Events.LEVEL_UPDATED, data); expect(queueAppendBlockerSpy).to.have.been.calledTwice; // Updating the duration is aync and has no event to signal completion, so we are unable to test for it directly }); it('synchronously updates the duration if no SourceBuffers exist', function () { bufferController.sourceBuffer = {}; - bufferController.onLevelUpdated(data); + bufferController.onLevelUpdated(Events.LEVEL_UPDATED, data); expect(queueAppendBlockerSpy).to.have.not.been.called; expect(mockMediaSource.duration, 'mediaSource.duration').to.equal(10); expect(bufferController._msDuration, '_msDuration').to.equal(10); @@ -408,7 +408,7 @@ describe('BufferController SourceBuffer operation queueing', function () { describe('onBufferEos', function () { it('marks the ExtendedSourceBuffer as ended', function () { // No type arg ends both SourceBuffers - bufferController.onBufferEos({ }); + bufferController.onBufferEos(Events.BUFFER_EOS, {}); expect(queueAppendBlockerSpy).to.have.been.calledTwice; queueNames.forEach(type => { const buffer = bufferController.sourceBuffer[type]; diff --git a/tests/unit/controller/buffer-controller.js b/tests/unit/controller/buffer-controller.js index 0df3d0d7cf4..4572a08f31c 100644 --- a/tests/unit/controller/buffer-controller.js +++ b/tests/unit/controller/buffer-controller.js @@ -1,6 +1,7 @@ import sinon from 'sinon'; import Hls from '../../../src/hls'; import BufferController from '../../../src/controller/buffer-controller'; +import { Events } from '../../../src/events'; describe('BufferController tests', function () { let hls; @@ -24,13 +25,13 @@ describe('BufferController tests', function () { it('flushes a specific type when provided a type', function () { const spy = sandbox.spy(bufferController.operationQueue, 'append'); - bufferController.onBufferFlushing({ startOffset: 0, endOffset: 10, type: 'video' }); + bufferController.onBufferFlushing(Events.BUFFER_FLUSHING, { startOffset: 0, endOffset: 10, type: 'video' }); expect(spy).to.have.been.calledOnce; }); it('flushes all source buffers when buffer flush event type is undefined', function () { const spy = sandbox.spy(bufferController.operationQueue, 'append'); - bufferController.onBufferFlushing({ startOffset: 0, endOffset: 10 }); + bufferController.onBufferFlushing(Events.BUFFER_FLUSHING, { startOffset: 0, endOffset: 10 }); expect(spy).to.have.been.calledTwice; }); }); @@ -155,9 +156,9 @@ describe('BufferController tests', function () { bufferController.createSourceBuffers.restore(); let video = document.createElement('video'); - bufferController.onMediaAttaching({ media: video }); + bufferController.onMediaAttaching(Events.MEDIA_ATTACHING, { media: video }); - hls.on(Hls.Events.BUFFER_CREATED, (_, data) => { + hls.on(Hls.Events.BUFFER_CREATED, (event, data) => { const tracks = data.tracks; expect(bufferController.pendingTracks).to.not.equal(tracks); expect(bufferController.tracks).to.equal(tracks); @@ -171,12 +172,12 @@ describe('BufferController tests', function () { }); it('expects one bufferCodec event by default', function () { - bufferController.onManifestParsed({}); + bufferController.onManifestParsed(Events.MANIFEST_PARSED, {}); expect(bufferController.bufferCodecEventsExpected).to.equal(1); }); it('expects two bufferCodec events if altAudio is signaled', function () { - bufferController.onManifestParsed({ altAudio: true }); + bufferController.onManifestParsed(Events.MANIFEST_PARSED, { altAudio: true }); expect(bufferController.bufferCodecEventsExpected).to.equal(2); }); @@ -214,11 +215,11 @@ describe('BufferController tests', function () { bufferController.mediaSource = { readyState: 'open' }; bufferController.bufferCodecEventsExpected = 2; - bufferController.onBufferCodecs({}); + bufferController.onBufferCodecs(Events.BUFFER_CODECS, {}); expect(checkPendingTracksSpy).to.have.been.calledOnce; expect(bufferController.bufferCodecEventsExpected).to.equal(1); - bufferController.onBufferCodecs({}); + bufferController.onBufferCodecs(Events.BUFFER_CODECS, {}); expect(checkPendingTracksSpy).to.have.been.calledTwice; expect(bufferController.bufferCodecEventsExpected).to.equal(0); }); @@ -227,10 +228,10 @@ describe('BufferController tests', function () { bufferController.sourceBuffer = {}; bufferController.mediaSource = { readyState: 'open', removeEventListener: sandbox.stub() }; - bufferController.onManifestParsed({ altAudio: true }); + bufferController.onManifestParsed(Events.MANIFEST_PARSED, { altAudio: true }); bufferController._onMediaSourceOpen(); - bufferController.onBufferCodecs({ audio: {} }); - bufferController.onBufferCodecs({ video: {} }); + bufferController.onBufferCodecs(Events.BUFFER_CODECS, { audio: {} }); + bufferController.onBufferCodecs(Events.BUFFER_CODECS, { video: {} }); expect(createSbStub).to.have.been.calledOnce; expect(createSbStub).to.have.been.calledWith({ audio: {}, video: {} }); diff --git a/tests/unit/controller/cap-level-controller.js b/tests/unit/controller/cap-level-controller.js index 227e603ed89..44041b220dc 100644 --- a/tests/unit/controller/cap-level-controller.js +++ b/tests/unit/controller/cap-level-controller.js @@ -1,6 +1,7 @@ import sinon from 'sinon'; import Hls from '../../../src/hls'; import CapLevelController from '../../../src/controller/cap-level-controller'; +import { Events } from '../../../src/events'; const levels = [ { @@ -104,20 +105,20 @@ describe('CapLevelController', function () { }); it('starts capping on BUFFER_CODECS only if video is found', function () { - capLevelController.onBufferCodecs({ video: {} }); + capLevelController.onBufferCodecs(Events.BUFFER_CODECS, { video: {} }); expect(startCappingSpy.calledOnce).to.be.true; }); it('does not start capping on BUFFER_CODECS if video is not found', function () { - capLevelController.onBufferCodecs({ audio: {} }); + capLevelController.onBufferCodecs(Events.BUFFER_CODECS, { audio: {} }); expect(startCappingSpy.notCalled).to.be.true; }); it('starts capping if the video codec was found after the audio codec', function () { - capLevelController.onBufferCodecs({ audio: {} }); + capLevelController.onBufferCodecs(Events.BUFFER_CODECS, { audio: {} }); expect(startCappingSpy.notCalled).to.be.true; - capLevelController.onBufferCodecs({ video: {} }); + capLevelController.onBufferCodecs(Events.BUFFER_CODECS, { video: {} }); expect(startCappingSpy.calledOnce).to.be.true; }); @@ -128,19 +129,19 @@ describe('CapLevelController', function () { firstLevel: 0 }; - capLevelController.onManifestParsed(data); + capLevelController.onManifestParsed(Events.MANIFEST_PARSED, data); expect(capLevelController.levels).to.equal(data.levels); expect(capLevelController.firstLevel).to.equal(data.firstLevel); expect(capLevelController.restrictedLevels).to.be.empty; }); it('should start capping in MANIFEST_PARSED if a video codec was signaled in the manifest', function () { - capLevelController.onManifestParsed({ video: {} }); + capLevelController.onManifestParsed(Events.MANIFEST_PARSED, { video: {} }); expect(startCappingSpy.calledOnce).to.be.true; }); it('does not start capping on MANIFEST_PARSED if no video codec was signaled in the manifest', function () { - capLevelController.onManifestParsed({ levels: [{}], altAudio: true }); + capLevelController.onManifestParsed(Events.MANIFEST_PARSED, { levels: [{}], altAudio: true }); expect(startCappingSpy.notCalled).to.be.true; }); @@ -154,7 +155,7 @@ describe('CapLevelController', function () { streamController = hls.streamController; nextLevelSwitchSpy = sinon.spy(streamController, 'nextLevelSwitch'); - capLevelController.onManifestParsed({ levels, video: {} }); + capLevelController.onManifestParsed(Events.MANIFEST_PARSED, { levels, video: {} }); }); it('continues capping without second timer', function () { diff --git a/tests/unit/controller/eme-controller.js b/tests/unit/controller/eme-controller.js index 0ac56526dd4..b6de95790b0 100644 --- a/tests/unit/controller/eme-controller.js +++ b/tests/unit/controller/eme-controller.js @@ -2,6 +2,7 @@ import EMEController from '../../../src/controller/eme-controller'; import HlsMock from '../../mocks/hls.mock'; import { EventEmitter } from 'eventemitter3'; import { ErrorDetails } from '../../../src/errors'; +import { Events } from '../../../src/events'; const sinon = require('sinon'); @@ -42,8 +43,8 @@ describe('EMEController', function () { requestMediaKeySystemAccessFunc: reqMediaKsAccessSpy }); - emeController.onMediaAttached({ media }); - emeController.onManifestParsed({ media }); + emeController.onMediaAttached(Events.MEDIA_ATTACHED, { media }); + emeController.onManifestParsed(Events.MANIFEST_PARSED, { media }); expect(media.setMediaKeys.callCount).to.equal(0); expect(reqMediaKsAccessSpy.callCount).to.equal(0); @@ -61,12 +62,12 @@ describe('EMEController', function () { requestMediaKeySystemAccessFunc: reqMediaKsAccessSpy }); - emeController.onMediaAttached({ media }); + emeController.onMediaAttached(Events.MEDIA_ATTACHED, { media }); expect(media.setMediaKeys.callCount).to.equal(0); expect(reqMediaKsAccessSpy.callCount).to.equal(0); - emeController.onManifestParsed({ levels: fakeLevels }); + emeController.onManifestParsed(Events.MANIFEST_PARSED, { levels: fakeLevels }); self.setTimeout(function () { expect(media.setMediaKeys.callCount).to.equal(0); @@ -75,7 +76,7 @@ describe('EMEController', function () { }, 0); }); - it('should trigger key system error when bad encrypted data is received', function (done) { + it('should emit key system error when bad encrypted data is received', function (done) { const reqMediaKsAccessSpy = sinon.spy(function () { return Promise.resolve({ // Media-keys mock @@ -92,8 +93,8 @@ describe('EMEController', function () { initData: 'bad data' }; - emeController.onMediaAttached({ media }); - emeController.onManifestParsed({ levels: fakeLevels }); + emeController.onMediaAttached(Events.MEDIA_ATTACHED, { media }); + emeController.onManifestParsed(Events.MANIFEST_PARSED, { levels: fakeLevels }); media.emit('encrypted', badData); diff --git a/tests/unit/controller/fragment-tracker.js b/tests/unit/controller/fragment-tracker.js index 6b92e44109f..4807144bb39 100644 --- a/tests/unit/controller/fragment-tracker.js +++ b/tests/unit/controller/fragment-tracker.js @@ -1,5 +1,5 @@ import Hls from '../../../src/hls'; -import Event from '../../../src/events'; +import { Events } from '../../../src/events'; import { FragmentTracker, FragmentState } from '../../../src/controller/fragment-tracker'; import { PlaylistLevelType } from '../../../src/types/loader'; @@ -25,7 +25,7 @@ function createMockFragment (data, types) { * @param {Fragment} fragment */ function loadFragment (hls, fragment) { - hls.trigger(Event.FRAG_LOADED, { frag: fragment }); + hls.trigger(Events.FRAG_LOADED, { frag: fragment }); } /** @@ -35,8 +35,9 @@ function loadFragment (hls, fragment) { */ function loadFragmentAndBuffered (hls, fragment) { loadFragment(hls, fragment); - hls.trigger(Event.FRAG_BUFFERED, { frag: fragment }); + hls.trigger(Events.FRAG_BUFFERED, { frag: fragment }); } + describe('FragmentTracker', function () { describe('getPartialFragment', function () { let partialFragment; @@ -52,7 +53,7 @@ describe('FragmentTracker', function () { type: 'main' }, ['audio', 'video']); - hls.trigger(Event.FRAG_LOADED, { frag: fragment }); + hls.trigger(Events.FRAG_LOADED, { frag: fragment }); const buffered = createMockBuffer([ { @@ -64,9 +65,9 @@ describe('FragmentTracker', function () { const timeRanges = {}; timeRanges.video = buffered; timeRanges.audio = buffered; - hls.trigger(Event.BUFFER_APPENDED, { timeRanges }); + hls.trigger(Events.BUFFER_APPENDED, { timeRanges }); - hls.trigger(Event.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); + hls.trigger(Events.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); it('detects fragments that partially loaded', function () { // Get the partial fragment at a time @@ -77,6 +78,7 @@ describe('FragmentTracker', function () { partialFragment = fragmentTracker.getPartialFragment(1); expect(partialFragment).to.equal(fragment); }); + it('returns null when time is not inside partial fragment', function () { partialFragment = fragmentTracker.getPartialFragment(1.5); expect(partialFragment).to.not.exist; @@ -99,7 +101,7 @@ describe('FragmentTracker', function () { level: 0, type: 'main' }, ['audio', 'video']); - hls.trigger(Event.FRAG_LOADED, { frag: fragment }); + hls.trigger(Events.FRAG_LOADED, { frag: fragment }); }; it('detects fragments that never loaded', function () { @@ -119,9 +121,9 @@ describe('FragmentTracker', function () { timeRanges = {}; timeRanges.video = buffered; timeRanges.audio = buffered; - hls.trigger(Event.BUFFER_APPENDED, { timeRanges }); + hls.trigger(Events.BUFFER_APPENDED, { timeRanges }); - hls.trigger(Event.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); + hls.trigger(Events.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); expect(fragmentTracker.getState(fragment)).to.equal(FragmentState.OK); }); @@ -137,9 +139,9 @@ describe('FragmentTracker', function () { timeRanges = {}; timeRanges.video = buffered; timeRanges.audio = buffered; - hls.trigger(Event.BUFFER_APPENDED, { timeRanges }); + hls.trigger(Events.BUFFER_APPENDED, { timeRanges }); - hls.trigger(Event.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); + hls.trigger(Events.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); expect(fragmentTracker.getState(fragment)).to.equal(FragmentState.PARTIAL); }); @@ -155,9 +157,9 @@ describe('FragmentTracker', function () { timeRanges = {}; timeRanges.video = buffered; timeRanges.audio = buffered; - hls.trigger(Event.BUFFER_APPENDED, { timeRanges }); + hls.trigger(Events.BUFFER_APPENDED, { timeRanges }); - hls.trigger(Event.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); + hls.trigger(Events.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); expect(fragmentTracker.getState(fragment)).to.equal(FragmentState.PARTIAL); @@ -171,7 +173,7 @@ describe('FragmentTracker', function () { timeRanges = {}; timeRanges.video = buffered; timeRanges.audio = buffered; - hls.trigger(Event.BUFFER_APPENDED, { timeRanges }); + hls.trigger(Events.BUFFER_APPENDED, { timeRanges }); expect(fragmentTracker.getState(fragment)).to.equal(FragmentState.NOT_LOADED); }); @@ -303,7 +305,7 @@ describe('FragmentTracker', function () { level: 1, type: 'main' }, ['audio', 'video']); - hls.trigger(Event.FRAG_LOADED, { frag: fragment }); + hls.trigger(Events.FRAG_LOADED, { frag: fragment }); timeRanges = {}; timeRanges.video = createMockBuffer([ @@ -318,9 +320,9 @@ describe('FragmentTracker', function () { endPTS: 2 } ]); - hls.trigger(Event.BUFFER_APPENDED, { timeRanges }); + hls.trigger(Events.BUFFER_APPENDED, { timeRanges }); - hls.trigger(Event.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); + hls.trigger(Events.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); expect(fragmentTracker.getState(fragment)).to.equal(FragmentState.PARTIAL); }); @@ -333,7 +335,7 @@ describe('FragmentTracker', function () { level: 1, type: 'main' }, ['audio', 'video']); - hls.trigger(Event.FRAG_LOADED, { frag: fragment }); + hls.trigger(Events.FRAG_LOADED, { frag: fragment }); timeRanges = {}; timeRanges.video = createMockBuffer([ @@ -348,9 +350,9 @@ describe('FragmentTracker', function () { endPTS: 2 } ]); - hls.trigger(Event.BUFFER_APPENDED, { timeRanges }); + hls.trigger(Events.BUFFER_APPENDED, { timeRanges }); - hls.trigger(Event.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); + hls.trigger(Events.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); expect(fragmentTracker.getState(fragment)).to.equal(FragmentState.PARTIAL); }); @@ -363,7 +365,7 @@ describe('FragmentTracker', function () { level: 1, type: 'audio' }, ['audio']); - hls.trigger(Event.FRAG_LOADED, { frag: fragment }); + hls.trigger(Events.FRAG_LOADED, { frag: fragment }); timeRanges = {}; timeRanges.video = createMockBuffer([ @@ -378,9 +380,9 @@ describe('FragmentTracker', function () { endPTS: 2 } ]); - hls.trigger(Event.BUFFER_APPENDED, { timeRanges }); + hls.trigger(Events.BUFFER_APPENDED, { timeRanges }); - hls.trigger(Event.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); + hls.trigger(Events.FRAG_BUFFERED, { stats: { aborted: true }, id: 'main', frag: fragment }); expect(fragmentTracker.getState(fragment)).to.equal(FragmentState.OK); }); diff --git a/tests/unit/controller/gap-controller.js b/tests/unit/controller/gap-controller.js index ebb6e7e24d7..94de5494e33 100644 --- a/tests/unit/controller/gap-controller.js +++ b/tests/unit/controller/gap-controller.js @@ -1,7 +1,7 @@ import Hls from '../../../src/hls'; import GapController, { SKIP_BUFFER_RANGE_START } from '../../../src/controller/gap-controller'; import { FragmentTracker } from '../../../src/controller/fragment-tracker'; -import Event from '../../../src/events'; +import { Events } from '../../../src/events'; import { ErrorTypes, ErrorDetails } from '../../../src/errors'; describe('GapController', function () { @@ -33,7 +33,7 @@ describe('GapController', function () { expect(media.currentTime).to.equal(expected); } - expect(triggerSpy).to.have.been.calledWith(Event.ERROR, { + expect(triggerSpy).to.have.been.calledWith(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_NUDGE_ON_STALL, fatal: false @@ -44,7 +44,7 @@ describe('GapController', function () { config.nudgeMaxRetry = 0; gapController._tryNudgeBuffer(); expect(media.currentTime).to.equal(0); - expect(triggerSpy).to.have.been.calledWith(Event.ERROR, { + expect(triggerSpy).to.have.been.calledWith(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_STALLED_ERROR, fatal: true @@ -55,7 +55,7 @@ describe('GapController', function () { describe('_reportStall', function () { it('should report a stall with the current buffer length if it has not already been reported', function () { gapController._reportStall(42); - expect(triggerSpy).to.have.been.calledWith(Event.ERROR, { + expect(triggerSpy).to.have.been.calledWith(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_STALLED_ERROR, fatal: false, diff --git a/tests/unit/controller/level-controller.js b/tests/unit/controller/level-controller.js index ce382b5b221..d65eee0f4c7 100644 --- a/tests/unit/controller/level-controller.js +++ b/tests/unit/controller/level-controller.js @@ -1,6 +1,6 @@ import LevelController from '../../../src/controller/level-controller'; import HlsMock from '../../mocks/hls.mock'; -import Event from '../../../src/events'; +import { Events } from '../../../src/events'; import { ErrorDetails, ErrorTypes } from '../../../src/errors'; import { Level } from '../../../src/types/level'; @@ -41,11 +41,11 @@ describe('LevelController', function () { const nextLevel = 1; - levelController.onManifestLoaded(data); + levelController.onManifestLoaded(Events.MANIFEST_LOADED, data); // First triggers "hlsManifestParsed" levelController.level = nextLevel; // Then triggers "levelSwitching" - expect(triggerSpy).to.have.been.calledWith(Event.LEVEL_SWITCHING, { + expect(triggerSpy).to.have.been.calledWith(Events.LEVEL_SWITCHING, { attrs: undefined, audioCodec: undefined, audioGroupIds: undefined, @@ -70,7 +70,7 @@ describe('LevelController', function () { describe('onManifestLoaded handler', function () { it('should trigger an error when no levels are found in the manifest', function () { - levelController.onManifestLoaded({ + levelController.onManifestLoaded(Events.MANIFEST_LOADED, { audioTracks: [], levels: [], networkDetails: '', @@ -78,7 +78,7 @@ describe('LevelController', function () { url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8' }); - expect(triggerSpy).to.have.been.calledWith(Event.ERROR, { + expect(triggerSpy).to.have.been.calledWith(Events.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.MANIFEST_INCOMPATIBLE_CODECS_ERROR, fatal: true, @@ -104,9 +104,9 @@ describe('LevelController', function () { url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8' }; - levelController.onManifestLoaded(data); + levelController.onManifestLoaded(Events.MANIFEST_LOADED, data); - expect(triggerSpy).to.have.been.calledWith(Event.MANIFEST_PARSED, { + expect(triggerSpy).to.have.been.calledWith(Events.MANIFEST_PARSED, { altAudio: false, audio: false, audioTracks: [], @@ -131,8 +131,8 @@ describe('LevelController', function () { url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8' }; - levelController.onManifestLoaded(data); - expect(triggerSpy).to.have.been.calledWith(Event.MANIFEST_PARSED, { + levelController.onManifestLoaded(Events.MANIFEST_LOADED, data); + expect(triggerSpy).to.have.been.calledWith(Events.MANIFEST_PARSED, { altAudio: true, audio: false, audioTracks: [], @@ -158,10 +158,10 @@ describe('LevelController', function () { it('signals video if there is a videoCodec signaled', function () { data.levels[0].videoCodec = 'avc1.42e01e'; - levelController.onManifestLoaded(data); + levelController.onManifestLoaded(Events.MANIFEST_LOADED, data); const { name, payload } = hls.getEventData(0); - expect(name).to.equal(Event.MANIFEST_PARSED); + expect(name).to.equal(Events.MANIFEST_PARSED); expect(payload.video).to.equal(true); expect(payload.audio).to.equal(false); expect(payload.altAudio).to.equal(false); @@ -169,10 +169,10 @@ describe('LevelController', function () { it('signals audio if there is an audioCodec signaled', function () { data.levels[0].audioCodec = 'mp4a.40.5'; - levelController.onManifestLoaded(data); + levelController.onManifestLoaded(Events.MANIFEST_LOADED, data); const { name, payload } = hls.getEventData(0); - expect(name).to.equal(Event.MANIFEST_PARSED); + expect(name).to.equal(Events.MANIFEST_PARSED); expect(payload.video).to.equal(false); expect(payload.audio).to.equal(true); expect(payload.altAudio).to.equal(false); @@ -184,10 +184,10 @@ describe('LevelController', function () { AUDIO: true } }]; - levelController.onManifestLoaded(data); + levelController.onManifestLoaded(Events.MANIFEST_LOADED, data); const { name, payload } = hls.getEventData(0); - expect(name).to.equal(Event.MANIFEST_PARSED); + expect(name).to.equal(Events.MANIFEST_PARSED); expect(payload.video).to.equal(false); expect(payload.audio).to.equal(true); expect(payload.altAudio).to.equal(false); @@ -217,10 +217,10 @@ describe('LevelController', function () { } ]; - levelController.onManifestLoaded(data); + levelController.onManifestLoaded(Events.MANIFEST_LOADED, data); const { name, payload } = hls.getEventData(0); - expect(name).to.equal(Event.MANIFEST_PARSED); + expect(name).to.equal(Events.MANIFEST_PARSED); expect(payload.video).to.equal(true); expect(payload.audio).to.equal(false); expect(payload.altAudio).to.equal(true); @@ -249,10 +249,10 @@ describe('LevelController', function () { } ]; - levelController.onManifestLoaded(data); + levelController.onManifestLoaded(Events.MANIFEST_LOADED, data); const { name, payload } = hls.getEventData(0); - expect(name).to.equal(Event.MANIFEST_PARSED); + expect(name).to.equal(Events.MANIFEST_PARSED); expect(payload.video).to.equal(true); expect(payload.audio).to.equal(false); expect(payload.altAudio).to.equal(false); diff --git a/tests/unit/controller/stream-controller.js b/tests/unit/controller/stream-controller.js index 10091a98111..424dcb76c2f 100644 --- a/tests/unit/controller/stream-controller.js +++ b/tests/unit/controller/stream-controller.js @@ -1,5 +1,5 @@ import Hls from '../../../src/hls'; -import Event from '../../../src/events'; +import { Events } from '../../../src/events'; import { FragmentTracker, FragmentState } from '../../../src/controller/fragment-tracker'; import StreamController from '../../../src/controller/stream-controller'; import { State } from '../../../src/controller/base-stream-controller'; @@ -54,7 +54,7 @@ describe('StreamController', function () { http://proxy-62.dailymotion.com/sec(3ae40f708f79ca9471f52b86da76a3a8)/video/107/282/158282701_mp4_h264_aac_hq.m3u8#cell=core`; const levels = M3U8Parser.parseMasterPlaylist(manifest, 'http://www.dailymotion.com'); // load levels data - streamController.onManifestParsed({ + streamController.onManifestParsed(Events.MANIFEST_PARSED, { levels }); streamController.startLoad(1); @@ -141,7 +141,7 @@ describe('StreamController', function () { }); function assertLoadingState (frag) { - expect(triggerSpy).to.have.been.calledWith(Event.FRAG_LOADING, { frag }); + expect(triggerSpy).to.have.been.calledWith(Events.FRAG_LOADING, { frag }); expect(streamController.state).to.equal(State.FRAG_LOADING); } diff --git a/tests/unit/controller/subtitle-stream-controller.js b/tests/unit/controller/subtitle-stream-controller.js index 898af2e0c38..1f117e95f6d 100644 --- a/tests/unit/controller/subtitle-stream-controller.js +++ b/tests/unit/controller/subtitle-stream-controller.js @@ -1,7 +1,7 @@ import sinon from 'sinon'; import Hls from '../../../src/hls'; -import Event from '../../../src/events'; +import { Events } from '../../../src/events'; import { FragmentTracker } from '../../../src/controller/fragment-tracker'; import { SubtitleStreamController } from '../../../src/controller/subtitle-stream-controller'; @@ -26,16 +26,16 @@ describe('SubtitleStreamController', function () { fragmentTracker = new FragmentTracker(hls); subtitleStreamController = new SubtitleStreamController(hls, fragmentTracker); - subtitleStreamController.onMediaAttached({ media: mediaMock }); + subtitleStreamController.onMediaAttached(Events.MEDIA_ATTACHED, { media: mediaMock }); }); afterEach(function () { - subtitleStreamController.onMediaDetaching({ media: mediaMock }); + subtitleStreamController.onMediaDetaching(Events.MEDIA_DETACHING, { media: mediaMock }); }); describe('onSubtitleTracksUpdate', function () { beforeEach(function () { - hls.trigger(Event.SUBTITLE_TRACKS_UPDATED, { + hls.trigger(Events.SUBTITLE_TRACKS_UPDATED, { subtitleTracks: tracksMock }); }); @@ -53,7 +53,7 @@ describe('SubtitleStreamController', function () { subtitleStreamController.clearInterval = sinon.spy(); subtitleStreamController.setInterval = sinon.spy(); - hls.trigger(Event.SUBTITLE_TRACK_SWITCH, { + hls.trigger(Events.SUBTITLE_TRACK_SWITCH, { id: 0 }); }); @@ -64,14 +64,14 @@ describe('SubtitleStreamController', function () { it('should call clearInterval if no tracks present', function () { subtitleStreamController.levels = []; - hls.trigger(Event.SUBTITLE_TRACK_SWITCH, { + hls.trigger(Events.SUBTITLE_TRACK_SWITCH, { id: 0 }); expect(subtitleStreamController.clearInterval).to.have.been.calledOnce; }); it('should call clearInterval if new track id === -1', function () { - hls.trigger(Event.SUBTITLE_TRACK_SWITCH, { + hls.trigger(Events.SUBTITLE_TRACK_SWITCH, { id: -1 }); expect(subtitleStreamController.clearInterval).to.have.been.calledOnce; @@ -88,8 +88,9 @@ describe('SubtitleStreamController', function () { it('should handle the event if the data matches the current track', function () { const details = { foo: 'bar' }; subtitleStreamController.currentTrackId = 1; - hls.trigger(Event.SUBTITLE_TRACK_LOADED, { - id: 1, details + hls.trigger(Events.SUBTITLE_TRACK_LOADED, { + id: 1, + details: details }); expect(subtitleStreamController.levels[1].details).to.equal(details); expect(subtitleStreamController.setInterval).to.have.been.calledOnce; @@ -98,7 +99,7 @@ describe('SubtitleStreamController', function () { it('should ignore the event if the data does not match the current track', function () { const details = { foo: 'bar' }; subtitleStreamController.currentTrackId = 0; - hls.trigger(Event.SUBTITLE_TRACK_LOADED, { + hls.trigger(Events.SUBTITLE_TRACK_LOADED, { id: 1, details }); expect(subtitleStreamController.levels[0].details).to.not.equal(details); @@ -109,7 +110,7 @@ describe('SubtitleStreamController', function () { subtitleStreamController.levels = []; subtitleStreamController.trackId = 0; const details = { foo: 'bar' }; - hls.trigger(Event.SUBTITLE_TRACK_LOADED, { + hls.trigger(Events.SUBTITLE_TRACK_LOADED, { id: 0, details }); expect(subtitleStreamController.levels[0]).to.not.exist; @@ -119,12 +120,12 @@ describe('SubtitleStreamController', function () { describe('onLevelLoaded', function () { it('records the start time of the last known A/V track', function () { - hls.trigger(Event.LEVEL_UPDATED, { + hls.trigger(Events.LEVEL_UPDATED, { details: { fragments: [{ start: 5 }] } }); expect(subtitleStreamController.lastAVStart).to.equal(5); - hls.trigger(Event.LEVEL_UPDATED, { + hls.trigger(Events.LEVEL_UPDATED, { details: { fragments: [] } }); expect(subtitleStreamController.lastAVStart).to.equal(0); diff --git a/tests/unit/controller/subtitle-track-controller.js b/tests/unit/controller/subtitle-track-controller.js index 12efd8fe92b..9080019c4b4 100644 --- a/tests/unit/controller/subtitle-track-controller.js +++ b/tests/unit/controller/subtitle-track-controller.js @@ -3,6 +3,7 @@ import Hls from '../../../src/hls'; import sinon from 'sinon'; import LoadStats from '../../../src/loader/load-stats'; import LevelDetails from '../../../src/loader/level-details'; +import { Events } from '../../../src/events'; describe('SubtitleTrackController', function () { let subtitleTrackController; @@ -180,17 +181,17 @@ describe('SubtitleTrackController', function () { subtitleTrackController.trackId = 1; const mockLoadedEvent = { id: 999, details: { foo: 'bar' } }; - subtitleTrackController.onSubtitleTrackLoaded(mockLoadedEvent); + subtitleTrackController.onSubtitleTrackLoaded(Events.SUBTITLE_TRACK_LOADED, mockLoadedEvent); expect(subtitleTrackController.timer).to.not.exist; expect(clearReloadSpy).to.have.been.calledOnce; mockLoadedEvent.id = 0; - subtitleTrackController.onSubtitleTrackLoaded(mockLoadedEvent); + subtitleTrackController.onSubtitleTrackLoaded(Events.SUBTITLE_TRACK_LOADED, mockLoadedEvent); expect(subtitleTrackController.timer).to.not.exist; expect(clearReloadSpy).to.have.been.calledTwice; mockLoadedEvent.id = 1; - subtitleTrackController.onSubtitleTrackLoaded(mockLoadedEvent); + subtitleTrackController.onSubtitleTrackLoaded(Events.SUBTITLE_TRACK_LOADED, mockLoadedEvent); tracks[1] = null; expect(subtitleTrackController.timer).to.not.exist; expect(clearReloadSpy).to.have.been.calledThrice; @@ -200,7 +201,7 @@ describe('SubtitleTrackController', function () { const details = new LevelDetails(''); subtitleTrackController.stopped = true; subtitleTrackController.trackId = 1; - subtitleTrackController.onSubtitleTrackLoaded({ id: 1, details, stats: new LoadStats() }); + subtitleTrackController.onSubtitleTrackLoaded(Events.SUBTITLE_TRACK_LOADED, { id: 1, details, stats: new LoadStats() }); expect(subtitleTrackController.timer).to.not.exist; }); @@ -208,7 +209,7 @@ describe('SubtitleTrackController', function () { const details = new LevelDetails(''); subtitleTrackController.stopped = false; subtitleTrackController.trackId = 1; - subtitleTrackController.onSubtitleTrackLoaded({ id: 1, details, stats: new LoadStats() }); + subtitleTrackController.onSubtitleTrackLoaded(Events.SUBTITLE_TRACK_LOADED, { id: 1, details, stats: new LoadStats() }); expect(subtitleTrackController.timer).to.exist; }); @@ -217,7 +218,7 @@ describe('SubtitleTrackController', function () { details.live = false; subtitleTrackController.trackId = 1; subtitleTrackController.timer = self.setTimeout(() => {}, 0); - subtitleTrackController.onSubtitleTrackLoaded({ id: 1, details, stats: new LoadStats() }); + subtitleTrackController.onSubtitleTrackLoaded(Events.SUBTITLE_TRACK_LOADED, { id: 1, details, stats: new LoadStats() }); expect(subtitleTrackController.timer).to.not.exist; }); }); diff --git a/tests/unit/controller/timeline-controller-nonnative.js b/tests/unit/controller/timeline-controller-nonnative.js index c44f6f3b48b..2e4295d1f55 100644 --- a/tests/unit/controller/timeline-controller-nonnative.js +++ b/tests/unit/controller/timeline-controller-nonnative.js @@ -33,7 +33,6 @@ describe('Non-Native TimelineController functions', function () { it('fires the NON_NATIVE_TEXT_TRACKS_FOUND event', function (done) { hls.on(Hls.Events.NON_NATIVE_TEXT_TRACKS_FOUND, (event, data) => { const track = data.tracks[0]; - expect(track._id).to.equal('textTrack1'); expect(track.kind).to.equal('captions'); expect(track.default).to.equal(false); expect(track.label).to.equal(timelineController.captionsProperties.textTrack1.label); diff --git a/tests/unit/controller/timeline-controller.js b/tests/unit/controller/timeline-controller.js index 9bd78cc2951..e00fefb9f85 100644 --- a/tests/unit/controller/timeline-controller.js +++ b/tests/unit/controller/timeline-controller.js @@ -1,5 +1,6 @@ import TimelineController from '../../../src/controller/timeline-controller'; import Hls from '../../../src/hls'; +import { Events } from '../../../src/events'; describe('TimelineController', function () { let timelineController; @@ -16,7 +17,7 @@ describe('TimelineController', function () { it('should set default track to showing when displaySubtitles is true', function () { hls.subtitleTrackController = { subtitleDisplay: true }; - timelineController.onManifestLoaded({ + timelineController.onManifestLoaded(Events.MANIFEST_LOADED, { subtitles: [{ id: 0 }, { id: 1, default: true }] }); @@ -27,7 +28,7 @@ describe('TimelineController', function () { it('should set default track to hidden when displaySubtitles is false', function () { hls.subtitleTrackController = { subtitleDisplay: false }; - timelineController.onManifestLoaded({ + timelineController.onManifestLoaded(Events.MANIFEST_LOADED, { subtitles: [{ id: 0 }, { id: 1, default: true }] }); @@ -39,7 +40,7 @@ describe('TimelineController', function () { it('should reuse text track when track order is same between manifests', function () { hls.subtitleTrackController = { subtitleDisplay: false }; - timelineController.onManifestLoaded({ + timelineController.onManifestLoaded(Events.MANIFEST_LOADED, { subtitles: [{ id: 0, name: 'en' }, { id: 1, name: 'ru' }] }); @@ -52,7 +53,7 @@ describe('TimelineController', function () { expect(timelineController.media.textTracks[1].label).to.equal('ru'); expect(timelineController.media.textTracks.length).to.equal(2); - timelineController.onManifestLoaded({ + timelineController.onManifestLoaded(Events.MANIFEST_LOADED, { subtitles: [{ id: 0, name: 'en' }, { id: 1, name: 'ru' }] }); @@ -69,7 +70,7 @@ describe('TimelineController', function () { it('should reuse text track when track order is not same between manifests', function () { hls.subtitleTrackController = { subtitleDisplay: false }; - timelineController.onManifestLoaded({ + timelineController.onManifestLoaded(Events.MANIFEST_LOADED, { subtitles: [{ id: 0, name: 'en' }, { id: 1, name: 'ru' }] }); @@ -82,7 +83,7 @@ describe('TimelineController', function () { expect(timelineController.media.textTracks[1].label).to.equal('ru'); expect(timelineController.media.textTracks.length).to.equal(2); - timelineController.onManifestLoaded({ + timelineController.onManifestLoaded(Events.MANIFEST_LOADED, { subtitles: [{ id: 0, name: 'ru' }, { id: 1, name: 'en' }] }); diff --git a/tests/unit/demuxer/transmuxer.js b/tests/unit/demuxer/transmuxer.js index bd2b1e74c78..c7c37e8aaf1 100644 --- a/tests/unit/demuxer/transmuxer.js +++ b/tests/unit/demuxer/transmuxer.js @@ -17,7 +17,7 @@ describe('TransmuxerInterface tests', function () { expect(transmuxerInterface.hls).to.equal(hls, 'Hls object created'); expect(transmuxerInterface.id).to.equal(id, 'Id has been set up'); - expect(transmuxerInterface.observer.trigger).to.exist; + expect(transmuxerInterface.observer.emit).to.exist; expect(transmuxerInterface.observer.off).to.exist; expect(transmuxerInterface.transmuxer).to.exist; }); @@ -34,7 +34,7 @@ describe('TransmuxerInterface tests', function () { expect(transmuxerInterface.hls).to.equal(hls, 'Hls object created'); expect(transmuxerInterface.id).to.equal(id, 'Id has been set up'); - expect(transmuxerInterface.observer.trigger, 'trigger exists').to.exist; + expect(transmuxerInterface.observer.emit, 'emit exists').to.exist; expect(transmuxerInterface.observer.off, 'off exists').to.exist; expect(transmuxerInterface.worker, 'worker exists').to.exist; }); diff --git a/tests/unit/events.js b/tests/unit/events.js index 211c0103e41..d2dc8d44b2f 100644 --- a/tests/unit/events.js +++ b/tests/unit/events.js @@ -1,4 +1,4 @@ -import Events from '../../src/events'; +import { Events } from '../../src/events'; function getAllCapsSnakeCaseToCamelCase (eventType) { let eventValue = ''; diff --git a/tests/unit/hls.js b/tests/unit/hls.js index d67e73b984c..96cb22d0dac 100644 --- a/tests/unit/hls.js +++ b/tests/unit/hls.js @@ -7,7 +7,7 @@ describe('Hls', function () { const MOCKED_ESTIMATE = 2000; const hls = new Hls(); hls.abrController = { - _bwEstimator: { + bwEstimator: { getEstimate: () => MOCKED_ESTIMATE } }; diff --git a/webpack.config.js b/webpack.config.js index 1bce9c7ac66..9e92d88e7c9 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -81,7 +81,8 @@ const baseConfig = { } } }, - ['@babel/plugin-transform-object-assign'] + ['@babel/plugin-transform-object-assign'], + ['@babel/plugin-proposal-optional-chaining'] ] } }