557 lines
34 KiB
JavaScript
557 lines
34 KiB
JavaScript
function AudioKeys(options) {
|
|
var self = this;
|
|
|
|
self._setState(options);
|
|
|
|
// all listeners are stored in arrays in their respective properties.
|
|
// e.g. self._listeners.down = [fn1, fn2, ... ]
|
|
self._listeners = {};
|
|
|
|
// bind DOM events
|
|
self._bind();
|
|
}
|
|
|
|
// Play well with require so that we can run a test suite and use browserify.
|
|
if(typeof module !== 'undefined') {
|
|
module.exports = AudioKeys;
|
|
}
|
|
|
|
AudioKeys.prototype._setState = function(options) {
|
|
var self = this;
|
|
|
|
if(!options) {
|
|
options = {};
|
|
}
|
|
|
|
// the state is kept in this object
|
|
self._state = {};
|
|
|
|
// set some defaults ...
|
|
self._extendState({
|
|
polyphony: 4,
|
|
rows: 1,
|
|
priority: 'last',
|
|
rootNote: 60,
|
|
octaveControls: true,
|
|
octave: 0,
|
|
velocityControls: true,
|
|
velocity: 127,
|
|
keys: [],
|
|
buffer: []
|
|
});
|
|
|
|
// ... and override them with options.
|
|
self._extendState(options);
|
|
};
|
|
|
|
AudioKeys.prototype._extendState = function(options) {
|
|
var self = this;
|
|
|
|
for(var o in options) {
|
|
self._state[o] = options[o];
|
|
}
|
|
};
|
|
|
|
AudioKeys.prototype.set = function(/* options || property, value */) {
|
|
var self = this;
|
|
|
|
if(arguments.length === 1) {
|
|
self._extendState(arguments[0]);
|
|
} else {
|
|
self._state[arguments[0]] = arguments[1];
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
AudioKeys.prototype.get = function(property) {
|
|
var self = this;
|
|
|
|
return self._state[property];
|
|
};
|
|
|
|
// ================================================================
|
|
// Event Listeners
|
|
// ================================================================
|
|
|
|
// AudioKeys has a very simple event handling system. Internally
|
|
// we'll call self._trigger('down', argument) when we want to fire
|
|
// an event for the user.
|
|
|
|
AudioKeys.prototype.down = function(fn) {
|
|
var self = this;
|
|
|
|
// add the function to our list of listeners
|
|
self._listeners.down = (self._listeners.down || []).concat(fn);
|
|
};
|
|
|
|
AudioKeys.prototype.up = function(fn) {
|
|
var self = this;
|
|
|
|
// add the function to our list of listeners
|
|
self._listeners.up = (self._listeners.up || []).concat(fn);
|
|
};
|
|
|
|
AudioKeys.prototype._trigger = function(action /* args */) {
|
|
var self = this;
|
|
|
|
// if we have any listeners by this name ...
|
|
if(self._listeners[action] && self._listeners[action].length) {
|
|
// grab the arguments to pass to the listeners ...
|
|
var args = Array.prototype.slice.call(arguments);
|
|
args.splice(0, 1);
|
|
// and call them!
|
|
self._listeners[action].forEach( function(fn) {
|
|
fn.apply(self, args);
|
|
});
|
|
}
|
|
};
|
|
|
|
// ================================================================
|
|
// DOM Bindings
|
|
// ================================================================
|
|
|
|
AudioKeys.prototype._bind = function() {
|
|
var self = this;
|
|
|
|
if(typeof window !== 'undefined' && window.document) {
|
|
window.document.addEventListener('keydown', function(e) {
|
|
self._addKey(e);
|
|
});
|
|
window.document.addEventListener('keyup', function(e) {
|
|
self._removeKey(e);
|
|
});
|
|
|
|
var lastFocus = true;
|
|
setInterval( function() {
|
|
if(window.document.hasFocus() === lastFocus) {
|
|
return;
|
|
}
|
|
lastFocus = !lastFocus;
|
|
if(!lastFocus) {
|
|
self.clear();
|
|
}
|
|
}, 100);
|
|
}
|
|
};
|
|
|
|
// _map returns the midi note for a given keyCode.
|
|
AudioKeys.prototype._map = function(keyCode) {
|
|
return this._keyMap[this._state.rows][keyCode] + this._offset();
|
|
};
|
|
|
|
AudioKeys.prototype._offset = function() {
|
|
return this._state.rootNote - this._keyMap[this._state.rows].root + (this._state.octave * 12);
|
|
};
|
|
|
|
// _isNote determines whether a keyCode is a note or not.
|
|
AudioKeys.prototype._isNote = function(keyCode) {
|
|
return !!this._keyMap[this._state.rows][keyCode];
|
|
};
|
|
|
|
// convert a midi note to a frequency. we assume here that _map has
|
|
// already been called (to account for a potential rootNote offset)
|
|
AudioKeys.prototype._toFrequency = function(note) {
|
|
return ( Math.pow(2, ( note-69 ) / 12) ) * 440.0;
|
|
};
|
|
|
|
// the object keys correspond to `rows`, so `_keyMap[rows]` should
|
|
// retrieve that particular mapping.
|
|
AudioKeys.prototype._keyMap = {
|
|
1: {
|
|
root: 60,
|
|
// starting with the 'a' key
|
|
65: 60,
|
|
87: 61,
|
|
83: 62,
|
|
69: 63,
|
|
68: 64,
|
|
70: 65,
|
|
84: 66,
|
|
71: 67,
|
|
89: 68,
|
|
72: 69,
|
|
85: 70,
|
|
74: 71,
|
|
75: 72,
|
|
79: 73,
|
|
76: 74,
|
|
80: 75,
|
|
186: 76,
|
|
222: 77
|
|
},
|
|
2: {
|
|
root: 60,
|
|
// bottom row
|
|
90: 60,
|
|
83: 61,
|
|
88: 62,
|
|
68: 63,
|
|
67: 64,
|
|
86: 65,
|
|
71: 66,
|
|
66: 67,
|
|
72: 68,
|
|
78: 69,
|
|
74: 70,
|
|
77: 71,
|
|
188: 72,
|
|
76: 73,
|
|
190: 74,
|
|
186: 75,
|
|
191: 76,
|
|
// top row
|
|
81: 72,
|
|
50: 73,
|
|
87: 74,
|
|
51: 75,
|
|
69: 76,
|
|
82: 77,
|
|
53: 78,
|
|
84: 79,
|
|
54: 80,
|
|
89: 81,
|
|
55: 82,
|
|
85: 83,
|
|
73: 84,
|
|
57: 85,
|
|
79: 86,
|
|
48: 87,
|
|
80: 88,
|
|
219: 89,
|
|
187: 90,
|
|
221: 91
|
|
}
|
|
};
|
|
|
|
// ================================================================
|
|
// KEY BUFFER
|
|
// ================================================================
|
|
|
|
// The process is:
|
|
|
|
// key press
|
|
// add to self._state.keys
|
|
// (an accurate representation of keys currently pressed)
|
|
// resolve self.buffer
|
|
// based on polyphony and priority, determine the notes
|
|
// that get triggered for the user
|
|
|
|
AudioKeys.prototype._addKey = function(e) {
|
|
var self = this;
|
|
// if the keyCode is one that can be mapped and isn't
|
|
// already pressed, add it to the key object.
|
|
if(self._isNote(e.keyCode) && !self._isPressed(e.keyCode)) {
|
|
var newKey = self._makeNote(e.keyCode);
|
|
// add the newKey to the list of keys
|
|
self._state.keys = (self._state.keys || []).concat(newKey);
|
|
// reevaluate the active notes based on our priority rules.
|
|
// give it the new note to use if there is an event to trigger.
|
|
self._update();
|
|
} else if(self._isSpecialKey(e.keyCode)) {
|
|
self._specialKey(e.keyCode);
|
|
}
|
|
};
|
|
|
|
AudioKeys.prototype._removeKey = function(e) {
|
|
var self = this;
|
|
// if the keyCode is active, remove it from the key object.
|
|
if(self._isPressed(e.keyCode)) {
|
|
var keyToRemove;
|
|
for(var i = 0; i < self._state.keys.length; i++) {
|
|
if(self._state.keys[i].keyCode === e.keyCode) {
|
|
keyToRemove = self._state.keys[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// remove the key from _keys
|
|
self._state.keys.splice(self._state.keys.indexOf(keyToRemove), 1);
|
|
self._update();
|
|
}
|
|
};
|
|
|
|
AudioKeys.prototype._isPressed = function(keyCode) {
|
|
var self = this;
|
|
|
|
if(!self._state.keys || !self._state.keys.length) {
|
|
return false;
|
|
}
|
|
|
|
for(var i = 0; i < self._state.keys.length; i++) {
|
|
if(self._state.keys[i].keyCode === keyCode) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// turn a key object into a note object for the event listeners.
|
|
AudioKeys.prototype._makeNote = function(keyCode) {
|
|
var self = this;
|
|
return {
|
|
keyCode: keyCode,
|
|
note: self._map(keyCode),
|
|
frequency: self._toFrequency( self._map(keyCode) ),
|
|
velocity: self._state.velocity
|
|
};
|
|
};
|
|
|
|
// clear any active notes
|
|
AudioKeys.prototype.clear = function() {
|
|
var self = this;
|
|
// trigger note off for the notes in the buffer before
|
|
// removing them.
|
|
self._state.buffer.forEach( function(key) {
|
|
self._trigger('up', key);
|
|
});
|
|
self._state.keys = [];
|
|
self._state.buffer = [];
|
|
};
|
|
|
|
// ================================================================
|
|
// NOTE BUFFER
|
|
// ================================================================
|
|
|
|
// every time a change is made to _keys due to a key on or key off
|
|
// we need to call `_update`. It compares the `_keys` array to the
|
|
// `buffer` array, which is the array of notes that are really
|
|
// being played, makes the necessary changes to `buffer` and
|
|
// triggers any events that need triggering.
|
|
|
|
AudioKeys.prototype._update = function() {
|
|
var self = this;
|
|
|
|
// a key has been added to self._state.keys.
|
|
// stash the old buffer
|
|
var oldBuffer = self._state.buffer;
|
|
// set the new priority in self.state._keys
|
|
self._prioritize();
|
|
// compare the buffers and trigger events based on
|
|
// the differences.
|
|
self._diff(oldBuffer);
|
|
};
|
|
|
|
AudioKeys.prototype._diff = function(oldBuffer) {
|
|
var self = this;
|
|
|
|
// if it's not in the OLD buffer, it's a note ON.
|
|
// if it's not in the NEW buffer, it's a note OFF.
|
|
|
|
var oldNotes = oldBuffer.map( function(key) {
|
|
return key.keyCode;
|
|
});
|
|
|
|
var newNotes = self._state.buffer.map( function(key) {
|
|
return key.keyCode;
|
|
});
|
|
|
|
// check for old (removed) notes
|
|
var notesToRemove = [];
|
|
oldNotes.forEach( function(key) {
|
|
if(newNotes.indexOf(key) === -1) {
|
|
notesToRemove.push(key);
|
|
}
|
|
});
|
|
|
|
// check for new notes
|
|
var notesToAdd = [];
|
|
newNotes.forEach( function(key) {
|
|
if(oldNotes.indexOf(key) === -1) {
|
|
notesToAdd.push(key);
|
|
}
|
|
});
|
|
|
|
notesToAdd.forEach( function(key) {
|
|
for(var i = 0; i < self._state.buffer.length; i++) {
|
|
if(self._state.buffer[i].keyCode === key) {
|
|
self._trigger('down', self._state.buffer[i]);
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
notesToRemove.forEach( function(key) {
|
|
// these need to fire the entire object
|
|
for(var i = 0; i < oldBuffer.length; i++) {
|
|
if(oldBuffer[i].keyCode === key) {
|
|
self._trigger('up', oldBuffer[i]);
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
AudioKeys.prototype._prioritize = function() {
|
|
var self = this;
|
|
|
|
// if all the keys have been turned off, no need
|
|
// to do anything here.
|
|
if(!self._state.keys.length) {
|
|
self._state.buffer = [];
|
|
return;
|
|
}
|
|
|
|
|
|
if(self._state.polyphony >= self._state.keys.length) {
|
|
// every note is active
|
|
self._state.keys = self._state.keys.map( function(key) {
|
|
key.isActive = true;
|
|
return key;
|
|
});
|
|
} else {
|
|
// set all keys to inactive.
|
|
self._state.keys = self._state.keys.map( function(key) {
|
|
key.isActive = false;
|
|
return key;
|
|
});
|
|
|
|
self['_' + self._state.priority]();
|
|
}
|
|
|
|
// now take the isActive keys and set the new buffer.
|
|
self._state.buffer = [];
|
|
|
|
self._state.keys.forEach( function(key) {
|
|
if(key.isActive) {
|
|
self._state.buffer.push(key);
|
|
}
|
|
});
|
|
|
|
// done.
|
|
};
|
|
|
|
AudioKeys.prototype._last = function() {
|
|
var self = this;
|
|
// set the last bunch to active based on the polyphony.
|
|
for(var i = self._state.keys.length - self._state.polyphony; i < self._state.keys.length; i++) {
|
|
self._state.keys[i].isActive = true;
|
|
}
|
|
};
|
|
|
|
AudioKeys.prototype._first = function() {
|
|
var self = this;
|
|
// set the last bunch to active based on the polyphony.
|
|
for(var i = 0; i < self._state.polyphony; i++) {
|
|
self._state.keys[i].isActive = true;
|
|
}
|
|
};
|
|
|
|
AudioKeys.prototype._highest = function() {
|
|
var self = this;
|
|
// get the highest notes and set them to active
|
|
var notes = self._state.keys.map( function(key) {
|
|
return key.note;
|
|
});
|
|
|
|
notes.sort( function(b,a) {
|
|
if(a === b) {
|
|
return 0;
|
|
}
|
|
return a < b ? -1 : 1;
|
|
});
|
|
|
|
notes.splice(self._state.polyphony, Number.MAX_VALUE);
|
|
|
|
self._state.keys.forEach( function(key) {
|
|
if(notes.indexOf(key.note) !== -1) {
|
|
key.isActive = true;
|
|
}
|
|
});
|
|
};
|
|
|
|
AudioKeys.prototype._lowest = function() {
|
|
var self = this;
|
|
// get the lowest notes and set them to active
|
|
var notes = self._state.keys.map( function(key) {
|
|
return key.note;
|
|
});
|
|
|
|
notes.sort( function(a,b) {
|
|
if(a === b) {
|
|
return 0;
|
|
}
|
|
return a < b ? -1 : 1;
|
|
});
|
|
|
|
notes.splice(self._state.polyphony, Number.MAX_VALUE);
|
|
|
|
self._state.keys.forEach( function(key) {
|
|
if(notes.indexOf(key.note) !== -1) {
|
|
key.isActive = true;
|
|
}
|
|
});
|
|
};
|
|
|
|
// This file maps special keys to the state— octave shifting and
|
|
// velocity selection, both available when `rows` = 1.
|
|
|
|
AudioKeys.prototype._isSpecialKey = function(keyCode) {
|
|
return (this._state.rows === 1 && this._specialKeyMap[keyCode]);
|
|
};
|
|
|
|
AudioKeys.prototype._specialKey = function(keyCode) {
|
|
var self = this;
|
|
if(self._specialKeyMap[keyCode].type === 'octave' && self._state.octaveControls) {
|
|
// shift the state of the `octave`
|
|
self._state.octave += self._specialKeyMap[keyCode].value;
|
|
} else if(self._specialKeyMap[keyCode].type === 'velocity' && self._state.velocityControls) {
|
|
// set the `velocity` to a new value
|
|
self._state.velocity = self._specialKeyMap[keyCode].value;
|
|
}
|
|
};
|
|
|
|
AudioKeys.prototype._specialKeyMap = {
|
|
// octaves
|
|
90: {
|
|
type: 'octave',
|
|
value: -1
|
|
},
|
|
88: {
|
|
type: 'octave',
|
|
value: 1
|
|
},
|
|
// velocity
|
|
49: {
|
|
type: 'velocity',
|
|
value: 1
|
|
},
|
|
50: {
|
|
type: 'velocity',
|
|
value: 14
|
|
},
|
|
51: {
|
|
type: 'velocity',
|
|
value: 28
|
|
},
|
|
52: {
|
|
type: 'velocity',
|
|
value: 42
|
|
},
|
|
53: {
|
|
type: 'velocity',
|
|
value: 56
|
|
},
|
|
54: {
|
|
type: 'velocity',
|
|
value: 70
|
|
},
|
|
55: {
|
|
type: 'velocity',
|
|
value: 84
|
|
},
|
|
56: {
|
|
type: 'velocity',
|
|
value: 98
|
|
},
|
|
57: {
|
|
type: 'velocity',
|
|
value: 112
|
|
},
|
|
48: {
|
|
type: 'velocity',
|
|
value: 127
|
|
},
|
|
};
|
|
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkF1ZGlvS2V5cy5qcyIsIkF1ZGlvS2V5cy5zdGF0ZS5qcyIsIkF1ZGlvS2V5cy5ldmVudHMuanMiLCJBdWRpb0tleXMubWFwcGluZy5qcyIsIkF1ZGlvS2V5cy5idWZmZXIuanMiLCJBdWRpb0tleXMucHJpb3JpdHkuanMiLCJBdWRpb0tleXMuc3BlY2lhbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDckRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNoRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ3hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDN0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNwR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJhdWRpb2tleXMuanMiLCJzb3VyY2VzQ29udGVudCI6WyJmdW5jdGlvbiBBdWRpb0tleXMob3B0aW9ucykge1xuICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgc2VsZi5fc2V0U3RhdGUob3B0aW9ucyk7XG5cbiAgLy8gYWxsIGxpc3RlbmVycyBhcmUgc3RvcmVkIGluIGFycmF5cyBpbiB0aGVpciByZXNwZWN0aXZlIHByb3BlcnRpZXMuXG4gIC8vIGUuZy4gc2VsZi5fbGlzdGVuZXJzLmRvd24gPSBbZm4xLCBmbjIsIC4uLiBdXG4gIHNlbGYuX2xpc3RlbmVycyA9IHt9O1xuXG4gIC8vIGJpbmQgRE9NIGV2ZW50c1xuICBzZWxmLl9iaW5kKCk7XG59XG5cbi8vIFBsYXkgd2VsbCB3aXRoIHJlcXVpcmUgc28gdGhhdCB3ZSBjYW4gcnVuIGEgdGVzdCBzdWl0ZSBhbmQgdXNlIGJyb3dzZXJpZnkuXG5pZih0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJykge1xuICBtb2R1bGUuZXhwb3J0cyA9IEF1ZGlvS2V5cztcbn1cbiIsIkF1ZGlvS2V5cy5wcm90b3R5cGUuX3NldFN0YXRlID0gZnVuY3Rpb24ob3B0aW9ucykge1xuICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgaWYoIW9wdGlvbnMpIHtcbiAgICBvcHRpb25zID0ge307XG4gIH1cblxuICAvLyB0aGUgc3RhdGUgaXMga2VwdCBpbiB0aGlzIG9iamVjdFxuICBzZWxmLl9zdGF0ZSA9IHt9O1xuXG4gIC8vIHNldCBzb21lIGRlZmF1bHRzIC4uLlxuICBzZWxmLl9leHRlbmRTdGF0ZSh7XG4gICAgcG9seXBob255OiA0LFxuICAgIHJvd3M6IDEsXG4gICAgcHJpb3JpdHk6ICdsYXN0JyxcbiAgICByb290Tm90ZTogNjAsXG4gICAgb2N0YXZlQ29udHJvbHM6IHRydWUsXG4gICAgb2N0YXZlOiAwLFxuICAgIHZlbG9jaXR5Q29udHJvbHM6IHRydWUsXG4gICAgdmVsb2NpdHk6IDEyNyxcbiAgICBrZXlzOiBbXSxcbiAgICBidWZmZXI6IFtdXG4gIH0pO1xuXG4gIC8vIC4uLiBhbmQgb3ZlcnJpZGUgdGhlbSB3aXRoIG9wdGlvbnMuXG4gIHNlbGYuX2V4dGVuZFN0YXRlKG9wdGlvbnMpO1xufTtcblxuQXVkaW9LZXlzLnByb3RvdHlwZS5fZXh0ZW5kU3RhdGUgPSBmdW5jdGlvbihvcHRpb25zKSB7XG4gIHZhciBzZWxmID0gdGhpcztcblxuICBmb3IodmFyIG8gaW4gb3B0aW9ucykge1xuICAgIHNlbGYuX3N0YXRlW29dID0gb3B0aW9uc1tvXTtcbiAgfVxufTtcblxuQXVkaW9LZXlzLnByb3RvdHlwZS5zZXQgPSBmdW5jdGlvbigvKiBvcHRpb25zIHx8IHByb3BlcnR5LCB2YWx1ZSAqLykge1xuICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgaWYoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgIHNlbGYuX2V4dGVuZFN0YXRlKGFyZ3VtZW50c1swXSk7XG4gIH0gZWxzZSB7XG4gICAgc2VsZi5fc3RhdGVbYXJndW1lbnRzWzBdXSA9IGFyZ3VtZW50c1sxXTtcbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuQXVkaW9LZXlzLnByb3RvdHlwZS5nZXQgPSBmdW5jdGlvbihwcm9wZXJ0eSkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgcmV0dXJuIHNlbGYuX3N0YXRlW3Byb3BlcnR5XTtcbn07XG4iLCIvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBFdmVudCBMaXN0ZW5lcnNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLy8gQXVkaW9LZXlzIGhhcyBhIHZlcnkgc2ltcGxlIGV2ZW50IGhhbmRsaW5nIHN5c3RlbS4gSW50ZXJuYWxseVxuLy8gd2UnbGwgY2FsbCBzZWxmLl90cmlnZ2VyKCdkb3duJywgYXJndW1lbnQpIHdoZW4gd2Ugd2FudCB0byBmaXJlXG4vLyBhbiBldmVudCBmb3IgdGhlIHVzZXIuXG5cbkF1ZGlvS2V5cy5wcm90b3R5cGUuZG93biA9IGZ1bmN0aW9uKGZuKSB7XG4gIHZhciBzZWxmID0gdGhpcztcblxuICAvLyBhZGQgdGhlIGZ1bmN0aW9uIHRvIG91ciBsaXN0IG9mIGxpc3RlbmVyc1xuICBzZWxmLl9saXN0ZW5lcnMuZG93biA9IChzZWxmLl9saXN0ZW5lcnMuZG93biB8fCBbXSkuY29uY2F0KGZuKTtcbn07XG5cbkF1ZGlvS2V5cy5wcm90b3R5cGUudXAgPSBmdW5jdGlvbihmbikge1xuICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgLy8gYWRkIHRoZSBmdW5jdGlvbiB0byBvdXIgbGlzdCBvZiBsaXN0ZW5lcnNcbiAgc2VsZi5fbGlzdGVuZXJzLnVwID0gKHNlbGYuX2xpc3RlbmVycy51cCB8fCBbXSkuY29uY2F0KGZuKTtcbn07XG5cbkF1ZGlvS2V5cy5wcm90b3R5cGUuX3RyaWdnZXIgPSBmdW5jdGlvbihhY3Rpb24gLyogYXJncyAqLykge1xuICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgLy8gaWYgd2UgaGF2ZSBhbnkgbGlzdGVuZXJzIGJ5IHRoaXMgbmFtZSAuLi5cbiAgaWYoc2VsZi5fbGlzdGVuZXJzW2FjdGlvbl0gJiYgc2VsZi5fbGlzdGVuZXJzW2FjdGlvbl0ubGVuZ3RoKSB7XG4gICAgLy8gZ3JhYiB0aGUgYXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIGxpc3RlbmVycyAuLi5cbiAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgYXJncy5zcGxpY2UoMCwgMSk7XG4gICAgLy8gYW5kIGNhbGwgdGhlbSFcbiAgICBzZWxmLl9saXN0ZW5lcnNbYWN0aW9uXS5mb3JFYWNoKCBmdW5jdGlvbihmbikge1xuICAgICAgZm4uYXBwbHkoc2VsZiwgYXJncyk7XG4gICAgfSk7XG4gIH1cbn07XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIERPTSBCaW5kaW5nc1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5BdWRpb0tleXMucHJvdG90eXBlLl9iaW5kID0gZnVuY3Rpb24oKSB7XG4gIHZhciBzZWxmID0gdGhpcztcblxuICBpZih0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiB3aW5kb3cuZG9jdW1lbnQpIHtcbiAgICB3aW5kb3cuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIGZ1bmN0aW9uKGUpIHtcbiAgICAgIHNlbGYuX2FkZEtleShlKTtcbiAgICB9KTtcbiAgICB3aW5kb3cuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigna2V5dXAnLCBmdW5jdGlvbihlKSB7XG4gICAgICBzZWxmLl9yZW1vdmVLZXkoZSk7XG4gICAgfSk7XG5cbiAgICB2YXIgbGFzdEZvY3VzID0gdHJ1ZTtcbiAgICBzZXRJbnRlcnZhbCggZnVuY3Rpb24oKSB7XG4gICAgICBpZih3aW5kb3cuZG9jdW1lbnQuaGFzRm9jdXMoKSA9PT0gbGFzdEZvY3VzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGxhc3RGb2N1cyA9ICFsYXN0Rm9jdXM7XG4gICAgICBpZighbGFzdEZvY3VzKSB7XG4gICAgICAgIHNlbGYuY2xlYXIoKTtcbiAgICAgIH1cbiAgICB9LCAxMDApO1xuICB9XG59O1xuIiwiLy8gX21hcCByZXR1cm5zIHRoZSBtaWRpIG5vdGUgZm9yIGEgZ2l2ZW4ga2V5Q29kZS5cbkF1ZGlvS2V5cy5wcm90b3R5cGUuX21hcCA9IGZ1bmN0aW9uKGtleUNvZGUpIHtcbiAgcmV0dXJuIHRoaXMuX2tleU1hcFt0aGlzLl9zdGF0ZS5yb3dzXVtrZXlDb2RlXSArIHRoaXMuX29mZnNldCgpO1xufTtcblxuQXVkaW9LZXlzLnByb3RvdHlwZS5fb2Zmc2V0ID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiB0aGlzLl9zdGF0ZS5yb290Tm90ZSAtIHRoaXMuX2tleU1hcFt0aGlzLl9zdGF0ZS5yb3dzXS5yb290ICsgKHRoaXMuX3N0YXRlLm9jdGF2ZSAqIDEyKTtcbn07XG5cbi8vIF9pc05vdGUgZGV0ZXJtaW5lcyB3aGV0aGVyIGEga2V5Q29kZSBpcyBhIG5vdGUgb3Igbm90LlxuQXVkaW9LZXlzLnByb3RvdHlwZS5faXNOb3RlID0gZnVuY3Rpb24oa2V5Q29kZSkge1xuICByZXR1cm4gISF0aGlzLl9rZXlNYXBbdGhpcy5fc3RhdGUucm93c11ba2V5Q29kZV07XG59O1xuXG4vLyBjb252ZXJ0IGEgbWlkaSBub3RlIHRvIGEgZnJlcXVlbmN5LiB3ZSBhc3N1bWUgaGVyZSB0aGF0IF9tYXAgaGFzXG4vLyBhbHJlYWR5IGJlZW4gY2FsbGVkICh0byBhY2NvdW50IGZvciBhIHBvdGVudGlhbCByb290Tm90ZSBvZmZzZXQpXG5BdWRpb0tleXMucHJvdG90eXBlLl90b0ZyZXF1ZW5jeSA9IGZ1bmN0aW9uKG5vdGUpIHtcbiAgcmV0dXJuICggTWF0aC5wb3coMiwgKCBub3RlLTY5ICkgLyAxMikgKSAqIDQ0MC4wO1xufTtcblxuLy8gdGhlIG9iamVjdCBrZXlzIGNvcnJlc3BvbmQgdG8gYHJvd3NgLCBzbyBgX2tleU1hcFtyb3dzXWAgc2hvdWxkXG4vLyByZXRyaWV2ZSB0aGF0IHBhcnRpY3VsYXIgbWFwcGluZy5cbkF1ZGlvS2V5cy5wcm90b3R5cGUuX2tleU1hcCA9IHtcbiAgMToge1xuICAgIHJvb3Q6IDYwLFxuICAgIC8vIHN0YXJ0aW5nIHdpdGggdGhlICdhJyBrZXlcbiAgICA2NTogIDYwLFxuICAgIDg3OiAgNjEsXG4gICAgODM6ICA2MixcbiAgICA2OTogIDYzLFxuICAgIDY4OiAgNjQsXG4gICAgNzA6ICA2NSxcbiAgICA4NDogIDY2LFxuICAgIDcxOiAgNjcsXG4gICAgODk6ICA2OCxcbiAgICA3MjogIDY5LFxuICAgIDg1OiAgNzAsXG4gICAgNzQ6ICA3MSxcbiAgICA3NTogIDcyLFxuICAgIDc5OiAgNzMsXG4gICAgNzY6ICA3NCxcbiAgICA4MDogIDc1LFxuICAgIDE4NjogNzYsXG4gICAgMjIyOiA3N1xuICB9LFxuICAyOiB7XG4gICAgcm9vdDogNjAsXG4gICAgLy8gYm90dG9tIHJvd1xuICAgIDkwOiAgNjAsXG4gICAgODM6ICA2MSxcbiAgICA4ODogIDYyLFxuICAgIDY4OiAgNjMsXG4gICAgNjc6ICA2NCxcbiAgICA4NjogIDY1LFxuICAgIDcxOiAgNjYsXG4gICAgNjY6ICA2NyxcbiAgICA3MjogIDY4LFxuICAgIDc4OiAgNjksXG4gICAgNzQ6ICA3MCxcbiAgICA3NzogIDcxLFxuICAgIDE4ODogNzIsXG4gICAgNzY6ICA3MyxcbiAgICAxOTA6IDc0LFxuICAgIDE4NjogNzUsXG4gICAgMTkxOiA3NixcbiAgICAvLyB0b3Agcm93XG4gICAgODE6ICA3MixcbiAgICA1MDogIDczLFxuICAgIDg3OiAgNzQsXG4gICAgNTE6ICA3NSxcbiAgICA2OTogIDc2LFxuICAgIDgyOiAgNzcsXG4gICAgNTM6ICA3OCxcbiAgICA4NDogIDc5LFxuICAgIDU0OiAgODAsXG4gICAgODk6ICA4MSxcbiAgICA1NTogIDgyLFxuICAgIDg1OiAgODMsXG4gICAgNzM6ICA4NCxcbiAgICA1NzogIDg1LFxuICAgIDc5OiAgODYsXG4gICAgNDg6ICA4NyxcbiAgICA4MDogIDg4LFxuICAgIDIxOTogODksXG4gICAgMTg3OiA5MCxcbiAgICAyMjE6IDkxXG4gIH1cbn07XG4iLCIvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBLRVkgQlVGRkVSXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8vIFRoZSBwcm9jZXNzIGlzOlxuXG4vLyBrZXkgcHJlc3Ncbi8vICAgYWRkIHRvIHNlbGYuX3N0YXRlLmtleXNcbi8vICAgKGFuIGFjY3VyYXRlIHJlcHJlc2VudGF0aW9uIG9mIGtleXMgY3VycmVudGx5IHByZXNzZWQpXG4vLyByZXNvbHZlIHNlbGYuYnVmZmVyXG4vLyAgIGJhc2VkIG9uIHBvbHlwaG9ueSBhbmQgcHJpb3JpdHksIGRldGVybWluZSB0aGUgbm90ZXNcbi8vICAgdGhhdCBnZXQgdHJpZ2dlcmVkIGZvciB0aGUgdXNlclxuXG5BdWRpb0tleXMucHJvdG90eXBlLl9hZGRLZXkgPSBmdW5jdGlvbihlKSB7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgLy8gaWYgdGhlIGtleUNvZGUgaXMgb25lIHRoYXQgY2FuIGJlIG1hcHBlZCBhbmQgaXNuJ3RcbiAgLy8gYWxyZWFkeSBwcmVzc2VkLCBhZGQgaXQgdG8gdGhlIGtleSBvYmplY3QuXG4gIGlmKHNlbGYuX2lzTm90ZShlLmtleUNvZGUpICYmICFzZWxmLl9pc1ByZXNzZWQoZS5rZXlDb2RlKSkge1xuICAgIHZhciBuZXdLZXkgPSBzZWxmLl9tYWtlTm90ZShlLmtleUNvZGUpO1xuICAgIC8vIGFkZCB0aGUgbmV3S2V5IHRvIHRoZSBsaXN0IG9mIGtleXNcbiAgICBzZWxmLl9zdGF0ZS5rZXlzID0gKHNlbGYuX3N0YXRlLmtleXMgfHwgW10pLmNvbmNhdChuZXdLZXkpO1xuICAgIC8vIHJlZXZhbHVhdGUgdGhlIGFjdGl2ZSBub3RlcyBiYXNlZCBvbiBvdXIgcHJpb3JpdHkgcnVsZXMuXG4gICAgLy8gZ2l2ZSBpdCB0aGUgbmV3IG5vdGUgdG8gdXNlIGlmIHRoZXJlIGlzIGFuIGV2ZW50IHRvIHRyaWdnZXIuXG4gICAgc2VsZi5fdXBkYXRlKCk7XG4gIH0gZWxzZSBpZihzZWxmLl9pc1NwZWNpYWxLZXkoZS5rZXlDb2RlKSkge1xuICAgIHNlbGYuX3NwZWNpYWxLZXkoZS5rZXlDb2RlKTtcbiAgfVxufTtcblxuQXVkaW9LZXlzLnByb3RvdHlwZS5fcmVtb3ZlS2V5ID0gZnVuY3Rpb24oZSkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIC8vIGlmIHRoZSBrZXlDb2RlIGlzIGFjdGl2ZSwgcmVtb3ZlIGl0IGZyb20gdGhlIGtleSBvYmplY3QuXG4gIGlmKHNlbGYuX2lzUHJlc3NlZChlLmtleUNvZGUpKSB7XG4gICAgdmFyIGtleVRvUmVtb3ZlO1xuICAgIGZvcih2YXIgaSA9IDA7IGkgPCBzZWxmLl9zdGF0ZS5rZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZihzZWxmLl9zdGF0ZS5rZXlzW2ldLmtleUNvZGUgPT09IGUua2V5Q29kZSkge1xuICAgICAgICBrZXlUb1JlbW92ZSA9IHNlbGYuX3N0YXRlLmtleXNbaV07XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIHJlbW92ZSB0aGUga2V5IGZyb20gX2tleXNcbiAgICBzZWxmLl9zdGF0ZS5rZXlzLnNwbGljZShzZWxmLl9zdGF0ZS5rZXlzLmluZGV4T2Yoa2V5VG9SZW1vdmUpLCAxKTtcbiAgICBzZWxmLl91cGRhdGUoKTtcbiAgfVxufTtcblxuQXVkaW9LZXlzLnByb3RvdHlwZS5faXNQcmVzc2VkID0gZnVuY3Rpb24oa2V5Q29kZSkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgaWYoIXNlbGYuX3N0YXRlLmtleXMgfHwgIXNlbGYuX3N0YXRlLmtleXMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgZm9yKHZhciBpID0gMDsgaSA8IHNlbGYuX3N0YXRlLmtleXMubGVuZ3RoOyBpKyspIHtcbiAgICBpZihzZWxmLl9zdGF0ZS5rZXlzW2ldLmtleUNvZGUgPT09IGtleUNvZGUpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZmFsc2U7XG59O1xuXG4vLyB0dXJuIGEga2V5IG9iamVjdCBpbnRvIGEgbm90ZSBvYmplY3QgZm9yIHRoZSBldmVudCBsaXN0ZW5lcnMuXG5BdWRpb0tleXMucHJvdG90eXBlLl9tYWtlTm90ZSA9IGZ1bmN0aW9uKGtleUNvZGUpIHtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICByZXR1cm4ge1xuICAgIGtleUNvZGU6IGtleUNvZGUsXG4gICAgbm90ZTogc2VsZi5fbWFwKGtleUNvZGUpLFxuICAgIGZyZXF1ZW5jeTogc2VsZi5fdG9GcmVxdWVuY3koIHNlbGYuX21hcChrZXlDb2RlKSApLFxuICAgIHZlbG9jaXR5OiBzZWxmLl9zdGF0ZS52ZWxvY2l0eVxuICB9O1xufTtcblxuLy8gY2xlYXIgYW55IGFjdGl2ZSBub3Rlc1xuQXVkaW9LZXlzLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uKCkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIC8vIHRyaWdnZXIgbm90ZSBvZmYgZm9yIHRoZSBub3RlcyBpbiB0aGUgYnVmZmVyIGJlZm9yZVxuICAvLyByZW1vdmluZyB0aGVtLlxuICBzZWxmLl9zdGF0ZS5idWZmZXIuZm9yRWFjaCggZnVuY3Rpb24oa2V5KSB7XG4gICAgc2VsZi5fdHJpZ2dlcigndXAnLCBrZXkpO1xuICB9KTtcbiAgc2VsZi5fc3RhdGUua2V5cyA9IFtdO1xuICBzZWxmLl9zdGF0ZS5idWZmZXIgPSBbXTtcbn07XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIE5PVEUgQlVGRkVSXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8vIGV2ZXJ5IHRpbWUgYSBjaGFuZ2UgaXMgbWFkZSB0byBfa2V5cyBkdWUgdG8gYSBrZXkgb24gb3Iga2V5IG9mZlxuLy8gd2UgbmVlZCB0byBjYWxsIGBfdXBkYXRlYC4gSXQgY29tcGFyZXMgdGhlIGBfa2V5c2AgYXJyYXkgdG8gdGhlXG4vLyBgYnVmZmVyYCBhcnJheSwgd2hpY2ggaXMgdGhlIGFycmF5IG9mIG5vdGVzIHRoYXQgYXJlIHJlYWxseVxuLy8gYmVpbmcgcGxheWVkLCBtYWtlcyB0aGUgbmVjZXNzYXJ5IGNoYW5nZXMgdG8gYGJ1ZmZlcmAgYW5kXG4vLyB0cmlnZ2VycyBhbnkgZXZlbnRzIHRoYXQgbmVlZCB0cmlnZ2VyaW5nLlxuXG5BdWRpb0tleXMucHJvdG90eXBlLl91cGRhdGUgPSBmdW5jdGlvbigpIHtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gIC8vIGEga2V5IGhhcyBiZWVuIGFkZGVkIHRvIHNlbGYuX3N0YXRlLmtleXMuXG4gIC8vIHN0YXNoIHRoZSBvbGQgYnVmZmVyXG4gIHZhciBvbGRCdWZmZXIgPSBzZWxmLl9zdGF0ZS5idWZmZXI7XG4gIC8vIHNldCB0aGUgbmV3IHByaW9yaXR5IGluIHNlbGYuc3RhdGUuX2tleXNcbiAgc2VsZi5fcHJpb3JpdGl6ZSgpO1xuICAvLyBjb21wYXJlIHRoZSBidWZmZXJzIGFuZCB0cmlnZ2VyIGV2ZW50cyBiYXNlZCBvblxuICAvLyB0aGUgZGlmZmVyZW5jZXMuXG4gIHNlbGYuX2RpZmYob2xkQnVmZmVyKTtcbn07XG5cbkF1ZGlvS2V5cy5wcm90b3R5cGUuX2RpZmYgPSBmdW5jdGlvbihvbGRCdWZmZXIpIHtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gIC8vIGlmIGl0J3Mgbm90IGluIHRoZSBPTEQgYnVmZmVyLCBpdCdzIGEgbm90ZSBPTi5cbiAgLy8gaWYgaXQncyBub3QgaW4gdGhlIE5FVyBidWZmZXIsIGl0J3MgYSBub3RlIE9GRi5cblxuICB2YXIgb2xkTm90ZXMgPSBvbGRCdWZmZXIubWFwKCBmdW5jdGlvbihrZXkpIHtcbiAgICByZXR1cm4ga2V5LmtleUNvZGU7XG4gIH0pO1xuXG4gIHZhciBuZXdOb3RlcyA9IHNlbGYuX3N0YXRlLmJ1ZmZlci5tYXAoIGZ1bmN0aW9uKGtleSkge1xuICAgIHJldHVybiBrZXkua2V5Q29kZTtcbiAgfSk7XG5cbiAgLy8gY2hlY2sgZm9yIG9sZCAocmVtb3ZlZCkgbm90ZXNcbiAgdmFyIG5vdGVzVG9SZW1vdmUgPSBbXTtcbiAgb2xkTm90ZXMuZm9yRWFjaCggZnVuY3Rpb24oa2V5KSB7XG4gICAgaWYobmV3Tm90ZXMuaW5kZXhPZihrZXkpID09PSAtMSkge1xuICAgICAgbm90ZXNUb1JlbW92ZS5wdXNoKGtleSk7XG4gICAgfVxuICB9KTtcblxuICAvLyBjaGVjayBmb3IgbmV3IG5vdGVzXG4gIHZhciBub3Rlc1RvQWRkID0gW107XG4gIG5ld05vdGVzLmZvckVhY2goIGZ1bmN0aW9uKGtleSkge1xuICAgIGlmKG9sZE5vdGVzLmluZGV4T2Yoa2V5KSA9PT0gLTEpIHtcbiAgICAgIG5vdGVzVG9BZGQucHVzaChrZXkpO1xuICAgIH1cbiAgfSk7XG5cbiAgbm90ZXNUb0FkZC5mb3JFYWNoKCBmdW5jdGlvbihrZXkpIHtcbiAgICBmb3IodmFyIGkgPSAwOyBpIDwgc2VsZi5fc3RhdGUuYnVmZmVyLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZihzZWxmLl9zdGF0ZS5idWZmZXJbaV0ua2V5Q29kZSA9PT0ga2V5KSB7XG4gICAgICAgIHNlbGYuX3RyaWdnZXIoJ2Rvd24nLCBzZWxmLl9zdGF0ZS5idWZmZXJbaV0pO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuXG4gIG5vdGVzVG9SZW1vdmUuZm9yRWFjaCggZnVuY3Rpb24oa2V5KSB7XG4gICAgLy8gdGhlc2UgbmVlZCB0byBmaXJlIHRoZSBlbnRpcmUgb2JqZWN0XG4gICAgZm9yKHZhciBpID0gMDsgaSA8IG9sZEJ1ZmZlci5sZW5ndGg7IGkrKykge1xuICAgICAgaWYob2xkQnVmZmVyW2ldLmtleUNvZGUgPT09IGtleSkge1xuICAgICAgICBzZWxmLl90cmlnZ2VyKCd1cCcsIG9sZEJ1ZmZlcltpXSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG59O1xuIiwiQXVkaW9LZXlzLnByb3RvdHlwZS5fcHJpb3JpdGl6ZSA9IGZ1bmN0aW9uKCkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgLy8gaWYgYWxsIHRoZSBrZXlzIGhhdmUgYmVlbiB0dXJuZWQgb2ZmLCBubyBuZWVkXG4gIC8vIHRvIGRvIGFueXRoaW5nIGhlcmUuXG4gIGlmKCFzZWxmLl9zdGF0ZS5rZXlzLmxlbmd0aCkge1xuICAgIHNlbGYuX3N0YXRlLmJ1ZmZlciA9IFtdO1xuICAgIHJldHVybjtcbiAgfVxuXG5cbiAgaWYoc2VsZi5fc3RhdGUucG9seXBob255ID49IHNlbGYuX3N0YXRlLmtleXMubGVuZ3RoKSB7XG4gICAgLy8gZXZlcnkgbm90ZSBpcyBhY3RpdmVcbiAgICBzZWxmLl9zdGF0ZS5rZXlzID0gc2VsZi5fc3RhdGUua2V5cy5tYXAoIGZ1bmN0aW9uKGtleSkge1xuICAgICAga2V5LmlzQWN0aXZlID0gdHJ1ZTtcbiAgICAgIHJldHVybiBrZXk7XG4gICAgfSk7XG4gIH0gZWxzZSB7XG4gICAgLy8gc2V0IGFsbCBrZXlzIHRvIGluYWN0aXZlLlxuICAgIHNlbGYuX3N0YXRlLmtleXMgPSBzZWxmLl9zdGF0ZS5rZXlzLm1hcCggZnVuY3Rpb24oa2V5KSB7XG4gICAgICBrZXkuaXNBY3RpdmUgPSBmYWxzZTtcbiAgICAgIHJldHVybiBrZXk7XG4gICAgfSk7XG5cbiAgICBzZWxmWydfJyArIHNlbGYuX3N0YXRlLnByaW9yaXR5XSgpO1xuICB9XG5cbiAgLy8gbm93IHRha2UgdGhlIGlzQWN0aXZlIGtleXMgYW5kIHNldCB0aGUgbmV3IGJ1ZmZlci5cbiAgc2VsZi5fc3RhdGUuYnVmZmVyID0gW107XG5cbiAgc2VsZi5fc3RhdGUua2V5cy5mb3JFYWNoKCBmdW5jdGlvbihrZXkpIHtcbiAgICBpZihrZXkuaXNBY3RpdmUpIHtcbiAgICAgIHNlbGYuX3N0YXRlLmJ1ZmZlci5wdXNoKGtleSk7XG4gICAgfVxuICB9KTtcblxuICAvLyBkb25lLlxufTtcblxuQXVkaW9LZXlzLnByb3RvdHlwZS5fbGFzdCA9IGZ1bmN0aW9uKCkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIC8vIHNldCB0aGUgbGFzdCBidW5jaCB0byBhY3RpdmUgYmFzZWQgb24gdGhlIHBvbHlwaG9ueS5cbiAgZm9yKHZhciBpID0gc2VsZi5fc3RhdGUua2V5cy5sZW5ndGggLSBzZWxmLl9zdGF0ZS5wb2x5cGhvbnk7IGkgPCBzZWxmLl9zdGF0ZS5rZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgc2VsZi5fc3RhdGUua2V5c1tpXS5pc0FjdGl2ZSA9IHRydWU7XG4gIH1cbn07XG5cbkF1ZGlvS2V5cy5wcm90b3R5cGUuX2ZpcnN0ID0gZnVuY3Rpb24oKSB7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgLy8gc2V0IHRoZSBsYXN0IGJ1bmNoIHRvIGFjdGl2ZSBiYXNlZCBvbiB0aGUgcG9seXBob255LlxuICBmb3IodmFyIGkgPSAwOyBpIDwgc2VsZi5fc3RhdGUucG9seXBob255OyBpKyspIHtcbiAgICBzZWxmLl9zdGF0ZS5rZXlzW2ldLmlzQWN0aXZlID0gdHJ1ZTtcbiAgfVxufTtcblxuQXVkaW9LZXlzLnByb3RvdHlwZS5faGlnaGVzdCA9IGZ1bmN0aW9uKCkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIC8vIGdldCB0aGUgaGlnaGVzdCBub3RlcyBhbmQgc2V0IHRoZW0gdG8gYWN0aXZlXG4gIHZhciBub3RlcyA9IHNlbGYuX3N0YXRlLmtleXMubWFwKCBmdW5jdGlvbihrZXkpIHtcbiAgICByZXR1cm4ga2V5Lm5vdGU7XG4gIH0pO1xuXG4gIG5vdGVzLnNvcnQoIGZ1bmN0aW9uKGIsYSkge1xuICAgIGlmKGEgPT09IGIpIHtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICByZXR1cm4gYSA8IGIgPyAtMSA6IDE7XG4gIH0pO1xuXG4gIG5vdGVzLnNwbGljZShzZWxmLl9zdGF0ZS5wb2x5cGhvbnksIE51bWJlci5NQVhfVkFMVUUpO1xuXG4gIHNlbGYuX3N0YXRlLmtleXMuZm9yRWFjaCggZnVuY3Rpb24oa2V5KSB7XG4gICAgaWYobm90ZXMuaW5kZXhPZihrZXkubm90ZSkgIT09IC0xKSB7XG4gICAgICBrZXkuaXNBY3RpdmUgPSB0cnVlO1xuICAgIH1cbiAgfSk7XG59O1xuXG5BdWRpb0tleXMucHJvdG90eXBlLl9sb3dlc3QgPSBmdW5jdGlvbigpIHtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICAvLyBnZXQgdGhlIGxvd2VzdCBub3RlcyBhbmQgc2V0IHRoZW0gdG8gYWN0aXZlXG4gIHZhciBub3RlcyA9IHNlbGYuX3N0YXRlLmtleXMubWFwKCBmdW5jdGlvbihrZXkpIHtcbiAgICByZXR1cm4ga2V5Lm5vdGU7XG4gIH0pO1xuXG4gIG5vdGVzLnNvcnQoIGZ1bmN0aW9uKGEsYikge1xuICAgIGlmKGEgPT09IGIpIHtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICByZXR1cm4gYSA8IGIgPyAtMSA6IDE7XG4gIH0pO1xuXG4gIG5vdGVzLnNwbGljZShzZWxmLl9zdGF0ZS5wb2x5cGhvbnksIE51bWJlci5NQVhfVkFMVUUpO1xuXG4gIHNlbGYuX3N0YXRlLmtleXMuZm9yRWFjaCggZnVuY3Rpb24oa2V5KSB7XG4gICAgaWYobm90ZXMuaW5kZXhPZihrZXkubm90ZSkgIT09IC0xKSB7XG4gICAgICBrZXkuaXNBY3RpdmUgPSB0cnVlO1xuICAgIH1cbiAgfSk7XG59O1xuIiwiLy8gVGhpcyBmaWxlIG1hcHMgc3BlY2lhbCBrZXlzIHRvIHRoZSBzdGF0ZeKAlCBvY3RhdmUgc2hpZnRpbmcgYW5kXG4vLyB2ZWxvY2l0eSBzZWxlY3Rpb24sIGJvdGggYXZhaWxhYmxlIHdoZW4gYHJvd3NgID0gMS5cblxuQXVkaW9LZXlzLnByb3RvdHlwZS5faXNTcGVjaWFsS2V5ID0gZnVuY3Rpb24oa2V5Q29kZSkge1xuICByZXR1cm4gKHRoaXMuX3N0YXRlLnJvd3MgPT09IDEgJiYgdGhpcy5fc3BlY2lhbEtleU1hcFtrZXlDb2RlXSk7XG59O1xuXG5BdWRpb0tleXMucHJvdG90eXBlLl9zcGVjaWFsS2V5ID0gZnVuY3Rpb24oa2V5Q29kZSkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIGlmKHNlbGYuX3NwZWNpYWxLZXlNYXBba2V5Q29kZV0udHlwZSA9PT0gJ29jdGF2ZScgJiYgc2VsZi5fc3RhdGUub2N0YXZlQ29udHJvbHMpIHtcbiAgICAvLyBzaGlmdCB0aGUgc3RhdGUgb2YgdGhlIGBvY3RhdmVgXG4gICAgc2VsZi5fc3RhdGUub2N0YXZlICs9IHNlbGYuX3NwZWNpYWxLZXlNYXBba2V5Q29kZV0udmFsdWU7XG4gIH0gZWxzZSBpZihzZWxmLl9zcGVjaWFsS2V5TWFwW2tleUNvZGVdLnR5cGUgPT09ICd2ZWxvY2l0eScgJiYgc2VsZi5fc3RhdGUudmVsb2NpdHlDb250cm9scykge1xuICAgIC8vIHNldCB0aGUgYHZlbG9jaXR5YCB0byBhIG5ldyB2YWx1ZVxuICAgIHNlbGYuX3N0YXRlLnZlbG9jaXR5ID0gc2VsZi5fc3BlY2lhbEtleU1hcFtrZXlDb2RlXS52YWx1ZTtcbiAgfVxufTtcblxuQXVkaW9LZXlzLnByb3RvdHlwZS5fc3BlY2lhbEtleU1hcCA9IHtcbiAgLy8gb2N0YXZlc1xuICA5MDoge1xuICAgIHR5cGU6ICdvY3RhdmUnLFxuICAgIHZhbHVlOiAtMVxuICB9LFxuICA4ODoge1xuICAgIHR5cGU6ICdvY3RhdmUnLFxuICAgIHZhbHVlOiAxXG4gIH0sXG4gIC8vIHZlbG9jaXR5XG4gIDQ5OiB7XG4gICAgdHlwZTogJ3ZlbG9jaXR5JyxcbiAgICB2YWx1ZTogMVxuICB9LFxuICA1MDoge1xuICAgIHR5cGU6ICd2ZWxvY2l0eScsXG4gICAgdmFsdWU6IDE0XG4gIH0sXG4gIDUxOiB7XG4gICAgdHlwZTogJ3ZlbG9jaXR5JyxcbiAgICB2YWx1ZTogMjhcbiAgfSxcbiAgNTI6IHtcbiAgICB0eXBlOiAndmVsb2NpdHknLFxuICAgIHZhbHVlOiA0MlxuICB9LFxuICA1Mzoge1xuICAgIHR5cGU6ICd2ZWxvY2l0eScsXG4gICAgdmFsdWU6IDU2XG4gIH0sXG4gIDU0OiB7XG4gICAgdHlwZTogJ3ZlbG9jaXR5JyxcbiAgICB2YWx1ZTogNzBcbiAgfSxcbiAgNTU6IHtcbiAgICB0eXBlOiAndmVsb2NpdHknLFxuICAgIHZhbHVlOiA4NFxuICB9LFxuICA1Njoge1xuICAgIHR5cGU6ICd2ZWxvY2l0eScsXG4gICAgdmFsdWU6IDk4XG4gIH0sXG4gIDU3OiB7XG4gICAgdHlwZTogJ3ZlbG9jaXR5JyxcbiAgICB2YWx1ZTogMTEyXG4gIH0sXG4gIDQ4OiB7XG4gICAgdHlwZTogJ3ZlbG9jaXR5JyxcbiAgICB2YWx1ZTogMTI3XG4gIH0sXG59O1xuIl0sInNvdXJjZVJvb3QiOiIvc291cmNlLyJ9
|