web-speech-cognitive-services
Advanced tools
Comparing version 0.0.1-master.e70a05d to 0.0.1-master.f80884e
@@ -7,2 +7,4 @@ 'use strict'; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
@@ -14,2 +16,6 @@ | ||
var _eventAsPromise = require('event-as-promise'); | ||
var _eventAsPromise2 = _interopRequireDefault(_eventAsPromise); | ||
var _memoizeOne = require('memoize-one'); | ||
@@ -23,2 +29,4 @@ | ||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } | ||
@@ -77,6 +85,6 @@ | ||
var name = 'Browser'; | ||
var osVersion = "0.0.1-master.e70a05d"; | ||
var osVersion = "0.0.1-master.f80884e"; | ||
var manufacturer = 'web-speech-cognitive-services'; | ||
var model = 'web-speech-cognitive-services'; | ||
var deviceVersion = "0.0.1-master.e70a05d"; | ||
var deviceVersion = "0.0.1-master.f80884e"; | ||
@@ -144,139 +152,202 @@ var config = new CognitiveSpeech.RecognizerConfig(new CognitiveSpeech.SpeechConfig(new CognitiveSpeech.Context(new CognitiveSpeech.OS(platform, name, osVersion), new CognitiveSpeech.Device(manufacturer, model, deviceVersion))), mode, lang, CognitiveSpeech.SpeechResultFormat.Detailed); | ||
_createClass(CognitiveServicesSpeechRecognition, [{ | ||
key: '_transitTo', | ||
value: function _transitTo(nextReadyState) { | ||
// console.log(`_transitTo: readyState = ${ this.readyState }, nextReadyState = ${ nextReadyState }`); | ||
key: 'abort', | ||
value: function abort() { | ||
// TODO: Should redesign how to stop a recognition session | ||
// After abort is called, we should not saw it is a "success", "silent", or "no match" | ||
var _ref3 = this.recognizer || {}, | ||
AudioSource = _ref3.AudioSource; | ||
if (nextReadyState > this.readyState) { | ||
var lifecycleEvents = [null, null, this.onstart, this.onaudiostart, this.onsoundstart, this.onspeechstart, this.onspeechend, this.onsoundend, this.onaudioend, this.onend]; | ||
AudioSource && AudioSource.TurnOff(); | ||
if (this.readyState === AUDIO_START && nextReadyState >= AUDIO_END) { | ||
// If soundstart, speechstart, speechend, and soundend are not fired after audiostart, | ||
// we can skip them and just fire audioend directly | ||
this.readyState = SOUND_END; | ||
} | ||
this._aborted = true; | ||
} | ||
}, { | ||
key: 'emit', | ||
value: function emit(name, event) { | ||
var listener = this['on' + name]; | ||
for (var transition = this.readyState + 1; transition <= nextReadyState; transition++) { | ||
var eventListener = lifecycleEvents[transition]; | ||
// eventListener && console.log(`Firing "${ EVENT_TYPES[transition] }"`); | ||
eventListener && eventListener({ type: EVENT_TYPES[transition] }); | ||
} | ||
if (nextReadyState === END) { | ||
this.readyState = IDLE; | ||
} else { | ||
this.readyState = nextReadyState; | ||
} | ||
} | ||
listener && listener.call(this, _extends({}, event, { type: name })); | ||
} | ||
}, { | ||
key: '_handleDetailedPhrase', | ||
value: function _handleDetailedPhrase(event) { | ||
console.log(event); | ||
key: 'stop', | ||
value: function stop() { | ||
throw new Error('not supported'); | ||
} | ||
}, { | ||
key: 'start', | ||
value: function () { | ||
var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() { | ||
var recognizer, _toPromise, eventListener, promises, error, listeningStarted, recognitionStarted, gotFirstHypothesis, speechHypothesis, speechDetailedPhrase, recognitionResult; | ||
this._transitTo(AUDIO_END); | ||
return regeneratorRuntime.wrap(function _callee3$(_context3) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
case 0: | ||
recognizer = this.recognizer = this.createRecognizer(window.localStorage.getItem('SPEECH_KEY'), this.lang); | ||
_toPromise = toPromise(), eventListener = _toPromise.eventListener, promises = _objectWithoutProperties(_toPromise, ['eventListener']); | ||
if (CognitiveSpeech.RecognitionStatus[event.Result.RecognitionStatus] === CognitiveSpeech.RecognitionStatus.Success) { | ||
var nBest = event.Result.NBest; | ||
recognizer.Recognize(eventListener); | ||
this._aborted = false; | ||
this.onresult && this.onresult(buildSpeechResult(event.Result.NBest[0].Display, event.Result.NBest[0].Confidence, true)); | ||
} else { | ||
this.onerror && this.onerror({ error: event.Result.RecognitionStatus, type: 'error' }); | ||
} | ||
} | ||
}, { | ||
key: '_handleHypothesis', | ||
value: function _handleHypothesis(event) { | ||
console.log(event); | ||
_context3.next = 6; | ||
return promises.recognitionTriggered; | ||
this.onresult && this.onresult(buildSpeechResult(event.Result.Text, .5, false)); | ||
} | ||
}, { | ||
key: 'abort', | ||
value: function abort() { | ||
var _ref3 = this.recognizer || {}, | ||
AudioSource = _ref3.AudioSource; | ||
case 6: | ||
error = void 0; | ||
_context3.next = 9; | ||
return Promise.race([promises.listeningStarted, promises.recognitionEnded]); | ||
console.log('ABORT: ' + AudioSource); | ||
case 9: | ||
listeningStarted = _context3.sent; | ||
AudioSource && AudioSource.TurnOff(); | ||
} | ||
}, { | ||
key: 'handleRecognize', | ||
value: function handleRecognize(event) { | ||
try { | ||
var name = event.Name; | ||
if (!(listeningStarted.Name === 'RecognitionEndedEvent')) { | ||
_context3.next = 14; | ||
break; | ||
} | ||
// Possibly not authorized to use microphone | ||
if (listeningStarted.Status === CognitiveSpeech.RecognitionCompletionStatus.AudioSourceError) { | ||
error = 'not-allowed'; | ||
} else { | ||
error = CognitiveSpeech.RecognitionCompletionStatus[listeningStarted.Status]; | ||
} | ||
_context3.next = 51; | ||
break; | ||
console.log('handleRecognize: ' + name); | ||
case 14: | ||
this.emit('start'); | ||
switch (name) { | ||
case 'ListeningStartedEvent': | ||
this._transitTo(AUDIO_START); | ||
break; | ||
_context3.next = 17; | ||
return promises.connectingToService; | ||
case 'RecognitionEndedEvent': | ||
if (event.Status !== CognitiveSpeech.RecognitionCompletionStatus.Success) { | ||
this._transitTo(AUDIO_END); | ||
this.onerror && this.onerror({ error: CognitiveSpeech.RecognitionCompletionStatus[event.Status], type: 'error' }); | ||
} | ||
case 17: | ||
_context3.next = 19; | ||
return Promise.race([promises.recognitionStarted, promises.recognitionEnded]); | ||
this._transitTo(END); | ||
case 19: | ||
recognitionStarted = _context3.sent; | ||
break; | ||
case 'RecognitionStartedEvent': | ||
this._transitTo(SPEECH_START); | ||
break; | ||
this.emit('audiostart'); | ||
case 'RecognitionTriggeredEvent': | ||
this._transitTo(START); | ||
break; | ||
if (!(recognitionStarted.Name === 'RecognitionEndedEvent')) { | ||
_context3.next = 25; | ||
break; | ||
} | ||
case 'SpeechEndDetectedEvent': | ||
this._transitTo(SPEECH_END); | ||
break; | ||
// Possibly network error | ||
if (recognitionStarted.Status === CognitiveSpeech.RecognitionCompletionStatus.ConnectError) { | ||
error = 'network'; | ||
} else { | ||
error = CognitiveSpeech.RecognitionCompletionStatus[recognitionStarted.Status]; | ||
} | ||
_context3.next = 36; | ||
break; | ||
case 'SpeechStartDetectedEvent': | ||
this._transitTo(SPEECH_START); | ||
break; | ||
case 25: | ||
gotFirstHypothesis = void 0; | ||
case 'SpeechHypothesisEvent': | ||
this._handleHypothesis(event); | ||
break; | ||
case 26: | ||
_context3.next = 28; | ||
return Promise.race([promises.getSpeechHypothesisPromise(), promises.speechEndDetected]); | ||
case 'SpeechDetailedPhraseEvent': | ||
this._handleDetailedPhrase(event); | ||
break; | ||
case 28: | ||
speechHypothesis = _context3.sent; | ||
case 'ConnectingToServiceEvent': | ||
case 'SpeechSimplePhraseEvent': | ||
break; | ||
if (!(speechHypothesis.Name === 'SpeechEndDetectedEvent')) { | ||
_context3.next = 31; | ||
break; | ||
} | ||
default: | ||
console.warn('Unexpected event "' + name + '" from Cognitive Services, please file a bug to https://github.com/compulim/web-speech-cognitive-services'); | ||
break; | ||
} | ||
} catch (err) { | ||
// Cognitive Services will hide all exceptions thrown in the event listener | ||
// We need to show it otherwise when exception happen, we will not know what's going on | ||
console.error(err); | ||
throw err; | ||
return _context3.abrupt('break', 35); | ||
case 31: | ||
if (!gotFirstHypothesis) { | ||
gotFirstHypothesis = true; | ||
this.emit('soundstart'); | ||
this.emit('speechstart'); | ||
} | ||
this.emit('result', buildSpeechResult(speechHypothesis.Result.Text, .5, false)); | ||
case 33: | ||
_context3.next = 26; | ||
break; | ||
case 35: | ||
if (gotFirstHypothesis) { | ||
this.emit('speechend'); | ||
this.emit('soundend'); | ||
} | ||
case 36: | ||
this.emit('audioend'); | ||
if (!this._aborted) { | ||
_context3.next = 43; | ||
break; | ||
} | ||
error = 'aborted'; | ||
_context3.next = 41; | ||
return promises.recognitionEnded; | ||
case 41: | ||
_context3.next = 51; | ||
break; | ||
case 43: | ||
_context3.next = 45; | ||
return Promise.race([promises.speechDetailedPhrase, promises.recognitionEnded]); | ||
case 45: | ||
speechDetailedPhrase = _context3.sent; | ||
if (!(speechDetailedPhrase.Name !== 'RecognitionEndedEvent')) { | ||
_context3.next = 51; | ||
break; | ||
} | ||
recognitionResult = CognitiveSpeech.RecognitionStatus[speechDetailedPhrase.Result.RecognitionStatus]; | ||
if (recognitionResult === CognitiveSpeech.RecognitionStatus.Success) { | ||
this.emit('result', buildSpeechResult(speechDetailedPhrase.Result.NBest[0].Display, speechDetailedPhrase.Result.NBest[0].Confidence, true)); | ||
} else if (recognitionResult !== CognitiveSpeech.RecognitionStatus.NoMatch) { | ||
// Possibly silent or muted | ||
if (recognitionResult === CognitiveSpeech.RecognitionStatus.InitialSilenceTimeout) { | ||
error = 'no-speech'; | ||
} else { | ||
error = speechDetailedPhrase.Result.RecognitionStatus; | ||
} | ||
} | ||
_context3.next = 51; | ||
return promises.recognitionEnded; | ||
case 51: | ||
error && this.emit('error', { error: error }); | ||
this.emit('end'); | ||
case 53: | ||
case 'end': | ||
return _context3.stop(); | ||
} | ||
} | ||
}, _callee3, this); | ||
})); | ||
function start() { | ||
return _ref4.apply(this, arguments); | ||
} | ||
} | ||
}, { | ||
key: 'start', | ||
value: function start() { | ||
this.recognizer = this.createRecognizer(window.localStorage.getItem('SPEECH_KEY'), this.lang); | ||
this.recognizer.Recognize(this.handleRecognize.bind(this)); | ||
this._transitTo(START); | ||
} | ||
return start; | ||
}() | ||
}, { | ||
key: 'stop', | ||
value: function stop() { | ||
throw new Error('not supported'); | ||
} | ||
}, { | ||
key: 'grammars', | ||
@@ -336,3 +407,44 @@ get: function get() { | ||
function toPromise() { | ||
var events = { | ||
ConnectingToServiceEvent: new _eventAsPromise2.default(), | ||
ListeningStartedEvent: new _eventAsPromise2.default(), | ||
RecognitionEndedEvent: new _eventAsPromise2.default(), | ||
RecognitionStartedEvent: new _eventAsPromise2.default(), | ||
RecognitionTriggeredEvent: new _eventAsPromise2.default(), | ||
SpeechDetailedPhraseEvent: new _eventAsPromise2.default(), | ||
SpeechEndDetectedEvent: new _eventAsPromise2.default(), | ||
SpeechHypothesisEvent: new _eventAsPromise2.default(), | ||
SpeechSimplePhraseEvent: new _eventAsPromise2.default(), | ||
SpeechStartDetectedEvent: new _eventAsPromise2.default() | ||
}; | ||
return { | ||
connectingToService: events.ConnectingToServiceEvent.upcoming(), | ||
listeningStarted: events.ListeningStartedEvent.upcoming(), | ||
recognitionEnded: events.RecognitionEndedEvent.upcoming(), | ||
recognitionStarted: events.RecognitionStartedEvent.upcoming(), | ||
recognitionTriggered: events.RecognitionTriggeredEvent.upcoming(), | ||
speechDetailedPhrase: events.SpeechDetailedPhraseEvent.upcoming(), | ||
speechEndDetected: events.SpeechEndDetectedEvent.upcoming(), | ||
getSpeechHypothesisPromise: function getSpeechHypothesisPromise() { | ||
return events.SpeechHypothesisEvent.upcoming(); | ||
}, | ||
speechSimplePhrase: events.SpeechSimplePhraseEvent.upcoming(), | ||
speechStartDetected: events.SpeechStartDetectedEvent.upcoming(), | ||
eventListener: function eventListener(event) { | ||
var name = event.Name; | ||
var eventAsPromise = events[name]; | ||
if (eventAsPromise) { | ||
eventAsPromise.eventListener.call(null, event); | ||
} else { | ||
console.warn('Unexpected event "' + name + '" from Cognitive Services, please file a bug to https://github.com/compulim/web-speech-cognitive-services'); | ||
} | ||
} | ||
}; | ||
} | ||
exports.default = CognitiveServicesSpeechRecognition; | ||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9Db2duaXRpdmVTZXJ2aWNlc1NwZWVjaFJlY29nbml0aW9uLmpzIl0sIm5hbWVzIjpbIkNvZ25pdGl2ZVNwZWVjaCIsIlVOSU5JVCIsIklETEUiLCJTVEFSVCIsIkFVRElPX1NUQVJUIiwiU09VTkRfU1RBUlQiLCJTUEVFQ0hfU1RBUlQiLCJTUEVFQ0hfRU5EIiwiU09VTkRfRU5EIiwiQVVESU9fRU5EIiwiRU5EIiwiRVZFTlRfVFlQRVMiLCJidWlsZFNwZWVjaFJlc3VsdCIsInRyYW5zY3JpcHQiLCJjb25maWRlbmNlIiwiaXNGaW5hbCIsInJlc3VsdCIsInJlc3VsdHMiLCJ0eXBlIiwiQ29nbml0aXZlU2VydmljZXNTcGVlY2hSZWNvZ25pdGlvbiIsIl9sYW5nIiwicmVhZHlTdGF0ZSIsIm9uYXVkaW9zdGFydCIsIm9uYXVkaW9lbmQiLCJvbmVuZCIsIm9uZXJyb3IiLCJvbm5vbWF0Y2giLCJvbnJlc3VsdCIsIm9uc291bmRzdGFydCIsIm9uc291bmRlbmQiLCJvbnNwZWVjaHN0YXJ0Iiwib25zcGVlY2hlbmQiLCJvbnN0YXJ0IiwiY3JlYXRlUmVjb2duaXplciIsInN1YnNjcmlwdGlvbktleU9yVG9rZW5GZXRjaCIsImxhbmciLCJuYXZpZ2F0b3IiLCJsYW5ndWFnZSIsIm1vZGUiLCJSZWNvZ25pdGlvbk1vZGUiLCJJbnRlcmFjdGl2ZSIsInBsYXRmb3JtIiwid2luZG93IiwidXNlckFnZW50IiwibmFtZSIsIm9zVmVyc2lvbiIsIm1hbnVmYWN0dXJlciIsIm1vZGVsIiwiZGV2aWNlVmVyc2lvbiIsImNvbmZpZyIsIlJlY29nbml6ZXJDb25maWciLCJTcGVlY2hDb25maWciLCJDb250ZXh0IiwiT1MiLCJEZXZpY2UiLCJTcGVlY2hSZXN1bHRGb3JtYXQiLCJEZXRhaWxlZCIsImF1dGgiLCJDb2duaXRpdmVUb2tlbkF1dGhlbnRpY2F0aW9uIiwiYXV0aEZldGNoRXZlbnRJRCIsIkNvZ25pdGl2ZVN1YnNjcmlwdGlvbktleUF1dGhlbnRpY2F0aW9uIiwiQ3JlYXRlUmVjb2duaXplciIsIm5leHRSZWFkeVN0YXRlIiwibGlmZWN5Y2xlRXZlbnRzIiwidHJhbnNpdGlvbiIsImV2ZW50TGlzdGVuZXIiLCJldmVudCIsImNvbnNvbGUiLCJsb2ciLCJfdHJhbnNpdFRvIiwiUmVjb2duaXRpb25TdGF0dXMiLCJSZXN1bHQiLCJTdWNjZXNzIiwibkJlc3QiLCJOQmVzdCIsIkRpc3BsYXkiLCJDb25maWRlbmNlIiwiZXJyb3IiLCJUZXh0IiwicmVjb2duaXplciIsIkF1ZGlvU291cmNlIiwiVHVybk9mZiIsIk5hbWUiLCJTdGF0dXMiLCJSZWNvZ25pdGlvbkNvbXBsZXRpb25TdGF0dXMiLCJfaGFuZGxlSHlwb3RoZXNpcyIsIl9oYW5kbGVEZXRhaWxlZFBocmFzZSIsIndhcm4iLCJlcnIiLCJsb2NhbFN0b3JhZ2UiLCJnZXRJdGVtIiwiUmVjb2duaXplIiwiaGFuZGxlUmVjb2duaXplIiwiYmluZCIsIkVycm9yIiwibmV4dEdyYW1tYXJzIiwibmV4dExhbmciLCJuZXh0Q29udGludW91cyIsIm5leHRJbnRlcmltUmVzdWx0cyIsIm5leHRNYXhBbHRlcm5hdGl2ZXMiLCJuZXh0U2VydmljZVVSSSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFBQTs7SUFBWUEsZTs7QUFDWjs7Ozs7Ozs7Ozs7O0FBRUEsSUFBTUMsU0FBUyxDQUFmO0FBQ0EsSUFBTUMsT0FBTyxDQUFiO0FBQ0EsSUFBTUMsUUFBUSxDQUFkO0FBQ0EsSUFBTUMsY0FBYyxDQUFwQjtBQUNBLElBQU1DLGNBQWMsQ0FBcEI7QUFDQSxJQUFNQyxlQUFlLENBQXJCO0FBQ0EsSUFBTUMsYUFBYSxDQUFuQjtBQUNBLElBQU1DLFlBQVksQ0FBbEI7QUFDQSxJQUFNQyxZQUFZLENBQWxCO0FBQ0EsSUFBTUMsTUFBTSxDQUFaOztBQUVBLElBQU1DLGNBQWMsQ0FDbEIsSUFEa0IsRUFFbEIsSUFGa0IsRUFHbEIsT0FIa0IsRUFJbEIsWUFKa0IsRUFLbEIsWUFMa0IsRUFNbEIsYUFOa0IsRUFPbEIsV0FQa0IsRUFRbEIsVUFSa0IsRUFTbEIsVUFUa0IsRUFVbEIsS0FWa0IsQ0FBcEI7O0FBYUEsU0FBU0MsaUJBQVQsQ0FBMkJDLFVBQTNCLEVBQXVDQyxVQUF2QyxFQUFtREMsT0FBbkQsRUFBNEQ7QUFDMUQsTUFBTUMsU0FBUyxDQUFDLEVBQUVGLHNCQUFGLEVBQWNELHNCQUFkLEVBQUQsQ0FBZjs7QUFFQUcsU0FBT0QsT0FBUCxHQUFpQkEsT0FBakI7O0FBRUEsU0FBTyxFQUFFRSxTQUFTLENBQUNELE1BQUQsQ0FBWCxFQUFxQkUsTUFBTSxRQUEzQixFQUFQO0FBQ0Q7O0lBRUtDLGtDO0FBQ0osZ0RBQWM7QUFBQTs7QUFBQTs7QUFDWixTQUFLQyxLQUFMLEdBQWEsRUFBYjs7QUFFQSxTQUFLQyxVQUFMLEdBQWtCLENBQWxCOztBQUVBLFNBQUtDLFlBQUwsR0FBb0IsSUFBcEI7QUFDQSxTQUFLQyxVQUFMLEdBQWtCLElBQWxCO0FBQ0EsU0FBS0MsS0FBTCxHQUFhLElBQWI7QUFDQSxTQUFLQyxPQUFMLEdBQWUsSUFBZjtBQUNBLFNBQUtDLFNBQUwsR0FBaUIsSUFBakI7QUFDQSxTQUFLQyxRQUFMLEdBQWdCLElBQWhCO0FBQ0EsU0FBS0MsWUFBTCxHQUFvQixJQUFwQjtBQUNBLFNBQUtDLFVBQUwsR0FBa0IsSUFBbEI7QUFDQSxTQUFLQyxhQUFMLEdBQXFCLElBQXJCO0FBQ0EsU0FBS0MsV0FBTCxHQUFtQixJQUFuQjtBQUNBLFNBQUtDLE9BQUwsR0FBZSxJQUFmOztBQUVBLFNBQUtDLGdCQUFMLEdBQXdCLDBCQUFRLFVBQzlCQywyQkFEOEIsRUFJM0I7QUFBQSxVQUZIQyxJQUVHLHVFQUZJQyxVQUFVQyxRQUVkO0FBQUEsVUFESEMsSUFDRyx1RUFESXRDLGdCQUFnQnVDLGVBQWhCLENBQWdDQyxXQUNwQzs7QUFDSCxVQUFNQyxXQUFXQyxPQUFPTixTQUFQLENBQWlCTyxTQUFsQztBQUNBLFVBQU1DLE9BQU8sU0FBYjtBQUNBLFVBQU1DLGtDQUFOO0FBQ0EsVUFBTUMsZUFBZSwrQkFBckI7QUFDQSxVQUFNQyxRQUFRLCtCQUFkO0FBQ0EsVUFBTUMsc0NBQU47O0FBRUEsVUFBTUMsU0FBUyxJQUFJakQsZ0JBQWdCa0QsZ0JBQXBCLENBQ2IsSUFBSWxELGdCQUFnQm1ELFlBQXBCLENBQ0UsSUFBSW5ELGdCQUFnQm9ELE9BQXBCLENBQ0UsSUFBSXBELGdCQUFnQnFELEVBQXBCLENBQXVCWixRQUF2QixFQUFpQ0csSUFBakMsRUFBdUNDLFNBQXZDLENBREYsRUFFRSxJQUFJN0MsZ0JBQWdCc0QsTUFBcEIsQ0FBMkJSLFlBQTNCLEVBQXlDQyxLQUF6QyxFQUFnREMsYUFBaEQsQ0FGRixDQURGLENBRGEsRUFPYlYsSUFQYSxFQVFiSCxJQVJhLEVBU2JuQyxnQkFBZ0J1RCxrQkFBaEIsQ0FBbUNDLFFBVHRCLENBQWY7O0FBWUEsVUFBSUMsYUFBSjs7QUFFQSxVQUFJLE9BQU92QiwyQkFBUCxLQUF1QyxVQUEzQyxFQUF1RDtBQUNyRHVCLGVBQU8sSUFBSXpELGdCQUFnQjBELDRCQUFwQjtBQUFBLDZFQUNMLGlCQUFNQyxnQkFBTjtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSwyQkFBZ0N6Qiw0QkFBNEJ5QixnQkFBNUIsRUFBOEMsS0FBOUMsQ0FBaEM7O0FBQUE7QUFBQTs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxXQURLOztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsOEVBRUwsa0JBQU1BLGdCQUFOO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLDJCQUFnQ3pCLDRCQUE0QnlCLGdCQUE1QixFQUE4QyxJQUE5QyxDQUFoQzs7QUFBQTtBQUFBOztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLFdBRks7O0FBQUE7QUFBQTtBQUFBO0FBQUEsWUFBUDtBQUlELE9BTEQsTUFLTztBQUNMRixlQUFPLElBQUl6RCxnQkFBZ0I0RCxzQ0FBcEIsQ0FBMkQxQiwyQkFBM0QsQ0FBUDtBQUNEOztBQUVELGFBQU9sQyxnQkFBZ0I2RCxnQkFBaEIsQ0FBaUNaLE1BQWpDLEVBQXlDUSxJQUF6QyxDQUFQO0FBQ0QsS0FwQ3VCLENBQXhCO0FBcUNEOzs7OytCQTBCVUssYyxFQUFnQjtBQUN6Qjs7QUFFQSxVQUFJQSxpQkFBaUIsS0FBS3pDLFVBQTFCLEVBQXNDO0FBQ3BDLFlBQU0wQyxrQkFBa0IsQ0FDdEIsSUFEc0IsRUFFdEIsSUFGc0IsRUFHdEIsS0FBSy9CLE9BSGlCLEVBSXRCLEtBQUtWLFlBSmlCLEVBS3RCLEtBQUtNLFlBTGlCLEVBTXRCLEtBQUtFLGFBTmlCLEVBT3RCLEtBQUtDLFdBUGlCLEVBUXRCLEtBQUtGLFVBUmlCLEVBU3RCLEtBQUtOLFVBVGlCLEVBVXRCLEtBQUtDLEtBVmlCLENBQXhCOztBQWFBLFlBQ0UsS0FBS0gsVUFBTCxLQUFvQmpCLFdBQXBCLElBQ0cwRCxrQkFBa0JyRCxTQUZ2QixFQUdFO0FBQ0E7QUFDQTtBQUNBLGVBQUtZLFVBQUwsR0FBa0JiLFNBQWxCO0FBQ0Q7O0FBRUQsYUFBSyxJQUFJd0QsYUFBYSxLQUFLM0MsVUFBTCxHQUFrQixDQUF4QyxFQUEyQzJDLGNBQWNGLGNBQXpELEVBQXlFRSxZQUF6RSxFQUF1RjtBQUNyRixjQUFNQyxnQkFBZ0JGLGdCQUFnQkMsVUFBaEIsQ0FBdEI7O0FBRUE7QUFDQUMsMkJBQWlCQSxjQUFjLEVBQUUvQyxNQUFNUCxZQUFZcUQsVUFBWixDQUFSLEVBQWQsQ0FBakI7QUFDRDs7QUFFRCxZQUFJRixtQkFBbUJwRCxHQUF2QixFQUE0QjtBQUMxQixlQUFLVyxVQUFMLEdBQWtCbkIsSUFBbEI7QUFDRCxTQUZELE1BRU87QUFDTCxlQUFLbUIsVUFBTCxHQUFrQnlDLGNBQWxCO0FBQ0Q7QUFDRjtBQUNGOzs7MENBRXFCSSxLLEVBQU87QUFDM0JDLGNBQVFDLEdBQVIsQ0FBWUYsS0FBWjs7QUFFQSxXQUFLRyxVQUFMLENBQWdCNUQsU0FBaEI7O0FBRUEsVUFBSVQsZ0JBQWdCc0UsaUJBQWhCLENBQWtDSixNQUFNSyxNQUFOLENBQWFELGlCQUEvQyxNQUFzRXRFLGdCQUFnQnNFLGlCQUFoQixDQUFrQ0UsT0FBNUcsRUFBcUg7QUFBQSxZQUNwR0MsS0FEb0csR0FDMUZQLE1BQU1LLE1BRG9GLENBQzNHRyxLQUQyRzs7O0FBR25ILGFBQUsvQyxRQUFMLElBQWlCLEtBQUtBLFFBQUwsQ0FBY2Ysa0JBQWtCc0QsTUFBTUssTUFBTixDQUFhRyxLQUFiLENBQW1CLENBQW5CLEVBQXNCQyxPQUF4QyxFQUFpRFQsTUFBTUssTUFBTixDQUFhRyxLQUFiLENBQW1CLENBQW5CLEVBQXNCRSxVQUF2RSxFQUFtRixJQUFuRixDQUFkLENBQWpCO0FBQ0QsT0FKRCxNQUlPO0FBQ0wsYUFBS25ELE9BQUwsSUFBZ0IsS0FBS0EsT0FBTCxDQUFhLEVBQUVvRCxPQUFPWCxNQUFNSyxNQUFOLENBQWFELGlCQUF0QixFQUF5Q3BELE1BQU0sT0FBL0MsRUFBYixDQUFoQjtBQUNEO0FBQ0Y7OztzQ0FFaUJnRCxLLEVBQU87QUFDdkJDLGNBQVFDLEdBQVIsQ0FBWUYsS0FBWjs7QUFFQSxXQUFLdkMsUUFBTCxJQUFpQixLQUFLQSxRQUFMLENBQWNmLGtCQUFrQnNELE1BQU1LLE1BQU4sQ0FBYU8sSUFBL0IsRUFBcUMsRUFBckMsRUFBeUMsS0FBekMsQ0FBZCxDQUFqQjtBQUNEOzs7NEJBRU87QUFBQSxrQkFDa0IsS0FBS0MsVUFBTCxJQUFtQixFQURyQztBQUFBLFVBQ0VDLFdBREYsU0FDRUEsV0FERjs7QUFHTmIsY0FBUUMsR0FBUixhQUF1QlksV0FBdkI7O0FBRUFBLHFCQUFlQSxZQUFZQyxPQUFaLEVBQWY7QUFDRDs7O29DQUVlZixLLEVBQU87QUFDckIsVUFBSTtBQUFBLFlBQ1l0QixJQURaLEdBQ3FCc0IsS0FEckIsQ0FDTWdCLElBRE47OztBQUdGZixnQkFBUUMsR0FBUix1QkFBaUN4QixJQUFqQzs7QUFFQSxnQkFBUUEsSUFBUjtBQUNBLGVBQUssdUJBQUw7QUFDRSxpQkFBS3lCLFVBQUwsQ0FBZ0JqRSxXQUFoQjtBQUNBOztBQUVGLGVBQUssdUJBQUw7QUFDRSxnQkFBSThELE1BQU1pQixNQUFOLEtBQWlCbkYsZ0JBQWdCb0YsMkJBQWhCLENBQTRDWixPQUFqRSxFQUEwRTtBQUN4RSxtQkFBS0gsVUFBTCxDQUFnQjVELFNBQWhCO0FBQ0EsbUJBQUtnQixPQUFMLElBQWdCLEtBQUtBLE9BQUwsQ0FBYSxFQUFFb0QsT0FBTzdFLGdCQUFnQm9GLDJCQUFoQixDQUE0Q2xCLE1BQU1pQixNQUFsRCxDQUFULEVBQW9FakUsTUFBTSxPQUExRSxFQUFiLENBQWhCO0FBQ0Q7O0FBRUQsaUJBQUttRCxVQUFMLENBQWdCM0QsR0FBaEI7O0FBRUE7O0FBRUYsZUFBSyx5QkFBTDtBQUNFLGlCQUFLMkQsVUFBTCxDQUFnQi9ELFlBQWhCO0FBQ0E7O0FBRUYsZUFBSywyQkFBTDtBQUNFLGlCQUFLK0QsVUFBTCxDQUFnQmxFLEtBQWhCO0FBQ0E7O0FBRUYsZUFBSyx3QkFBTDtBQUNFLGlCQUFLa0UsVUFBTCxDQUFnQjlELFVBQWhCO0FBQ0E7O0FBRUYsZUFBSywwQkFBTDtBQUNFLGlCQUFLOEQsVUFBTCxDQUFnQi9ELFlBQWhCO0FBQ0E7O0FBRUYsZUFBSyx1QkFBTDtBQUNFLGlCQUFLK0UsaUJBQUwsQ0FBdUJuQixLQUF2QjtBQUNBOztBQUVGLGVBQUssMkJBQUw7QUFDRSxpQkFBS29CLHFCQUFMLENBQTJCcEIsS0FBM0I7QUFDQTs7QUFFRixlQUFLLDBCQUFMO0FBQ0EsZUFBSyx5QkFBTDtBQUNFOztBQUVGO0FBQ0VDLG9CQUFRb0IsSUFBUix3QkFBb0MzQyxJQUFwQztBQUNBO0FBN0NGO0FBK0NELE9BcERELENBb0RFLE9BQU80QyxHQUFQLEVBQVk7QUFDWjtBQUNBO0FBQ0FyQixnQkFBUVUsS0FBUixDQUFjVyxHQUFkO0FBQ0EsY0FBTUEsR0FBTjtBQUNEO0FBQ0Y7Ozs0QkFFTztBQUNOLFdBQUtULFVBQUwsR0FBa0IsS0FBSzlDLGdCQUFMLENBQ2hCUyxPQUFPK0MsWUFBUCxDQUFvQkMsT0FBcEIsQ0FBNEIsWUFBNUIsQ0FEZ0IsRUFFaEIsS0FBS3ZELElBRlcsQ0FBbEI7O0FBS0EsV0FBSzRDLFVBQUwsQ0FBZ0JZLFNBQWhCLENBQTBCLEtBQUtDLGVBQUwsQ0FBcUJDLElBQXJCLENBQTBCLElBQTFCLENBQTFCO0FBQ0EsV0FBS3hCLFVBQUwsQ0FBZ0JsRSxLQUFoQjtBQUNEOzs7MkJBRU07QUFDTCxZQUFNLElBQUkyRixLQUFKLENBQVUsZUFBVixDQUFOO0FBQ0Q7Ozt3QkF0S2M7QUFBRTtBQUFTLEs7c0JBQ2JDLFksRUFBYztBQUN6QjtBQUNEOzs7d0JBRVU7QUFBRSxhQUFPLEtBQUszRSxLQUFaO0FBQW9CLEs7c0JBQ3hCNEUsUSxFQUFVO0FBQUUsV0FBSzVFLEtBQUwsR0FBYTRFLFFBQWI7QUFBd0I7Ozt3QkFFNUI7QUFBRSxhQUFPLEtBQVA7QUFBZSxLO3NCQUNuQkMsYyxFQUFnQjtBQUFFLFlBQU0sSUFBSUgsS0FBSixDQUFVLGVBQVYsQ0FBTjtBQUFtQzs7O3dCQUUvQztBQUFFLGFBQU8sSUFBUDtBQUFjLEs7c0JBQ2xCSSxrQixFQUFvQjtBQUNyQyxVQUFJLENBQUNBLGtCQUFMLEVBQXlCO0FBQ3ZCLGNBQU0sSUFBSUosS0FBSixDQUFVLGVBQVYsQ0FBTjtBQUNEO0FBQ0Y7Ozt3QkFFcUI7QUFBRSxhQUFPLENBQVA7QUFBVyxLO3NCQUNmSyxtQixFQUFxQjtBQUFFLFlBQU0sSUFBSUwsS0FBSixDQUFVLGVBQVYsQ0FBTjtBQUFtQzs7O3dCQUU3RDtBQUFFLGFBQU8sSUFBUDtBQUFjLEs7c0JBQ2xCTSxjLEVBQWdCO0FBQUUsWUFBTSxJQUFJTixLQUFKLENBQVUsZUFBVixDQUFOO0FBQW1DOzs7Ozs7a0JBbUp2RDNFLGtDIiwiZmlsZSI6IkNvZ25pdGl2ZVNlcnZpY2VzU3BlZWNoUmVjb2duaXRpb24uanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBDb2duaXRpdmVTcGVlY2ggZnJvbSAnbWljcm9zb2Z0LXNwZWVjaC1icm93c2VyLXNkayc7XG5pbXBvcnQgbWVtb2l6ZSBmcm9tICdtZW1vaXplLW9uZSc7XG5cbmNvbnN0IFVOSU5JVCA9IDA7XG5jb25zdCBJRExFID0gMTtcbmNvbnN0IFNUQVJUID0gMjtcbmNvbnN0IEFVRElPX1NUQVJUID0gMztcbmNvbnN0IFNPVU5EX1NUQVJUID0gNDtcbmNvbnN0IFNQRUVDSF9TVEFSVCA9IDU7XG5jb25zdCBTUEVFQ0hfRU5EID0gNjtcbmNvbnN0IFNPVU5EX0VORCA9IDc7XG5jb25zdCBBVURJT19FTkQgPSA4O1xuY29uc3QgRU5EID0gOTtcblxuY29uc3QgRVZFTlRfVFlQRVMgPSBbXG4gIG51bGwsXG4gIG51bGwsXG4gICdzdGFydCcsXG4gICdhdWRpb3N0YXJ0JyxcbiAgJ3NvdW5kc3RhcnQnLFxuICAnc3BlZWNoc3RhcnQnLFxuICAnc3BlZWNoZW5kJyxcbiAgJ3NvdW5kZW5kJyxcbiAgJ2F1ZGlvZW5kJyxcbiAgJ2VuZCdcbl07XG5cbmZ1bmN0aW9uIGJ1aWxkU3BlZWNoUmVzdWx0KHRyYW5zY3JpcHQsIGNvbmZpZGVuY2UsIGlzRmluYWwpIHtcbiAgY29uc3QgcmVzdWx0ID0gW3sgY29uZmlkZW5jZSwgdHJhbnNjcmlwdCB9XTtcblxuICByZXN1bHQuaXNGaW5hbCA9IGlzRmluYWw7XG5cbiAgcmV0dXJuIHsgcmVzdWx0czogW3Jlc3VsdF0sIHR5cGU6ICdyZXN1bHQnIH07XG59XG5cbmNsYXNzIENvZ25pdGl2ZVNlcnZpY2VzU3BlZWNoUmVjb2duaXRpb24ge1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLl9sYW5nID0gJyc7XG5cbiAgICB0aGlzLnJlYWR5U3RhdGUgPSAwO1xuXG4gICAgdGhpcy5vbmF1ZGlvc3RhcnQgPSBudWxsO1xuICAgIHRoaXMub25hdWRpb2VuZCA9IG51bGw7XG4gICAgdGhpcy5vbmVuZCA9IG51bGw7XG4gICAgdGhpcy5vbmVycm9yID0gbnVsbDtcbiAgICB0aGlzLm9ubm9tYXRjaCA9IG51bGw7XG4gICAgdGhpcy5vbnJlc3VsdCA9IG51bGw7XG4gICAgdGhpcy5vbnNvdW5kc3RhcnQgPSBudWxsO1xuICAgIHRoaXMub25zb3VuZGVuZCA9IG51bGw7XG4gICAgdGhpcy5vbnNwZWVjaHN0YXJ0ID0gbnVsbDtcbiAgICB0aGlzLm9uc3BlZWNoZW5kID0gbnVsbDtcbiAgICB0aGlzLm9uc3RhcnQgPSBudWxsO1xuXG4gICAgdGhpcy5jcmVhdGVSZWNvZ25pemVyID0gbWVtb2l6ZSgoXG4gICAgICBzdWJzY3JpcHRpb25LZXlPclRva2VuRmV0Y2gsXG4gICAgICBsYW5nID0gbmF2aWdhdG9yLmxhbmd1YWdlLFxuICAgICAgbW9kZSA9IENvZ25pdGl2ZVNwZWVjaC5SZWNvZ25pdGlvbk1vZGUuSW50ZXJhY3RpdmVcbiAgICApID0+IHtcbiAgICAgIGNvbnN0IHBsYXRmb3JtID0gd2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQ7XG4gICAgICBjb25zdCBuYW1lID0gJ0Jyb3dzZXInO1xuICAgICAgY29uc3Qgb3NWZXJzaW9uID0gVkVSU0lPTjtcbiAgICAgIGNvbnN0IG1hbnVmYWN0dXJlciA9ICd3ZWItc3BlZWNoLWNvZ25pdGl2ZS1zZXJ2aWNlcyc7XG4gICAgICBjb25zdCBtb2RlbCA9ICd3ZWItc3BlZWNoLWNvZ25pdGl2ZS1zZXJ2aWNlcyc7XG4gICAgICBjb25zdCBkZXZpY2VWZXJzaW9uID0gVkVSU0lPTjtcblxuICAgICAgY29uc3QgY29uZmlnID0gbmV3IENvZ25pdGl2ZVNwZWVjaC5SZWNvZ25pemVyQ29uZmlnKFxuICAgICAgICBuZXcgQ29nbml0aXZlU3BlZWNoLlNwZWVjaENvbmZpZyhcbiAgICAgICAgICBuZXcgQ29nbml0aXZlU3BlZWNoLkNvbnRleHQoXG4gICAgICAgICAgICBuZXcgQ29nbml0aXZlU3BlZWNoLk9TKHBsYXRmb3JtLCBuYW1lLCBvc1ZlcnNpb24pLFxuICAgICAgICAgICAgbmV3IENvZ25pdGl2ZVNwZWVjaC5EZXZpY2UobWFudWZhY3R1cmVyLCBtb2RlbCwgZGV2aWNlVmVyc2lvbilcbiAgICAgICAgICApXG4gICAgICAgICksXG4gICAgICAgIG1vZGUsXG4gICAgICAgIGxhbmcsXG4gICAgICAgIENvZ25pdGl2ZVNwZWVjaC5TcGVlY2hSZXN1bHRGb3JtYXQuRGV0YWlsZWRcbiAgICAgICk7XG5cbiAgICAgIGxldCBhdXRoO1xuXG4gICAgICBpZiAodHlwZW9mIHN1YnNjcmlwdGlvbktleU9yVG9rZW5GZXRjaCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBhdXRoID0gbmV3IENvZ25pdGl2ZVNwZWVjaC5Db2duaXRpdmVUb2tlbkF1dGhlbnRpY2F0aW9uKFxuICAgICAgICAgIGFzeW5jIGF1dGhGZXRjaEV2ZW50SUQgPT4gYXdhaXQgc3Vic2NyaXB0aW9uS2V5T3JUb2tlbkZldGNoKGF1dGhGZXRjaEV2ZW50SUQsIGZhbHNlKSxcbiAgICAgICAgICBhc3luYyBhdXRoRmV0Y2hFdmVudElEID0+IGF3YWl0IHN1YnNjcmlwdGlvbktleU9yVG9rZW5GZXRjaChhdXRoRmV0Y2hFdmVudElELCB0cnVlKVxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYXV0aCA9IG5ldyBDb2duaXRpdmVTcGVlY2guQ29nbml0aXZlU3Vic2NyaXB0aW9uS2V5QXV0aGVudGljYXRpb24oc3Vic2NyaXB0aW9uS2V5T3JUb2tlbkZldGNoKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIENvZ25pdGl2ZVNwZWVjaC5DcmVhdGVSZWNvZ25pemVyKGNvbmZpZywgYXV0aCk7XG4gICAgfSk7XG4gIH1cblxuICBnZXQgZ3JhbW1hcnMoKSB7IHJldHVybjsgfVxuICBzZXQgZ3JhbW1hcnMobmV4dEdyYW1tYXJzKSB7XG4gICAgLy8gdGhyb3cgbmV3IEVycm9yKCdub3Qgc3VwcG9ydGVkJyk7XG4gIH1cblxuICBnZXQgbGFuZygpIHsgcmV0dXJuIHRoaXMuX2xhbmc7IH1cbiAgc2V0IGxhbmcobmV4dExhbmcpIHsgdGhpcy5fbGFuZyA9IG5leHRMYW5nOyB9XG5cbiAgZ2V0IGNvbnRpbnVvdXMoKSB7IHJldHVybiBmYWxzZTsgfVxuICBzZXQgY29udGludW91cyhuZXh0Q29udGludW91cykgeyB0aHJvdyBuZXcgRXJyb3IoJ25vdCBzdXBwb3J0ZWQnKTsgfVxuXG4gIGdldCBpbnRlcmltUmVzdWx0cygpIHsgcmV0dXJuIHRydWU7IH1cbiAgc2V0IGludGVyaW1SZXN1bHRzKG5leHRJbnRlcmltUmVzdWx0cykge1xuICAgIGlmICghbmV4dEludGVyaW1SZXN1bHRzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ25vdCBzdXBwb3J0ZWQnKTtcbiAgICB9XG4gIH1cblxuICBnZXQgbWF4QWx0ZXJuYXRpdmVzKCkgeyByZXR1cm4gMTsgfVxuICBzZXQgbWF4QWx0ZXJuYXRpdmVzKG5leHRNYXhBbHRlcm5hdGl2ZXMpIHsgdGhyb3cgbmV3IEVycm9yKCdub3Qgc3VwcG9ydGVkJyk7IH1cblxuICBnZXQgc2VydmljZVVSSSgpIHsgcmV0dXJuIG51bGw7IH1cbiAgc2V0IHNlcnZpY2VVUkkobmV4dFNlcnZpY2VVUkkpIHsgdGhyb3cgbmV3IEVycm9yKCdub3Qgc3VwcG9ydGVkJyk7IH1cblxuICBfdHJhbnNpdFRvKG5leHRSZWFkeVN0YXRlKSB7XG4gICAgLy8gY29uc29sZS5sb2coYF90cmFuc2l0VG86IHJlYWR5U3RhdGUgPSAkeyB0aGlzLnJlYWR5U3RhdGUgfSwgbmV4dFJlYWR5U3RhdGUgPSAkeyBuZXh0UmVhZHlTdGF0ZSB9YCk7XG5cbiAgICBpZiAobmV4dFJlYWR5U3RhdGUgPiB0aGlzLnJlYWR5U3RhdGUpIHtcbiAgICAgIGNvbnN0IGxpZmVjeWNsZUV2ZW50cyA9IFtcbiAgICAgICAgbnVsbCxcbiAgICAgICAgbnVsbCxcbiAgICAgICAgdGhpcy5vbnN0YXJ0LFxuICAgICAgICB0aGlzLm9uYXVkaW9zdGFydCxcbiAgICAgICAgdGhpcy5vbnNvdW5kc3RhcnQsXG4gICAgICAgIHRoaXMub25zcGVlY2hzdGFydCxcbiAgICAgICAgdGhpcy5vbnNwZWVjaGVuZCxcbiAgICAgICAgdGhpcy5vbnNvdW5kZW5kLFxuICAgICAgICB0aGlzLm9uYXVkaW9lbmQsXG4gICAgICAgIHRoaXMub25lbmRcbiAgICAgIF07XG5cbiAgICAgIGlmIChcbiAgICAgICAgdGhpcy5yZWFkeVN0YXRlID09PSBBVURJT19TVEFSVFxuICAgICAgICAmJiBuZXh0UmVhZHlTdGF0ZSA+PSBBVURJT19FTkRcbiAgICAgICkge1xuICAgICAgICAvLyBJZiBzb3VuZHN0YXJ0LCBzcGVlY2hzdGFydCwgc3BlZWNoZW5kLCBhbmQgc291bmRlbmQgYXJlIG5vdCBmaXJlZCBhZnRlciBhdWRpb3N0YXJ0LFxuICAgICAgICAvLyB3ZSBjYW4gc2tpcCB0aGVtIGFuZCBqdXN0IGZpcmUgYXVkaW9lbmQgZGlyZWN0bHlcbiAgICAgICAgdGhpcy5yZWFkeVN0YXRlID0gU09VTkRfRU5EO1xuICAgICAgfVxuXG4gICAgICBmb3IgKGxldCB0cmFuc2l0aW9uID0gdGhpcy5yZWFkeVN0YXRlICsgMTsgdHJhbnNpdGlvbiA8PSBuZXh0UmVhZHlTdGF0ZTsgdHJhbnNpdGlvbisrKSB7XG4gICAgICAgIGNvbnN0IGV2ZW50TGlzdGVuZXIgPSBsaWZlY3ljbGVFdmVudHNbdHJhbnNpdGlvbl07XG5cbiAgICAgICAgLy8gZXZlbnRMaXN0ZW5lciAmJiBjb25zb2xlLmxvZyhgRmlyaW5nIFwiJHsgRVZFTlRfVFlQRVNbdHJhbnNpdGlvbl0gfVwiYCk7XG4gICAgICAgIGV2ZW50TGlzdGVuZXIgJiYgZXZlbnRMaXN0ZW5lcih7IHR5cGU6IEVWRU5UX1RZUEVTW3RyYW5zaXRpb25dIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAobmV4dFJlYWR5U3RhdGUgPT09IEVORCkge1xuICAgICAgICB0aGlzLnJlYWR5U3RhdGUgPSBJRExFO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5yZWFkeVN0YXRlID0gbmV4dFJlYWR5U3RhdGU7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgX2hhbmRsZURldGFpbGVkUGhyYXNlKGV2ZW50KSB7XG4gICAgY29uc29sZS5sb2coZXZlbnQpO1xuXG4gICAgdGhpcy5fdHJhbnNpdFRvKEFVRElPX0VORCk7XG5cbiAgICBpZiAoQ29nbml0aXZlU3BlZWNoLlJlY29nbml0aW9uU3RhdHVzW2V2ZW50LlJlc3VsdC5SZWNvZ25pdGlvblN0YXR1c10gPT09IENvZ25pdGl2ZVNwZWVjaC5SZWNvZ25pdGlvblN0YXR1cy5TdWNjZXNzKSB7XG4gICAgICBjb25zdCB7IE5CZXN0OiBuQmVzdCB9ID0gZXZlbnQuUmVzdWx0O1xuXG4gICAgICB0aGlzLm9ucmVzdWx0ICYmIHRoaXMub25yZXN1bHQoYnVpbGRTcGVlY2hSZXN1bHQoZXZlbnQuUmVzdWx0Lk5CZXN0WzBdLkRpc3BsYXksIGV2ZW50LlJlc3VsdC5OQmVzdFswXS5Db25maWRlbmNlLCB0cnVlKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMub25lcnJvciAmJiB0aGlzLm9uZXJyb3IoeyBlcnJvcjogZXZlbnQuUmVzdWx0LlJlY29nbml0aW9uU3RhdHVzLCB0eXBlOiAnZXJyb3InIH0pO1xuICAgIH1cbiAgfVxuXG4gIF9oYW5kbGVIeXBvdGhlc2lzKGV2ZW50KSB7XG4gICAgY29uc29sZS5sb2coZXZlbnQpO1xuXG4gICAgdGhpcy5vbnJlc3VsdCAmJiB0aGlzLm9ucmVzdWx0KGJ1aWxkU3BlZWNoUmVzdWx0KGV2ZW50LlJlc3VsdC5UZXh0LCAuNSwgZmFsc2UpKTtcbiAgfVxuXG4gIGFib3J0KCkge1xuICAgIGNvbnN0IHsgQXVkaW9Tb3VyY2UgfSA9IHRoaXMucmVjb2duaXplciB8fCB7fTtcblxuICAgIGNvbnNvbGUubG9nKGBBQk9SVDogJHsgQXVkaW9Tb3VyY2UgfWApO1xuXG4gICAgQXVkaW9Tb3VyY2UgJiYgQXVkaW9Tb3VyY2UuVHVybk9mZigpO1xuICB9XG5cbiAgaGFuZGxlUmVjb2duaXplKGV2ZW50KSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHsgTmFtZTogbmFtZSB9ID0gZXZlbnQ7XG5cbiAgICAgIGNvbnNvbGUubG9nKGBoYW5kbGVSZWNvZ25pemU6ICR7IG5hbWUgfWApO1xuXG4gICAgICBzd2l0Y2ggKG5hbWUpIHtcbiAgICAgIGNhc2UgJ0xpc3RlbmluZ1N0YXJ0ZWRFdmVudCc6XG4gICAgICAgIHRoaXMuX3RyYW5zaXRUbyhBVURJT19TVEFSVCk7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdSZWNvZ25pdGlvbkVuZGVkRXZlbnQnOlxuICAgICAgICBpZiAoZXZlbnQuU3RhdHVzICE9PSBDb2duaXRpdmVTcGVlY2guUmVjb2duaXRpb25Db21wbGV0aW9uU3RhdHVzLlN1Y2Nlc3MpIHtcbiAgICAgICAgICB0aGlzLl90cmFuc2l0VG8oQVVESU9fRU5EKTtcbiAgICAgICAgICB0aGlzLm9uZXJyb3IgJiYgdGhpcy5vbmVycm9yKHsgZXJyb3I6IENvZ25pdGl2ZVNwZWVjaC5SZWNvZ25pdGlvbkNvbXBsZXRpb25TdGF0dXNbZXZlbnQuU3RhdHVzXSwgdHlwZTogJ2Vycm9yJyB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuX3RyYW5zaXRUbyhFTkQpO1xuXG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdSZWNvZ25pdGlvblN0YXJ0ZWRFdmVudCc6XG4gICAgICAgIHRoaXMuX3RyYW5zaXRUbyhTUEVFQ0hfU1RBUlQpO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnUmVjb2duaXRpb25UcmlnZ2VyZWRFdmVudCc6XG4gICAgICAgIHRoaXMuX3RyYW5zaXRUbyhTVEFSVCk7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdTcGVlY2hFbmREZXRlY3RlZEV2ZW50JzpcbiAgICAgICAgdGhpcy5fdHJhbnNpdFRvKFNQRUVDSF9FTkQpO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnU3BlZWNoU3RhcnREZXRlY3RlZEV2ZW50JzpcbiAgICAgICAgdGhpcy5fdHJhbnNpdFRvKFNQRUVDSF9TVEFSVCk7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdTcGVlY2hIeXBvdGhlc2lzRXZlbnQnOlxuICAgICAgICB0aGlzLl9oYW5kbGVIeXBvdGhlc2lzKGV2ZW50KTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ1NwZWVjaERldGFpbGVkUGhyYXNlRXZlbnQnOlxuICAgICAgICB0aGlzLl9oYW5kbGVEZXRhaWxlZFBocmFzZShldmVudCk7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdDb25uZWN0aW5nVG9TZXJ2aWNlRXZlbnQnOlxuICAgICAgY2FzZSAnU3BlZWNoU2ltcGxlUGhyYXNlRXZlbnQnOlxuICAgICAgICBicmVhaztcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgY29uc29sZS53YXJuKGBVbmV4cGVjdGVkIGV2ZW50IFxcXCIkeyBuYW1lIH1cXFwiIGZyb20gQ29nbml0aXZlIFNlcnZpY2VzLCBwbGVhc2UgZmlsZSBhIGJ1ZyB0byBodHRwczovL2dpdGh1Yi5jb20vY29tcHVsaW0vd2ViLXNwZWVjaC1jb2duaXRpdmUtc2VydmljZXNgKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBDb2duaXRpdmUgU2VydmljZXMgd2lsbCBoaWRlIGFsbCBleGNlcHRpb25zIHRocm93biBpbiB0aGUgZXZlbnQgbGlzdGVuZXJcbiAgICAgIC8vIFdlIG5lZWQgdG8gc2hvdyBpdCBvdGhlcndpc2Ugd2hlbiBleGNlcHRpb24gaGFwcGVuLCB3ZSB3aWxsIG5vdCBrbm93IHdoYXQncyBnb2luZyBvblxuICAgICAgY29uc29sZS5lcnJvcihlcnIpO1xuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cbiAgfVxuXG4gIHN0YXJ0KCkge1xuICAgIHRoaXMucmVjb2duaXplciA9IHRoaXMuY3JlYXRlUmVjb2duaXplcihcbiAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnU1BFRUNIX0tFWScpLFxuICAgICAgdGhpcy5sYW5nXG4gICAgKTtcblxuICAgIHRoaXMucmVjb2duaXplci5SZWNvZ25pemUodGhpcy5oYW5kbGVSZWNvZ25pemUuYmluZCh0aGlzKSk7XG4gICAgdGhpcy5fdHJhbnNpdFRvKFNUQVJUKTtcbiAgfVxuXG4gIHN0b3AoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdub3Qgc3VwcG9ydGVkJyk7XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQ29nbml0aXZlU2VydmljZXNTcGVlY2hSZWNvZ25pdGlvblxuIl19 | ||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9Db2duaXRpdmVTZXJ2aWNlc1NwZWVjaFJlY29nbml0aW9uLmpzIl0sIm5hbWVzIjpbIkNvZ25pdGl2ZVNwZWVjaCIsIlVOSU5JVCIsIklETEUiLCJTVEFSVCIsIkFVRElPX1NUQVJUIiwiU09VTkRfU1RBUlQiLCJTUEVFQ0hfU1RBUlQiLCJTUEVFQ0hfRU5EIiwiU09VTkRfRU5EIiwiQVVESU9fRU5EIiwiRU5EIiwiRVZFTlRfVFlQRVMiLCJidWlsZFNwZWVjaFJlc3VsdCIsInRyYW5zY3JpcHQiLCJjb25maWRlbmNlIiwiaXNGaW5hbCIsInJlc3VsdCIsInJlc3VsdHMiLCJ0eXBlIiwiQ29nbml0aXZlU2VydmljZXNTcGVlY2hSZWNvZ25pdGlvbiIsIl9sYW5nIiwicmVhZHlTdGF0ZSIsIm9uYXVkaW9zdGFydCIsIm9uYXVkaW9lbmQiLCJvbmVuZCIsIm9uZXJyb3IiLCJvbm5vbWF0Y2giLCJvbnJlc3VsdCIsIm9uc291bmRzdGFydCIsIm9uc291bmRlbmQiLCJvbnNwZWVjaHN0YXJ0Iiwib25zcGVlY2hlbmQiLCJvbnN0YXJ0IiwiY3JlYXRlUmVjb2duaXplciIsInN1YnNjcmlwdGlvbktleU9yVG9rZW5GZXRjaCIsImxhbmciLCJuYXZpZ2F0b3IiLCJsYW5ndWFnZSIsIm1vZGUiLCJSZWNvZ25pdGlvbk1vZGUiLCJJbnRlcmFjdGl2ZSIsInBsYXRmb3JtIiwid2luZG93IiwidXNlckFnZW50IiwibmFtZSIsIm9zVmVyc2lvbiIsIm1hbnVmYWN0dXJlciIsIm1vZGVsIiwiZGV2aWNlVmVyc2lvbiIsImNvbmZpZyIsIlJlY29nbml6ZXJDb25maWciLCJTcGVlY2hDb25maWciLCJDb250ZXh0IiwiT1MiLCJEZXZpY2UiLCJTcGVlY2hSZXN1bHRGb3JtYXQiLCJEZXRhaWxlZCIsImF1dGgiLCJDb2duaXRpdmVUb2tlbkF1dGhlbnRpY2F0aW9uIiwiYXV0aEZldGNoRXZlbnRJRCIsIkNvZ25pdGl2ZVN1YnNjcmlwdGlvbktleUF1dGhlbnRpY2F0aW9uIiwiQ3JlYXRlUmVjb2duaXplciIsInJlY29nbml6ZXIiLCJBdWRpb1NvdXJjZSIsIlR1cm5PZmYiLCJfYWJvcnRlZCIsImV2ZW50IiwibGlzdGVuZXIiLCJjYWxsIiwiRXJyb3IiLCJsb2NhbFN0b3JhZ2UiLCJnZXRJdGVtIiwidG9Qcm9taXNlIiwiZXZlbnRMaXN0ZW5lciIsInByb21pc2VzIiwiUmVjb2duaXplIiwicmVjb2duaXRpb25UcmlnZ2VyZWQiLCJlcnJvciIsIlByb21pc2UiLCJyYWNlIiwibGlzdGVuaW5nU3RhcnRlZCIsInJlY29nbml0aW9uRW5kZWQiLCJOYW1lIiwiU3RhdHVzIiwiUmVjb2duaXRpb25Db21wbGV0aW9uU3RhdHVzIiwiQXVkaW9Tb3VyY2VFcnJvciIsImVtaXQiLCJjb25uZWN0aW5nVG9TZXJ2aWNlIiwicmVjb2duaXRpb25TdGFydGVkIiwiQ29ubmVjdEVycm9yIiwiZ290Rmlyc3RIeXBvdGhlc2lzIiwiZ2V0U3BlZWNoSHlwb3RoZXNpc1Byb21pc2UiLCJzcGVlY2hFbmREZXRlY3RlZCIsInNwZWVjaEh5cG90aGVzaXMiLCJSZXN1bHQiLCJUZXh0Iiwic3BlZWNoRGV0YWlsZWRQaHJhc2UiLCJyZWNvZ25pdGlvblJlc3VsdCIsIlJlY29nbml0aW9uU3RhdHVzIiwiU3VjY2VzcyIsIk5CZXN0IiwiRGlzcGxheSIsIkNvbmZpZGVuY2UiLCJOb01hdGNoIiwiSW5pdGlhbFNpbGVuY2VUaW1lb3V0IiwibmV4dEdyYW1tYXJzIiwibmV4dExhbmciLCJuZXh0Q29udGludW91cyIsIm5leHRJbnRlcmltUmVzdWx0cyIsIm5leHRNYXhBbHRlcm5hdGl2ZXMiLCJuZXh0U2VydmljZVVSSSIsImV2ZW50cyIsIkNvbm5lY3RpbmdUb1NlcnZpY2VFdmVudCIsIkV2ZW50QXNQcm9taXNlIiwiTGlzdGVuaW5nU3RhcnRlZEV2ZW50IiwiUmVjb2duaXRpb25FbmRlZEV2ZW50IiwiUmVjb2duaXRpb25TdGFydGVkRXZlbnQiLCJSZWNvZ25pdGlvblRyaWdnZXJlZEV2ZW50IiwiU3BlZWNoRGV0YWlsZWRQaHJhc2VFdmVudCIsIlNwZWVjaEVuZERldGVjdGVkRXZlbnQiLCJTcGVlY2hIeXBvdGhlc2lzRXZlbnQiLCJTcGVlY2hTaW1wbGVQaHJhc2VFdmVudCIsIlNwZWVjaFN0YXJ0RGV0ZWN0ZWRFdmVudCIsInVwY29taW5nIiwic3BlZWNoU2ltcGxlUGhyYXNlIiwic3BlZWNoU3RhcnREZXRlY3RlZCIsImV2ZW50QXNQcm9taXNlIiwiY29uc29sZSIsIndhcm4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUFBQTs7SUFBWUEsZTs7QUFDWjs7OztBQUNBOzs7Ozs7Ozs7Ozs7OztBQUVBLElBQU1DLFNBQVMsQ0FBZjtBQUNBLElBQU1DLE9BQU8sQ0FBYjtBQUNBLElBQU1DLFFBQVEsQ0FBZDtBQUNBLElBQU1DLGNBQWMsQ0FBcEI7QUFDQSxJQUFNQyxjQUFjLENBQXBCO0FBQ0EsSUFBTUMsZUFBZSxDQUFyQjtBQUNBLElBQU1DLGFBQWEsQ0FBbkI7QUFDQSxJQUFNQyxZQUFZLENBQWxCO0FBQ0EsSUFBTUMsWUFBWSxDQUFsQjtBQUNBLElBQU1DLE1BQU0sQ0FBWjs7QUFFQSxJQUFNQyxjQUFjLENBQ2xCLElBRGtCLEVBRWxCLElBRmtCLEVBR2xCLE9BSGtCLEVBSWxCLFlBSmtCLEVBS2xCLFlBTGtCLEVBTWxCLGFBTmtCLEVBT2xCLFdBUGtCLEVBUWxCLFVBUmtCLEVBU2xCLFVBVGtCLEVBVWxCLEtBVmtCLENBQXBCOztBQWFBLFNBQVNDLGlCQUFULENBQTJCQyxVQUEzQixFQUF1Q0MsVUFBdkMsRUFBbURDLE9BQW5ELEVBQTREO0FBQzFELE1BQU1DLFNBQVMsQ0FBQyxFQUFFRixzQkFBRixFQUFjRCxzQkFBZCxFQUFELENBQWY7O0FBRUFHLFNBQU9ELE9BQVAsR0FBaUJBLE9BQWpCOztBQUVBLFNBQU8sRUFBRUUsU0FBUyxDQUFDRCxNQUFELENBQVgsRUFBcUJFLE1BQU0sUUFBM0IsRUFBUDtBQUNEOztJQUVLQyxrQztBQUNKLGdEQUFjO0FBQUE7O0FBQUE7O0FBQ1osU0FBS0Ms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LENBQStCRSxRQUEvQixFQVRmO0FBVUxFLHlCQUFxQmQsT0FBT1csd0JBQVAsQ0FBZ0NDLFFBQWhDLEVBVmhCO0FBV0xsRCxtQkFBZSw4QkFBUztBQUFBLFVBQ1I3QixJQURRLEdBQ0NzQixLQURELENBQ2RnQixJQURjOztBQUV0QixVQUFNNEMsaUJBQWlCZixPQUFPbkUsSUFBUCxDQUF2Qjs7QUFFQSxVQUFJa0YsY0FBSixFQUFvQjtBQUNsQkEsdUJBQWVyRCxhQUFmLENBQTZCTCxJQUE3QixDQUFrQyxJQUFsQyxFQUF3Q0YsS0FBeEM7QUFDRCxPQUZELE1BRU87QUFDTDZELGdCQUFRQyxJQUFSLHdCQUFvQ3BGLElBQXBDO0FBQ0Q7QUFDRjtBQXBCSSxHQUFQO0FBc0JEOztrQkFFY3pCLGtDIiwiZmlsZSI6IkNvZ25pdGl2ZVNlcnZpY2VzU3BlZWNoUmVjb2duaXRpb24uanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBDb2duaXRpdmVTcGVlY2ggZnJvbSAnbWljcm9zb2Z0LXNwZWVjaC1icm93c2VyLXNkayc7XG5pbXBvcnQgRXZlbnRBc1Byb21pc2UgZnJvbSAnZXZlbnQtYXMtcHJvbWlzZSc7XG5pbXBvcnQgbWVtb2l6ZSBmcm9tICdtZW1vaXplLW9uZSc7XG5cbmNvbnN0IFVOSU5JVCA9IDA7XG5jb25zdCBJRExFID0gMTtcbmNvbnN0IFNUQVJUID0gMjtcbmNvbnN0IEFVRElPX1NUQVJUID0gMztcbmNvbnN0IFNPVU5EX1NUQVJUID0gNDtcbmNvbnN0IFNQRUVDSF9TVEFSVCA9IDU7XG5jb25zdCBTUEVFQ0hfRU5EID0gNjtcbmNvbnN0IFNPVU5EX0VORCA9IDc7XG5jb25zdCBBVURJT19FTkQgPSA4O1xuY29uc3QgRU5EID0gOTtcblxuY29uc3QgRVZFTlRfVFlQRVMgPSBbXG4gIG51bGwsXG4gIG51bGwsXG4gICdzdGFydCcsXG4gICdhdWRpb3N0YXJ0JyxcbiAgJ3NvdW5kc3RhcnQnLFxuICAnc3BlZWNoc3RhcnQnLFxuICAnc3BlZWNoZW5kJyxcbiAgJ3NvdW5kZW5kJyxcbiAgJ2F1ZGlvZW5kJyxcbiAgJ2VuZCdcbl07XG5cbmZ1bmN0aW9uIGJ1aWxkU3BlZWNoUmVzdWx0KHRyYW5zY3JpcHQsIGNvbmZpZGVuY2UsIGlzRmluYWwpIHtcbiAgY29uc3QgcmVzdWx0ID0gW3sgY29uZmlkZW5jZSwgdHJhbnNjcmlwdCB9XTtcblxuICByZXN1bHQuaXNGaW5hbCA9IGlzRmluYWw7XG5cbiAgcmV0dXJuIHsgcmVzdWx0czogW3Jlc3VsdF0sIHR5cGU6ICdyZXN1bHQnIH07XG59XG5cbmNsYXNzIENvZ25pdGl2ZVNlcnZpY2VzU3BlZWNoUmVjb2duaXRpb24ge1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLl9sYW5nID0gJyc7XG5cbiAgICB0aGlzLnJlYWR5U3RhdGUgPSAwO1xuXG4gICAgdGhpcy5vbmF1ZGlvc3RhcnQgPSBudWxsO1xuICAgIHRoaXMub25hdWRpb2VuZCA9IG51bGw7XG4gICAgdGhpcy5vbmVuZCA9IG51bGw7XG4gICAgdGhpcy5vbmVycm9yID0gbnVsbDtcbiAgICB0aGlzLm9ubm9tYXRjaCA9IG51bGw7XG4gICAgdGhpcy5vbnJlc3VsdCA9IG51bGw7XG4gICAgdGhpcy5vbnNvdW5kc3RhcnQgPSBudWxsO1xuICAgIHRoaXMub25zb3VuZGVuZCA9IG51bGw7XG4gICAgdGhpcy5vbnNwZWVjaHN0YXJ0ID0gbnVsbDtcbiAgICB0aGlzLm9uc3BlZWNoZW5kID0gbnVsbDtcbiAgICB0aGlzLm9uc3RhcnQgPSBudWxsO1xuXG4gICAgdGhpcy5jcmVhdGVSZWNvZ25pemVyID0gbWVtb2l6ZSgoXG4gICAgICBzdWJzY3JpcHRpb25LZXlPclRva2VuRmV0Y2gsXG4gICAgICBsYW5nID0gbmF2aWdhdG9yLmxhbmd1YWdlLFxuICAgICAgbW9kZSA9IENvZ25pdGl2ZVNwZWVjaC5SZWNvZ25pdGlvbk1vZGUuSW50ZXJhY3RpdmVcbiAgICApID0+IHtcbiAgICAgIGNvbnN0IHBsYXRmb3JtID0gd2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQ7XG4gICAgICBjb25zdCBuYW1lID0gJ0Jyb3dzZXInO1xuICAgICAgY29uc3Qgb3NWZXJzaW9uID0gVkVSU0lPTjtcbiAgICAgIGNvbnN0IG1hbnVmYWN0dXJlciA9ICd3ZWItc3BlZWNoLWNvZ25pdGl2ZS1zZXJ2aWNlcyc7XG4gICAgICBjb25zdCBtb2RlbCA9ICd3ZWItc3BlZWNoLWNvZ25pdGl2ZS1zZXJ2aWNlcyc7XG4gICAgICBjb25zdCBkZXZpY2VWZXJzaW9uID0gVkVSU0lPTjtcblxuICAgICAgY29uc3QgY29uZmlnID0gbmV3IENvZ25pdGl2ZVNwZWVjaC5SZWNvZ25pemVyQ29uZmlnKFxuICAgICAgICBuZXcgQ29nbml0aXZlU3BlZWNoLlNwZWVjaENvbmZpZyhcbiAgICAgICAgICBuZXcgQ29nbml0aXZlU3BlZWNoLkNvbnRleHQoXG4gICAgICAgICAgICBuZXcgQ29nbml0aXZlU3BlZWNoLk9TKHBsYXRmb3JtLCBuYW1lLCBvc1ZlcnNpb24pLFxuICAgICAgICAgICAgbmV3IENvZ25pdGl2ZVNwZWVjaC5EZXZpY2UobWFudWZhY3R1cmVyLCBtb2RlbCwgZGV2aWNlVmVyc2lvbilcbiAgICAgICAgICApXG4gICAgICAgICksXG4gICAgICAgIG1vZGUsXG4gICAgICAgIGxhbmcsXG4gICAgICAgIENvZ25pdGl2ZVNwZWVjaC5TcGVlY2hSZXN1bHRGb3JtYXQuRGV0YWlsZWRcbiAgICAgICk7XG5cbiAgICAgIGxldCBhdXRoO1xuXG4gICAgICBpZiAodHlwZW9mIHN1YnNjcmlwdGlvbktleU9yVG9rZW5GZXRjaCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBhdXRoID0gbmV3IENvZ25pdGl2ZVNwZWVjaC5Db2duaXRpdmVUb2tlbkF1dGhlbnRpY2F0aW9uKFxuICAgICAgICAgIGFzeW5jIGF1dGhGZXRjaEV2ZW50SUQgPT4gYXdhaXQgc3Vic2NyaXB0aW9uS2V5T3JUb2tlbkZldGNoKGF1dGhGZXRjaEV2ZW50SUQsIGZhbHNlKSxcbiAgICAgICAgICBhc3luYyBhdXRoRmV0Y2hFdmVudElEID0+IGF3YWl0IHN1YnNjcmlwdGlvbktleU9yVG9rZW5GZXRjaChhdXRoRmV0Y2hFdmVudElELCB0cnVlKVxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYXV0aCA9IG5ldyBDb2duaXRpdmVTcGVlY2guQ29nbml0aXZlU3Vic2NyaXB0aW9uS2V5QXV0aGVudGljYXRpb24oc3Vic2NyaXB0aW9uS2V5T3JUb2tlbkZldGNoKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIENvZ25pdGl2ZVNwZWVjaC5DcmVhdGVSZWNvZ25pemVyKGNvbmZpZywgYXV0aCk7XG4gICAgfSk7XG4gIH1cblxuICBnZXQgZ3JhbW1hcnMoKSB7IHJldHVybjsgfVxuICBzZXQgZ3JhbW1hcnMobmV4dEdyYW1tYXJzKSB7XG4gICAgLy8gdGhyb3cgbmV3IEVycm9yKCdub3Qgc3VwcG9ydGVkJyk7XG4gIH1cblxuICBnZXQgbGFuZygpIHsgcmV0dXJuIHRoaXMuX2xhbmc7IH1cbiAgc2V0IGxhbmcobmV4dExhbmcpIHsgdGhpcy5fbGFuZyA9IG5leHRMYW5nOyB9XG5cbiAgZ2V0IGNvbnRpbnVvdXMoKSB7IHJldHVybiBmYWxzZTsgfVxuICBzZXQgY29udGludW91cyhuZXh0Q29udGludW91cykgeyB0aHJvdyBuZXcgRXJyb3IoJ25vdCBzdXBwb3J0ZWQnKTsgfVxuXG4gIGdldCBpbnRlcmltUmVzdWx0cygpIHsgcmV0dXJuIHRydWU7IH1cbiAgc2V0IGludGVyaW1SZXN1bHRzKG5leHRJbnRlcmltUmVzdWx0cykge1xuICAgIGlmICghbmV4dEludGVyaW1SZXN1bHRzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ25vdCBzdXBwb3J0ZWQnKTtcbiAgICB9XG4gIH1cblxuICBnZXQgbWF4QWx0ZXJuYXRpdmVzKCkgeyByZXR1cm4gMTsgfVxuICBzZXQgbWF4QWx0ZXJuYXRpdmVzKG5leHRNYXhBbHRlcm5hdGl2ZXMpIHsgdGhyb3cgbmV3IEVycm9yKCdub3Qgc3VwcG9ydGVkJyk7IH1cblxuICBnZXQgc2VydmljZVVSSSgpIHsgcmV0dXJuIG51bGw7IH1cbiAgc2V0IHNlcnZpY2VVUkkobmV4dFNlcnZpY2VVUkkpIHsgdGhyb3cgbmV3IEVycm9yKCdub3Qgc3VwcG9ydGVkJyk7IH1cblxuICBhYm9ydCgpIHtcbiAgICAvLyBUT0RPOiBTaG91bGQgcmVkZXNpZ24gaG93IHRvIHN0b3AgYSByZWNvZ25pdGlvbiBzZXNzaW9uXG4gICAgLy8gICAgICAgQWZ0ZXIgYWJvcnQgaXMgY2FsbGVkLCB3ZSBzaG91bGQgbm90IHNhdyBpdCBpcyBhIFwic3VjY2Vzc1wiLCBcInNpbGVudFwiLCBvciBcIm5vIG1hdGNoXCJcbiAgICBjb25zdCB7IEF1ZGlvU291cmNlIH0gPSB0aGlzLnJlY29nbml6ZXIgfHwge307XG5cbiAgICBBdWRpb1NvdXJjZSAmJiBBdWRpb1NvdXJjZS5UdXJuT2ZmKCk7XG5cbiAgICB0aGlzLl9hYm9ydGVkID0gdHJ1ZTtcbiAgfVxuXG4gIGVtaXQobmFtZSwgZXZlbnQpIHtcbiAgICBjb25zdCBsaXN0ZW5lciA9IHRoaXNbYG9uJHsgbmFtZSB9YF07XG5cbiAgICBsaXN0ZW5lciAmJiBsaXN0ZW5lci5jYWxsKHRoaXMsIHsgLi4uZXZlbnQsIHR5cGU6IG5hbWUgfSk7XG4gIH1cblxuICBzdG9wKCkge1xuICAgIHRocm93IG5ldyBFcnJvcignbm90IHN1cHBvcnRlZCcpO1xuICB9XG5cbiAgYXN5bmMgc3RhcnQoKSB7XG4gICAgY29uc3QgcmVjb2duaXplciA9IHRoaXMucmVjb2duaXplciA9IHRoaXMuY3JlYXRlUmVjb2duaXplcihcbiAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnU1BFRUNIX0tFWScpLFxuICAgICAgdGhpcy5sYW5nXG4gICAgKTtcblxuICAgIGNvbnN0IHsgZXZlbnRMaXN0ZW5lciwgLi4ucHJvbWlzZXMgfSA9IHRvUHJvbWlzZSgpO1xuXG4gICAgcmVjb2duaXplci5SZWNvZ25pemUoZXZlbnRMaXN0ZW5lcik7XG4gICAgdGhpcy5fYWJvcnRlZCA9IGZhbHNlO1xuXG4gICAgYXdhaXQgcHJvbWlzZXMucmVjb2duaXRpb25UcmlnZ2VyZWQ7XG5cbiAgICBsZXQgZXJyb3I7XG5cbiAgICBjb25zdCBsaXN0ZW5pbmdTdGFydGVkID0gYXdhaXQgUHJvbWlzZS5yYWNlKFtcbiAgICAgIHByb21pc2VzLmxpc3RlbmluZ1N0YXJ0ZWQsXG4gICAgICBwcm9taXNlcy5yZWNvZ25pdGlvbkVuZGVkXG4gICAgXSk7XG5cbiAgICBpZiAobGlzdGVuaW5nU3RhcnRlZC5OYW1lID09PSAnUmVjb2duaXRpb25FbmRlZEV2ZW50Jykge1xuICAgICAgLy8gUG9zc2libHkgbm90IGF1dGhvcml6ZWQgdG8gdXNlIG1pY3JvcGhvbmVcbiAgICAgIGlmIChsaXN0ZW5pbmdTdGFydGVkLlN0YXR1cyA9PT0gQ29nbml0aXZlU3BlZWNoLlJlY29nbml0aW9uQ29tcGxldGlvblN0YXR1cy5BdWRpb1NvdXJjZUVycm9yKSB7XG4gICAgICAgIGVycm9yID0gJ25vdC1hbGxvd2VkJztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVycm9yID0gQ29nbml0aXZlU3BlZWNoLlJlY29nbml0aW9uQ29tcGxldGlvblN0YXR1c1tsaXN0ZW5pbmdTdGFydGVkLlN0YXR1c107XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZW1pdCgnc3RhcnQnKTtcblxuICAgICAgYXdhaXQgcHJvbWlzZXMuY29ubmVjdGluZ1RvU2VydmljZTtcblxuICAgICAgY29uc3QgcmVjb2duaXRpb25TdGFydGVkID0gYXdhaXQgUHJvbWlzZS5yYWNlKFtcbiAgICAgICAgcHJvbWlzZXMucmVjb2duaXRpb25TdGFydGVkLFxuICAgICAgICBwcm9taXNlcy5yZWNvZ25pdGlvbkVuZGVkXG4gICAgICBdKTtcblxuICAgICAgdGhpcy5lbWl0KCdhdWRpb3N0YXJ0Jyk7XG5cbiAgICAgIGlmIChyZWNvZ25pdGlvblN0YXJ0ZWQuTmFtZSA9PT0gJ1JlY29nbml0aW9uRW5kZWRFdmVudCcpIHtcbiAgICAgICAgLy8gUG9zc2libHkgbmV0d29yayBlcnJvclxuICAgICAgICBpZiAocmVjb2duaXRpb25TdGFydGVkLlN0YXR1cyA9PT0gQ29nbml0aXZlU3BlZWNoLlJlY29nbml0aW9uQ29tcGxldGlvblN0YXR1cy5Db25uZWN0RXJyb3IpIHtcbiAgICAgICAgICBlcnJvciA9ICduZXR3b3JrJztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBlcnJvciA9IENvZ25pdGl2ZVNwZWVjaC5SZWNvZ25pdGlvbkNvbXBsZXRpb25TdGF0dXNbcmVjb2duaXRpb25TdGFydGVkLlN0YXR1c107XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCBnb3RGaXJzdEh5cG90aGVzaXM7XG5cbiAgICAgICAgZm9yICg7Oykge1xuICAgICAgICAgIGNvbnN0IHNwZWVjaEh5cG90aGVzaXMgPSBhd2FpdCBQcm9taXNlLnJhY2UoW1xuICAgICAgICAgICAgcHJvbWlzZXMuZ2V0U3BlZWNoSHlwb3RoZXNpc1Byb21pc2UoKSxcbiAgICAgICAgICAgIHByb21pc2VzLnNwZWVjaEVuZERldGVjdGVkXG4gICAgICAgICAgXSk7XG5cbiAgICAgICAgICBpZiAoc3BlZWNoSHlwb3RoZXNpcy5OYW1lID09PSAnU3BlZWNoRW5kRGV0ZWN0ZWRFdmVudCcpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICghZ290Rmlyc3RIeXBvdGhlc2lzKSB7XG4gICAgICAgICAgICBnb3RGaXJzdEh5cG90aGVzaXMgPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy5lbWl0KCdzb3VuZHN0YXJ0Jyk7XG4gICAgICAgICAgICB0aGlzLmVtaXQoJ3NwZWVjaHN0YXJ0Jyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5lbWl0KCdyZXN1bHQnLCBidWlsZFNwZWVjaFJlc3VsdChzcGVlY2hIeXBvdGhlc2lzLlJlc3VsdC5UZXh0LCAuNSwgZmFsc2UpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChnb3RGaXJzdEh5cG90aGVzaXMpIHtcbiAgICAgICAgICB0aGlzLmVtaXQoJ3NwZWVjaGVuZCcpO1xuICAgICAgICAgIHRoaXMuZW1pdCgnc291bmRlbmQnKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLmVtaXQoJ2F1ZGlvZW5kJyk7XG5cbiAgICAgIGlmICh0aGlzLl9hYm9ydGVkKSB7XG4gICAgICAgIGVycm9yID0gJ2Fib3J0ZWQnO1xuXG4gICAgICAgIGF3YWl0IHByb21pc2VzLnJlY29nbml0aW9uRW5kZWQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBzcGVlY2hEZXRhaWxlZFBocmFzZSA9IGF3YWl0IFByb21pc2UucmFjZShbXG4gICAgICAgICAgcHJvbWlzZXMuc3BlZWNoRGV0YWlsZWRQaHJhc2UsXG4gICAgICAgICAgcHJvbWlzZXMucmVjb2duaXRpb25FbmRlZFxuICAgICAgICBdKTtcblxuICAgICAgICBpZiAoc3BlZWNoRGV0YWlsZWRQaHJhc2UuTmFtZSAhPT0gJ1JlY29nbml0aW9uRW5kZWRFdmVudCcpIHtcbiAgICAgICAgICBjb25zdCByZWNvZ25pdGlvblJlc3VsdCA9IENvZ25pdGl2ZVNwZWVjaC5SZWNvZ25pdGlvblN0YXR1c1tzcGVlY2hEZXRhaWxlZFBocmFzZS5SZXN1bHQuUmVjb2duaXRpb25TdGF0dXNdO1xuXG4gICAgICAgICAgaWYgKHJlY29nbml0aW9uUmVzdWx0ID09PSBDb2duaXRpdmVTcGVlY2guUmVjb2duaXRpb25TdGF0dXMuU3VjY2Vzcykge1xuICAgICAgICAgICAgdGhpcy5lbWl0KCdyZXN1bHQnLCBidWlsZFNwZWVjaFJlc3VsdChzcGVlY2hEZXRhaWxlZFBocmFzZS5SZXN1bHQuTkJlc3RbMF0uRGlzcGxheSwgc3BlZWNoRGV0YWlsZWRQaHJhc2UuUmVzdWx0Lk5CZXN0WzBdLkNvbmZpZGVuY2UsIHRydWUpKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHJlY29nbml0aW9uUmVzdWx0ICE9PSBDb2duaXRpdmVTcGVlY2guUmVjb2duaXRpb25TdGF0dXMuTm9NYXRjaCkge1xuICAgICAgICAgICAgLy8gUG9zc2libHkgc2lsZW50IG9yIG11dGVkXG4gICAgICAgICAgICBpZiAocmVjb2duaXRpb25SZXN1bHQgPT09IENvZ25pdGl2ZVNwZWVjaC5SZWNvZ25pdGlvblN0YXR1cy5Jbml0aWFsU2lsZW5jZVRpbWVvdXQpIHtcbiAgICAgICAgICAgICAgZXJyb3IgPSAnbm8tc3BlZWNoJztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGVycm9yID0gc3BlZWNoRGV0YWlsZWRQaHJhc2UuUmVzdWx0LlJlY29nbml0aW9uU3RhdHVzO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGF3YWl0IHByb21pc2VzLnJlY29nbml0aW9uRW5kZWQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBlcnJvciAmJiB0aGlzLmVtaXQoJ2Vycm9yJywgeyBlcnJvciB9KTtcbiAgICB0aGlzLmVtaXQoJ2VuZCcpO1xuICB9XG59XG5cbmZ1bmN0aW9uIHRvUHJvbWlzZSgpIHtcbiAgY29uc3QgZXZlbnRzID0ge1xuICAgIENvbm5lY3RpbmdUb1NlcnZpY2VFdmVudDogbmV3IEV2ZW50QXNQcm9taXNlKCksXG4gICAgTGlzdGVuaW5nU3RhcnRlZEV2ZW50OiBuZXcgRXZlbnRBc1Byb21pc2UoKSxcbiAgICBSZWNvZ25pdGlvbkVuZGVkRXZlbnQ6IG5ldyBFdmVudEFzUHJvbWlzZSgpLFxuICAgIFJlY29nbml0aW9uU3RhcnRlZEV2ZW50OiBuZXcgRXZlbnRBc1Byb21pc2UoKSxcbiAgICBSZWNvZ25pdGlvblRyaWdnZXJlZEV2ZW50OiBuZXcgRXZlbnRBc1Byb21pc2UoKSxcbiAgICBTcGVlY2hEZXRhaWxlZFBocmFzZUV2ZW50OiBuZXcgRXZlbnRBc1Byb21pc2UoKSxcbiAgICBTcGVlY2hFbmREZXRlY3RlZEV2ZW50OiBuZXcgRXZlbnRBc1Byb21pc2UoKSxcbiAgICBTcGVlY2hIeXBvdGhlc2lzRXZlbnQ6IG5ldyBFdmVudEFzUHJvbWlzZSgpLFxuICAgIFNwZWVjaFNpbXBsZVBocmFzZUV2ZW50OiBuZXcgRXZlbnRBc1Byb21pc2UoKSxcbiAgICBTcGVlY2hTdGFydERldGVjdGVkRXZlbnQ6IG5ldyBFdmVudEFzUHJvbWlzZSgpXG4gIH07XG5cbiAgcmV0dXJuIHtcbiAgICBjb25uZWN0aW5nVG9TZXJ2aWNlOiBldmVudHMuQ29ubmVjdGluZ1RvU2VydmljZUV2ZW50LnVwY29taW5nKCksXG4gICAgbGlzdGVuaW5nU3RhcnRlZDogZXZlbnRzLkxpc3RlbmluZ1N0YXJ0ZWRFdmVudC51cGNvbWluZygpLFxuICAgIHJlY29nbml0aW9uRW5kZWQ6IGV2ZW50cy5SZWNvZ25pdGlvbkVuZGVkRXZlbnQudXBjb21pbmcoKSxcbiAgICByZWNvZ25pdGlvblN0YXJ0ZWQ6IGV2ZW50cy5SZWNvZ25pdGlvblN0YXJ0ZWRFdmVudC51cGNvbWluZygpLFxuICAgIHJlY29nbml0aW9uVHJpZ2dlcmVkOiBldmVudHMuUmVjb2duaXRpb25UcmlnZ2VyZWRFdmVudC51cGNvbWluZygpLFxuICAgIHNwZWVjaERldGFpbGVkUGhyYXNlOiBldmVudHMuU3BlZWNoRGV0YWlsZWRQaHJhc2VFdmVudC51cGNvbWluZygpLFxuICAgIHNwZWVjaEVuZERldGVjdGVkOiBldmVudHMuU3BlZWNoRW5kRGV0ZWN0ZWRFdmVudC51cGNvbWluZygpLFxuICAgIGdldFNwZWVjaEh5cG90aGVzaXNQcm9taXNlOiAoKSA9PiBldmVudHMuU3BlZWNoSHlwb3RoZXNpc0V2ZW50LnVwY29taW5nKCksXG4gICAgc3BlZWNoU2ltcGxlUGhyYXNlOiBldmVudHMuU3BlZWNoU2ltcGxlUGhyYXNlRXZlbnQudXBjb21pbmcoKSxcbiAgICBzcGVlY2hTdGFydERldGVjdGVkOiBldmVudHMuU3BlZWNoU3RhcnREZXRlY3RlZEV2ZW50LnVwY29taW5nKCksXG4gICAgZXZlbnRMaXN0ZW5lcjogZXZlbnQgPT4ge1xuICAgICAgY29uc3QgeyBOYW1lOiBuYW1lIH0gPSBldmVudDtcbiAgICAgIGNvbnN0IGV2ZW50QXNQcm9taXNlID0gZXZlbnRzW25hbWVdO1xuXG4gICAgICBpZiAoZXZlbnRBc1Byb21pc2UpIHtcbiAgICAgICAgZXZlbnRBc1Byb21pc2UuZXZlbnRMaXN0ZW5lci5jYWxsKG51bGwsIGV2ZW50KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgVW5leHBlY3RlZCBldmVudCBcXFwiJHsgbmFtZSB9XFxcIiBmcm9tIENvZ25pdGl2ZSBTZXJ2aWNlcywgcGxlYXNlIGZpbGUgYSBidWcgdG8gaHR0cHM6Ly9naXRodWIuY29tL2NvbXB1bGltL3dlYi1zcGVlY2gtY29nbml0aXZlLXNlcnZpY2VzYCk7XG4gICAgICB9XG4gICAgfVxuICB9O1xufVxuXG5leHBvcnQgZGVmYXVsdCBDb2duaXRpdmVTZXJ2aWNlc1NwZWVjaFJlY29nbml0aW9uXG4iXX0= |
{ | ||
"name": "web-speech-cognitive-services", | ||
"version": "0.0.1-master.e70a05d", | ||
"version": "0.0.1-master.f80884e", | ||
"description": "", | ||
@@ -31,8 +31,10 @@ "keywords": [], | ||
"babel-plugin-version-transform": "^1.0.0", | ||
"babel-polyfill": "^6.26.0", | ||
"babel-preset-stage-3": "^6.24.1", | ||
"classnames": "^2.2.6", | ||
"event-as-promise": "^1.0.3", | ||
"glamor": "^2.20.40", | ||
"jest": "^22.4.4", | ||
"lerna": "^2.11.0", | ||
"microsoft-speech-browser-sdk": "0.0.12", | ||
"microsoft-speech-browser-sdk": "^0.0.12", | ||
"react": "^16.4.1", | ||
@@ -39,0 +41,0 @@ "react-dictate-button": "^1.0.0", |
193
README.md
# web-speech-cognitive-services | ||
[![npm version](https://badge.fury.io/js/we-bspeech-cognitive-services.svg)](https://badge.fury.io/js/we-bspeech-cognitive-services) [![Build Status](https://travis-ci.org/compulim/we-bspeech-cognitive-services.svg?branch=master)](https://travis-ci.org/compulim/web-speech-cognitive-services) | ||
[![npm version](https://badge.fury.io/js/web-speech-cognitive-services.svg)](https://badge.fury.io/js/web-speech-cognitive-services) [![Build Status](https://travis-ci.org/compulim/web-speech-cognitive-services.svg?branch=master)](https://travis-ci.org/compulim/web-speech-cognitive-services) | ||
Polyfill Web Speech API with Cognitive Services. | ||
## Event lifecycle mapping from Cognitive Services | ||
This scaffold is provided by [`react-component-template`](https://github.com/compulim/react-component-template/). | ||
| # | WebSpeech | Cognitive Services | Notes | | ||
| - | - | - | - | | ||
| 1 | `start` | `RecognitionTriggeredEvent` | | | ||
| 2 | `audiostart` | `ListeningStartedEvent` | | | ||
| 3 | | `ConnectingToServiceEvent` | | | ||
| 4 | `soundstart`, `speechstart` | `RecognitionStartedEvent` | | | ||
| 5 | `onresult(isFinal = false)` | `SpeechHypothesisEvent` | | | ||
| 6 | `speechend`, `soundend`, `audioend` | `SpeechEndDetectedEvent` | `speechend` and `soundend` only fire if either `speechstart` and `soundstart` was fired | | ||
| 7 | `onresult(isFinal = true)`, `onerror` | `SpeechSimplePhraseEvent` | | | ||
| 8 | `end` | `RecognitionEndedEvent` | | | ||
# Demo | ||
### Scenarios | ||
Try out our demo at https://compulim.github.io/web-speech-cognitive-services?s=your-subscription-key. | ||
* Happy path | ||
We use [`react-dictate-button`](https://github.com/compulim/react-dictate-button/) to quickly setup the playground. | ||
# Background | ||
Web Speech API is not widely adopted on popular browsers and platforms. Polyfilling the API using cloud services is a great way to enable wider adoption. Nonetheless, Web Speech API in Google Chrome is also backed by cloud services. | ||
Microsoft Azure [Cognitive Services Speech-to-Text](https://azure.microsoft.com/en-us/services/cognitive-services/speech-to-text/) service provide speech recognition with great accuracy. But unfortunately, the APIs are not based on Web Speech API. | ||
This package will polyfill Web Speech API by turning Cognitive Services Speech-to-Text API into Web Speech API. We test this package with popular combination of platforms and browsers. | ||
# Test matrix | ||
Browsers are all latest as of 2018-06-28, except: | ||
* macOS was 10.13.1 (2017-10-31), instead of 10.13.5 | ||
* Tthere should be no change on the matrix since Safari does not support Web Speech API | ||
* Xbox was tested on Insider build (1806) | ||
Overall in point form: | ||
* With Web Speech API only, web dev can enable speech recognition on most popular platforms, except iOS | ||
* iOS: No browsers on iOS support Web Speech API | ||
* Some platforms requires non-default browser | ||
* With Cognitive Services Speech-to-Text, all popular platforms with their default browsers are supported | ||
* iOS: Chrome and Edge does not support Cognitive Services because WebRTC is disabled | ||
| Platform | OS | Browser | Cognitive Services (WebRTC) | Web Speech API | | ||
| - | - | - | - | - | | ||
| PC | Windows 10 (1803) | Chrome 67.0.3396.99 | Yes | Yes | | ||
| PC | Windows 10 (1803) | Edge 42.17134.1.0 | Yes | No, `SpeechRecognition` not implemented | | ||
| PC | Windows 10 (1803) | Firefox 61.0 | Yes | No, `SpeechRecognition` not implemented | | ||
| MacBook Pro | macOS High Sierra 10.13.1 | Chrome 67.0.3396.99 | Yes | Yes | | ||
| MacBook Pro | macOS High Sierra 10.13.1 | Safari 11.0.1 | Yes | No, `SpeechRecognition` not implemented | | ||
| Apple iPhone X | iOS 11.4 | Chrome 67.0.3396.87 | No, `AudioSourceError` | No, `SpeechRecognition` not implemented | | ||
| Apple iPhone X | iOS 11.4 | Edge 42.2.2.0 | No, `AudioSourceError` | No, `SpeechRecognition` not implemented | | ||
| Apple iPhone X | iOS 11.4 | Safari | Yes | No, `SpeechRecognition` not implemented | | ||
| Apple iPod (6th gen) | iOS 11.4 | Chrome 67.0.3396.87 | No, `AudioSourceError` | No, `SpeechRecognition` not implemented | | ||
| Apple iPod (6th gen) | iOS 11.4 | Edge 42.2.2.0 | No, `AudioSourceError` | No, `SpeechRecognition` not implemented | | ||
| Apple iPod (6th gen) | iOS 11.4 | Safari | No, `AudioSourceError` | No, `SpeechRecognition` not implemented | | ||
| Google Pixel 2 | Android 8.1.0 | Chrome 67.0.3396.87 | Yes | Yes | | ||
| Google Pixel 2 | Android 8.1.0 | Edge 42.0.0.2057 | Yes | Yes | | ||
| Google Pixel 2 | Android 8.1.0 | Firefox 60.1.0 | Yes | Yes | | ||
| Microsoft Lumia 950 | Windows 10 (1709) | Edge 40.15254.489.0 | No, `AudioSourceError` | No, `SpeechRecognition` not implemented | | ||
| Microsoft Xbox One | Windows 10 (1806) 17134.4054 | Edge 42.17134.4054.0 | No, `AudioSourceError` | No, `SpeechRecognition` not implemented | | ||
## Event lifecycle scenarios | ||
We test multiple scenarios to make sure the package polyfill Web Speech API correctly. Following are events and its firing order. | ||
* [Happy path](#happy-path) | ||
* [Abort during recognition](#abort-during-recognition) | ||
* [Network issues](#network-issues) | ||
* [Audio muted or volume too low](#audio-muted-or-volume-too-low) | ||
* [No speech is recognized](#no-speech-is-recognized) | ||
* [Not authorized to use microphone](#not-authorized-to-use-microphone) | ||
### Happy path | ||
Everything works, including multiple interim results. | ||
* Cognitive Services | ||
1. `RecognitionTriggeredEvent` | ||
@@ -29,11 +79,64 @@ 2. `ListeningStartedEvent` | ||
6. `SpeechEndDetectedEvent` | ||
7. `SpeechSimplePhraseEvent` | ||
7. `SpeechDetailedPhraseEvent` | ||
8. `RecognitionEndedEvent` | ||
* Network issues | ||
* Web Speech API | ||
1. `start` | ||
2. `audiostart` | ||
3. `soundstart` | ||
4. `speechstart` | ||
5. `result` (multiple times) | ||
6. `speechend` | ||
7. `soundend` | ||
8. `audioend` | ||
9. `result(results = [{ isFinal = true }])` | ||
10. `end` | ||
### Abort during recognition | ||
#### Abort before first recognition is made | ||
* Cognitive Services | ||
* Essentially muted the speech, that could still result in success, silent, or no match | ||
* Web Speech API | ||
1. `start` | ||
2. `audiostart` | ||
8. `audioend` | ||
9. `error(error = 'aborted')` | ||
10. `end` | ||
#### Abort after some speech is recognized | ||
* Cognitive Services | ||
* Essentially muted the speech, that could still result in success, silent, or no match | ||
* Web Speech API | ||
1. `start` | ||
2. `audiostart` | ||
3. `soundstart` (optional) | ||
4. `speechstart` (optional) | ||
5. `result` (optional) | ||
6. `speechend` (optional) | ||
7. `soundend` (optional) | ||
8. `audioend` | ||
9. `error(error = 'aborted')` | ||
10. `end` | ||
### Network issues | ||
Turn on airplane mode. | ||
* Cognitive Services | ||
1. `RecognitionTriggeredEvent` | ||
2. `ListeningStartedEvent` | ||
3. `ConnectingToServiceEvent` | ||
4. `SpeechSimplePhraseEvent` | ||
5. `RecognitionEndedEvent` | ||
* Audio muted or volume too low | ||
5. `RecognitionEndedEvent(Result.RecognitionStatus = 'ConnectError')` | ||
* Web Speech API | ||
1. `start` | ||
2. `audiostart` | ||
3. `audioend` | ||
4. `error(error = 'network')` | ||
5. `end` | ||
### Audio muted or volume too low | ||
* Cognitive Services | ||
1. `RecognitionTriggeredEvent` | ||
@@ -44,5 +147,16 @@ 2. `ListeningStartedEvent` | ||
5. `SpeechEndDetectedEvent` | ||
6. `SpeechSimplePhraseEvent(Result.RecognitionStatus = 'InitialSilenceTimeout')` | ||
6. `SpeechDetailedPhraseEvent(Result.RecognitionStatus = 'InitialSilenceTimeout')` | ||
7. `RecognitionEndedEvent` | ||
* Failed to recognize speech (a.k.a. no match) | ||
* Web Speech API | ||
1. `start` | ||
2. `audiostart` | ||
3. `audioend` | ||
4. `error(error = 'no-speech')` | ||
5. `end` | ||
### No speech is recognized | ||
Some sounds are heard, but they cannot be recognized as text. There could be some interim results with recognized text, but the confidence is so low it dropped out of final result. | ||
* Cognitive Services | ||
1. `RecognitionTriggeredEvent` | ||
@@ -54,16 +168,41 @@ 2. `ListeningStartedEvent` | ||
6. `SpeechEndDetectedEvent` | ||
7. `SpeechSimplePhraseEvent(Result.RecognitionStatus = 'NoMatch')` | ||
7. `SpeechDetailedPhraseEvent(Result.RecognitionStatus = 'NoMatch')` | ||
8. `RecognitionEndedEvent` | ||
* User abort | ||
* Essentially muted the speech, that could result in success, silent, or no match | ||
* Not authorized to use microphone | ||
* Web Speech API | ||
1. `start` | ||
2. `audiostart` | ||
3. `soundstart` | ||
4. `speechstart` | ||
5. `result` | ||
6. `speechend` | ||
7. `soundend` | ||
8. `audioend` | ||
9. `end` | ||
> Note: the Web Speech API has `onnomatch` event, but unfortunately, Google Chrome did not fire this event. | ||
### Not authorized to use microphone | ||
The user click "deny" on the permission dialog, or there are no microphone detected in the system. | ||
* Cognitive Services | ||
1. `RecognitionTriggeredEvent` | ||
2. `RecognitionEndedEvent(Result.RecognitionStatus = 'AudioSourceError')` | ||
* Web Speech API | ||
1. `error(error = 'not-allowed')` | ||
2. `end` | ||
# Known issues | ||
* Interim results do not return confidence, final result do have confidence | ||
* We always return `0.5` for interim results | ||
* Cognitive Services support grammar list but not in JSGF format, more work to be done in this area | ||
* Although Google Chrome support setting the grammar list, it seems the grammar list is not used at all | ||
# Contributions | ||
Like us? [Star](https://github.com/compulim/we-bspeech-cognitive-services/stargazers) us. | ||
Like us? [Star](https://github.com/compulim/web-speech-cognitive-services/stargazers) us. | ||
Want to make it better? [File](https://github.com/compulim/we-bspeech-cognitive-services/issues) us an issue. | ||
Want to make it better? [File](https://github.com/compulim/web-speech-cognitive-services/issues) us an issue. | ||
Don't like something you see? [Submit](https://github.com/compulim/web-speech-cognitive-services/pulls) a pull request. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
52458
363
206
18
1