Last active
August 8, 2016 05:44
-
-
Save realazthat/0bddc47030d7166119c02876e68d3eaf to your computer and use it in GitHub Desktop.
requirebin sketch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var createKDTree = require("static-kdtree"); | |
const resl = require('resl'); | |
const regl = require('regl')({ | |
attributes: {preserveDrawingBuffer: true} | |
}); | |
const quad = require('glsl-quad'); | |
var us = require('microseconds'); | |
const drawTexture = regl({ | |
vert: quad.shader.vert, | |
frag: quad.shader.frag, | |
attributes: { | |
a_position: quad.verts, | |
a_uv: quad.uvs | |
}, | |
elements: quad.indices, | |
uniforms: { | |
u_tex: regl.prop('texture'), | |
u_clip_y: +1 | |
} | |
}); | |
let util = { | |
coords: function coords({curve, M}) { | |
let x = curve % M.x; | |
let y = Math.floor(curve / M.x); | |
return {x,y}; | |
}, | |
modulo: function modulo(v,m){ | |
if (v >= 0){ | |
return v % m | |
} | |
v = -v; | |
v %= m; | |
return m - v; | |
}, | |
curve: function curve({x, y, M}) { | |
x = this.modulo(x, M.x); | |
y = this.modulo(y, M.y); | |
return y*M.x + x; | |
} | |
}; | |
resl({ | |
manifest: { | |
"0": { | |
type: 'image', | |
// quad provides a bitmap as a uri to display; the "directions" bitmap shows two | |
// axis with up/down/right/left lines/arrows. | |
src: quad.bitmaps.directions.uri, | |
parser: (data) => regl.texture({ | |
data: data, | |
mag: 'nearest', | |
min: 'nearest', | |
flipY: true | |
}) | |
}, | |
"1": { | |
type: 'image', | |
src: 'https://raw.githubusercontent.com/realazthat/glsl-gaussian/master/assets/Storm%20Cell%20Over%20the%20Southern%20Appalachian%20Mountains-dsc_2303_0-256x256.png', | |
parser: (data) => regl.texture({ | |
data: data, | |
mag: 'nearest', | |
min: 'nearest', | |
flipY: true | |
}) | |
} | |
}, | |
onDone: (textures) => { | |
for (let tkey of Object.keys(textures)) { | |
let texture = textures[tkey]; | |
let fbo = regl.framebuffer({ | |
color: texture, | |
colorFormat: 'rgba', | |
colorType: 'uint8', | |
depth: false, | |
stencil: false | |
}); | |
let data = null; | |
regl({framebuffer: fbo})(() => { | |
data = regl.read(); | |
}); | |
let channels = 4; | |
let interestingChannels = 3; | |
let M = {x: texture.width, y: texture.height}; | |
let rows = []; | |
for (let curve = 0; curve < (data.length/channels); ++curve) { | |
let {x,y} = util.coords({curve, M}); | |
let row = []; | |
for (let rx = -2; rx <= 2; ++rx) { | |
for (let ry = -2; ry <= 2; ++ry) { | |
let nx = x + rx; | |
let ny = y + ry; | |
let ncurve = util.curve({x: nx, y: ny, M}); | |
for (let channel = 0; channel < interestingChannels; ++channel) { | |
row.push(data[ncurve*channels+channel]); | |
} | |
} | |
} | |
rows.push(row); | |
} | |
console.log('M: ', M); | |
console.log('data.length:', data.length); | |
console.log('rows.length: ', rows.length); | |
//drawTexture({texture}); | |
let t0 = us.now(); | |
console.log('building kd-tree ...'); | |
let tree = createKDTree(rows); | |
let dt = us.since(t0); | |
console.log('kd-tree built. in ' + us.parse(dt).toString()); | |
} | |
} | |
}); |
This file has been truncated, but you can view the full file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
setTimeout(function(){ | |
;require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
(function (global){ | |
/*! | |
* The buffer module from node.js, for the browser. | |
* | |
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org> | |
* @license MIT | |
*/ | |
/* eslint-disable no-proto */ | |
'use strict' | |
var base64 = require('base64-js') | |
var ieee754 = require('ieee754') | |
var isArray = require('isarray') | |
exports.Buffer = Buffer | |
exports.SlowBuffer = SlowBuffer | |
exports.INSPECT_MAX_BYTES = 50 | |
Buffer.poolSize = 8192 // not used by this implementation | |
var rootParent = {} | |
/** | |
* If `Buffer.TYPED_ARRAY_SUPPORT`: | |
* === true Use Uint8Array implementation (fastest) | |
* === false Use Object implementation (most compatible, even IE6) | |
* | |
* Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, | |
* Opera 11.6+, iOS 4.2+. | |
* | |
* Due to various browser bugs, sometimes the Object implementation will be used even | |
* when the browser supports typed arrays. | |
* | |
* Note: | |
* | |
* - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, | |
* See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. | |
* | |
* - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property | |
* on objects. | |
* | |
* - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. | |
* | |
* - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of | |
* incorrect length in some situations. | |
* We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they | |
* get the Object implementation, which is slower but behaves correctly. | |
*/ | |
Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined | |
? global.TYPED_ARRAY_SUPPORT | |
: typedArraySupport() | |
function typedArraySupport () { | |
function Bar () {} | |
try { | |
var arr = new Uint8Array(1) | |
arr.foo = function () { return 42 } | |
arr.constructor = Bar | |
return arr.foo() === 42 && // typed array instances can be augmented | |
arr.constructor === Bar && // constructor can be set | |
typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` | |
arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` | |
} catch (e) { | |
return false | |
} | |
} | |
function kMaxLength () { | |
return Buffer.TYPED_ARRAY_SUPPORT | |
? 0x7fffffff | |
: 0x3fffffff | |
} | |
/** | |
* Class: Buffer | |
* ============= | |
* | |
* The Buffer constructor returns instances of `Uint8Array` that are augmented | |
* with function properties for all the node `Buffer` API functions. We use | |
* `Uint8Array` so that square bracket notation works as expected -- it returns | |
* a single octet. | |
* | |
* By augmenting the instances, we can avoid modifying the `Uint8Array` | |
* prototype. | |
*/ | |
function Buffer (arg) { | |
if (!(this instanceof Buffer)) { | |
// Avoid going through an ArgumentsAdaptorTrampoline in the common case. | |
if (arguments.length > 1) return new Buffer(arg, arguments[1]) | |
return new Buffer(arg) | |
} | |
if (!Buffer.TYPED_ARRAY_SUPPORT) { | |
this.length = 0 | |
this.parent = undefined | |
} | |
// Common case. | |
if (typeof arg === 'number') { | |
return fromNumber(this, arg) | |
} | |
// Slightly less common case. | |
if (typeof arg === 'string') { | |
return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8') | |
} | |
// Unusual. | |
return fromObject(this, arg) | |
} | |
function fromNumber (that, length) { | |
that = allocate(that, length < 0 ? 0 : checked(length) | 0) | |
if (!Buffer.TYPED_ARRAY_SUPPORT) { | |
for (var i = 0; i < length; i++) { | |
that[i] = 0 | |
} | |
} | |
return that | |
} | |
function fromString (that, string, encoding) { | |
if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8' | |
// Assumption: byteLength() return value is always < kMaxLength. | |
var length = byteLength(string, encoding) | 0 | |
that = allocate(that, length) | |
that.write(string, encoding) | |
return that | |
} | |
function fromObject (that, object) { | |
if (Buffer.isBuffer(object)) return fromBuffer(that, object) | |
if (isArray(object)) return fromArray(that, object) | |
if (object == null) { | |
throw new TypeError('must start with number, buffer, array or string') | |
} | |
if (typeof ArrayBuffer !== 'undefined') { | |
if (object.buffer instanceof ArrayBuffer) { | |
return fromTypedArray(that, object) | |
} | |
if (object instanceof ArrayBuffer) { | |
return fromArrayBuffer(that, object) | |
} | |
} | |
if (object.length) return fromArrayLike(that, object) | |
return fromJsonObject(that, object) | |
} | |
function fromBuffer (that, buffer) { | |
var length = checked(buffer.length) | 0 | |
that = allocate(that, length) | |
buffer.copy(that, 0, 0, length) | |
return that | |
} | |
function fromArray (that, array) { | |
var length = checked(array.length) | 0 | |
that = allocate(that, length) | |
for (var i = 0; i < length; i += 1) { | |
that[i] = array[i] & 255 | |
} | |
return that | |
} | |
// Duplicate of fromArray() to keep fromArray() monomorphic. | |
function fromTypedArray (that, array) { | |
var length = checked(array.length) | 0 | |
that = allocate(that, length) | |
// Truncating the elements is probably not what people expect from typed | |
// arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior | |
// of the old Buffer constructor. | |
for (var i = 0; i < length; i += 1) { | |
that[i] = array[i] & 255 | |
} | |
return that | |
} | |
function fromArrayBuffer (that, array) { | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
// Return an augmented `Uint8Array` instance, for best performance | |
array.byteLength | |
that = Buffer._augment(new Uint8Array(array)) | |
} else { | |
// Fallback: Return an object instance of the Buffer class | |
that = fromTypedArray(that, new Uint8Array(array)) | |
} | |
return that | |
} | |
function fromArrayLike (that, array) { | |
var length = checked(array.length) | 0 | |
that = allocate(that, length) | |
for (var i = 0; i < length; i += 1) { | |
that[i] = array[i] & 255 | |
} | |
return that | |
} | |
// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object. | |
// Returns a zero-length buffer for inputs that don't conform to the spec. | |
function fromJsonObject (that, object) { | |
var array | |
var length = 0 | |
if (object.type === 'Buffer' && isArray(object.data)) { | |
array = object.data | |
length = checked(array.length) | 0 | |
} | |
that = allocate(that, length) | |
for (var i = 0; i < length; i += 1) { | |
that[i] = array[i] & 255 | |
} | |
return that | |
} | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
Buffer.prototype.__proto__ = Uint8Array.prototype | |
Buffer.__proto__ = Uint8Array | |
} else { | |
// pre-set for values that may exist in the future | |
Buffer.prototype.length = undefined | |
Buffer.prototype.parent = undefined | |
} | |
function allocate (that, length) { | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
// Return an augmented `Uint8Array` instance, for best performance | |
that = Buffer._augment(new Uint8Array(length)) | |
that.__proto__ = Buffer.prototype | |
} else { | |
// Fallback: Return an object instance of the Buffer class | |
that.length = length | |
that._isBuffer = true | |
} | |
var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1 | |
if (fromPool) that.parent = rootParent | |
return that | |
} | |
function checked (length) { | |
// Note: cannot use `length < kMaxLength` here because that fails when | |
// length is NaN (which is otherwise coerced to zero.) | |
if (length >= kMaxLength()) { | |
throw new RangeError('Attempt to allocate Buffer larger than maximum ' + | |
'size: 0x' + kMaxLength().toString(16) + ' bytes') | |
} | |
return length | 0 | |
} | |
function SlowBuffer (subject, encoding) { | |
if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding) | |
var buf = new Buffer(subject, encoding) | |
delete buf.parent | |
return buf | |
} | |
Buffer.isBuffer = function isBuffer (b) { | |
return !!(b != null && b._isBuffer) | |
} | |
Buffer.compare = function compare (a, b) { | |
if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { | |
throw new TypeError('Arguments must be Buffers') | |
} | |
if (a === b) return 0 | |
var x = a.length | |
var y = b.length | |
var i = 0 | |
var len = Math.min(x, y) | |
while (i < len) { | |
if (a[i] !== b[i]) break | |
++i | |
} | |
if (i !== len) { | |
x = a[i] | |
y = b[i] | |
} | |
if (x < y) return -1 | |
if (y < x) return 1 | |
return 0 | |
} | |
Buffer.isEncoding = function isEncoding (encoding) { | |
switch (String(encoding).toLowerCase()) { | |
case 'hex': | |
case 'utf8': | |
case 'utf-8': | |
case 'ascii': | |
case 'binary': | |
case 'base64': | |
case 'raw': | |
case 'ucs2': | |
case 'ucs-2': | |
case 'utf16le': | |
case 'utf-16le': | |
return true | |
default: | |
return false | |
} | |
} | |
Buffer.concat = function concat (list, length) { | |
if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.') | |
if (list.length === 0) { | |
return new Buffer(0) | |
} | |
var i | |
if (length === undefined) { | |
length = 0 | |
for (i = 0; i < list.length; i++) { | |
length += list[i].length | |
} | |
} | |
var buf = new Buffer(length) | |
var pos = 0 | |
for (i = 0; i < list.length; i++) { | |
var item = list[i] | |
item.copy(buf, pos) | |
pos += item.length | |
} | |
return buf | |
} | |
function byteLength (string, encoding) { | |
if (typeof string !== 'string') string = '' + string | |
var len = string.length | |
if (len === 0) return 0 | |
// Use a for loop to avoid recursion | |
var loweredCase = false | |
for (;;) { | |
switch (encoding) { | |
case 'ascii': | |
case 'binary': | |
// Deprecated | |
case 'raw': | |
case 'raws': | |
return len | |
case 'utf8': | |
case 'utf-8': | |
return utf8ToBytes(string).length | |
case 'ucs2': | |
case 'ucs-2': | |
case 'utf16le': | |
case 'utf-16le': | |
return len * 2 | |
case 'hex': | |
return len >>> 1 | |
case 'base64': | |
return base64ToBytes(string).length | |
default: | |
if (loweredCase) return utf8ToBytes(string).length // assume utf8 | |
encoding = ('' + encoding).toLowerCase() | |
loweredCase = true | |
} | |
} | |
} | |
Buffer.byteLength = byteLength | |
function slowToString (encoding, start, end) { | |
var loweredCase = false | |
start = start | 0 | |
end = end === undefined || end === Infinity ? this.length : end | 0 | |
if (!encoding) encoding = 'utf8' | |
if (start < 0) start = 0 | |
if (end > this.length) end = this.length | |
if (end <= start) return '' | |
while (true) { | |
switch (encoding) { | |
case 'hex': | |
return hexSlice(this, start, end) | |
case 'utf8': | |
case 'utf-8': | |
return utf8Slice(this, start, end) | |
case 'ascii': | |
return asciiSlice(this, start, end) | |
case 'binary': | |
return binarySlice(this, start, end) | |
case 'base64': | |
return base64Slice(this, start, end) | |
case 'ucs2': | |
case 'ucs-2': | |
case 'utf16le': | |
case 'utf-16le': | |
return utf16leSlice(this, start, end) | |
default: | |
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) | |
encoding = (encoding + '').toLowerCase() | |
loweredCase = true | |
} | |
} | |
} | |
Buffer.prototype.toString = function toString () { | |
var length = this.length | 0 | |
if (length === 0) return '' | |
if (arguments.length === 0) return utf8Slice(this, 0, length) | |
return slowToString.apply(this, arguments) | |
} | |
Buffer.prototype.equals = function equals (b) { | |
if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') | |
if (this === b) return true | |
return Buffer.compare(this, b) === 0 | |
} | |
Buffer.prototype.inspect = function inspect () { | |
var str = '' | |
var max = exports.INSPECT_MAX_BYTES | |
if (this.length > 0) { | |
str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') | |
if (this.length > max) str += ' ... ' | |
} | |
return '<Buffer ' + str + '>' | |
} | |
Buffer.prototype.compare = function compare (b) { | |
if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') | |
if (this === b) return 0 | |
return Buffer.compare(this, b) | |
} | |
Buffer.prototype.indexOf = function indexOf (val, byteOffset) { | |
if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff | |
else if (byteOffset < -0x80000000) byteOffset = -0x80000000 | |
byteOffset >>= 0 | |
if (this.length === 0) return -1 | |
if (byteOffset >= this.length) return -1 | |
// Negative offsets start from the end of the buffer | |
if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0) | |
if (typeof val === 'string') { | |
if (val.length === 0) return -1 // special case: looking for empty string always fails | |
return String.prototype.indexOf.call(this, val, byteOffset) | |
} | |
if (Buffer.isBuffer(val)) { | |
return arrayIndexOf(this, val, byteOffset) | |
} | |
if (typeof val === 'number') { | |
if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') { | |
return Uint8Array.prototype.indexOf.call(this, val, byteOffset) | |
} | |
return arrayIndexOf(this, [ val ], byteOffset) | |
} | |
function arrayIndexOf (arr, val, byteOffset) { | |
var foundIndex = -1 | |
for (var i = 0; byteOffset + i < arr.length; i++) { | |
if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) { | |
if (foundIndex === -1) foundIndex = i | |
if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex | |
} else { | |
foundIndex = -1 | |
} | |
} | |
return -1 | |
} | |
throw new TypeError('val must be string, number or Buffer') | |
} | |
// `get` is deprecated | |
Buffer.prototype.get = function get (offset) { | |
console.log('.get() is deprecated. Access using array indexes instead.') | |
return this.readUInt8(offset) | |
} | |
// `set` is deprecated | |
Buffer.prototype.set = function set (v, offset) { | |
console.log('.set() is deprecated. Access using array indexes instead.') | |
return this.writeUInt8(v, offset) | |
} | |
function hexWrite (buf, string, offset, length) { | |
offset = Number(offset) || 0 | |
var remaining = buf.length - offset | |
if (!length) { | |
length = remaining | |
} else { | |
length = Number(length) | |
if (length > remaining) { | |
length = remaining | |
} | |
} | |
// must be an even number of digits | |
var strLen = string.length | |
if (strLen % 2 !== 0) throw new Error('Invalid hex string') | |
if (length > strLen / 2) { | |
length = strLen / 2 | |
} | |
for (var i = 0; i < length; i++) { | |
var parsed = parseInt(string.substr(i * 2, 2), 16) | |
if (isNaN(parsed)) throw new Error('Invalid hex string') | |
buf[offset + i] = parsed | |
} | |
return i | |
} | |
function utf8Write (buf, string, offset, length) { | |
return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) | |
} | |
function asciiWrite (buf, string, offset, length) { | |
return blitBuffer(asciiToBytes(string), buf, offset, length) | |
} | |
function binaryWrite (buf, string, offset, length) { | |
return asciiWrite(buf, string, offset, length) | |
} | |
function base64Write (buf, string, offset, length) { | |
return blitBuffer(base64ToBytes(string), buf, offset, length) | |
} | |
function ucs2Write (buf, string, offset, length) { | |
return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) | |
} | |
Buffer.prototype.write = function write (string, offset, length, encoding) { | |
// Buffer#write(string) | |
if (offset === undefined) { | |
encoding = 'utf8' | |
length = this.length | |
offset = 0 | |
// Buffer#write(string, encoding) | |
} else if (length === undefined && typeof offset === 'string') { | |
encoding = offset | |
length = this.length | |
offset = 0 | |
// Buffer#write(string, offset[, length][, encoding]) | |
} else if (isFinite(offset)) { | |
offset = offset | 0 | |
if (isFinite(length)) { | |
length = length | 0 | |
if (encoding === undefined) encoding = 'utf8' | |
} else { | |
encoding = length | |
length = undefined | |
} | |
// legacy write(string, encoding, offset, length) - remove in v0.13 | |
} else { | |
var swap = encoding | |
encoding = offset | |
offset = length | 0 | |
length = swap | |
} | |
var remaining = this.length - offset | |
if (length === undefined || length > remaining) length = remaining | |
if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { | |
throw new RangeError('attempt to write outside buffer bounds') | |
} | |
if (!encoding) encoding = 'utf8' | |
var loweredCase = false | |
for (;;) { | |
switch (encoding) { | |
case 'hex': | |
return hexWrite(this, string, offset, length) | |
case 'utf8': | |
case 'utf-8': | |
return utf8Write(this, string, offset, length) | |
case 'ascii': | |
return asciiWrite(this, string, offset, length) | |
case 'binary': | |
return binaryWrite(this, string, offset, length) | |
case 'base64': | |
// Warning: maxLength not taken into account in base64Write | |
return base64Write(this, string, offset, length) | |
case 'ucs2': | |
case 'ucs-2': | |
case 'utf16le': | |
case 'utf-16le': | |
return ucs2Write(this, string, offset, length) | |
default: | |
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) | |
encoding = ('' + encoding).toLowerCase() | |
loweredCase = true | |
} | |
} | |
} | |
Buffer.prototype.toJSON = function toJSON () { | |
return { | |
type: 'Buffer', | |
data: Array.prototype.slice.call(this._arr || this, 0) | |
} | |
} | |
function base64Slice (buf, start, end) { | |
if (start === 0 && end === buf.length) { | |
return base64.fromByteArray(buf) | |
} else { | |
return base64.fromByteArray(buf.slice(start, end)) | |
} | |
} | |
function utf8Slice (buf, start, end) { | |
end = Math.min(buf.length, end) | |
var res = [] | |
var i = start | |
while (i < end) { | |
var firstByte = buf[i] | |
var codePoint = null | |
var bytesPerSequence = (firstByte > 0xEF) ? 4 | |
: (firstByte > 0xDF) ? 3 | |
: (firstByte > 0xBF) ? 2 | |
: 1 | |
if (i + bytesPerSequence <= end) { | |
var secondByte, thirdByte, fourthByte, tempCodePoint | |
switch (bytesPerSequence) { | |
case 1: | |
if (firstByte < 0x80) { | |
codePoint = firstByte | |
} | |
break | |
case 2: | |
secondByte = buf[i + 1] | |
if ((secondByte & 0xC0) === 0x80) { | |
tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) | |
if (tempCodePoint > 0x7F) { | |
codePoint = tempCodePoint | |
} | |
} | |
break | |
case 3: | |
secondByte = buf[i + 1] | |
thirdByte = buf[i + 2] | |
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { | |
tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) | |
if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { | |
codePoint = tempCodePoint | |
} | |
} | |
break | |
case 4: | |
secondByte = buf[i + 1] | |
thirdByte = buf[i + 2] | |
fourthByte = buf[i + 3] | |
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { | |
tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) | |
if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { | |
codePoint = tempCodePoint | |
} | |
} | |
} | |
} | |
if (codePoint === null) { | |
// we did not generate a valid codePoint so insert a | |
// replacement char (U+FFFD) and advance only 1 byte | |
codePoint = 0xFFFD | |
bytesPerSequence = 1 | |
} else if (codePoint > 0xFFFF) { | |
// encode to utf16 (surrogate pair dance) | |
codePoint -= 0x10000 | |
res.push(codePoint >>> 10 & 0x3FF | 0xD800) | |
codePoint = 0xDC00 | codePoint & 0x3FF | |
} | |
res.push(codePoint) | |
i += bytesPerSequence | |
} | |
return decodeCodePointsArray(res) | |
} | |
// Based on http://stackoverflow.com/a/22747272/680742, the browser with | |
// the lowest limit is Chrome, with 0x10000 args. | |
// We go 1 magnitude less, for safety | |
var MAX_ARGUMENTS_LENGTH = 0x1000 | |
function decodeCodePointsArray (codePoints) { | |
var len = codePoints.length | |
if (len <= MAX_ARGUMENTS_LENGTH) { | |
return String.fromCharCode.apply(String, codePoints) // avoid extra slice() | |
} | |
// Decode in chunks to avoid "call stack size exceeded". | |
var res = '' | |
var i = 0 | |
while (i < len) { | |
res += String.fromCharCode.apply( | |
String, | |
codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) | |
) | |
} | |
return res | |
} | |
function asciiSlice (buf, start, end) { | |
var ret = '' | |
end = Math.min(buf.length, end) | |
for (var i = start; i < end; i++) { | |
ret += String.fromCharCode(buf[i] & 0x7F) | |
} | |
return ret | |
} | |
function binarySlice (buf, start, end) { | |
var ret = '' | |
end = Math.min(buf.length, end) | |
for (var i = start; i < end; i++) { | |
ret += String.fromCharCode(buf[i]) | |
} | |
return ret | |
} | |
function hexSlice (buf, start, end) { | |
var len = buf.length | |
if (!start || start < 0) start = 0 | |
if (!end || end < 0 || end > len) end = len | |
var out = '' | |
for (var i = start; i < end; i++) { | |
out += toHex(buf[i]) | |
} | |
return out | |
} | |
function utf16leSlice (buf, start, end) { | |
var bytes = buf.slice(start, end) | |
var res = '' | |
for (var i = 0; i < bytes.length; i += 2) { | |
res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) | |
} | |
return res | |
} | |
Buffer.prototype.slice = function slice (start, end) { | |
var len = this.length | |
start = ~~start | |
end = end === undefined ? len : ~~end | |
if (start < 0) { | |
start += len | |
if (start < 0) start = 0 | |
} else if (start > len) { | |
start = len | |
} | |
if (end < 0) { | |
end += len | |
if (end < 0) end = 0 | |
} else if (end > len) { | |
end = len | |
} | |
if (end < start) end = start | |
var newBuf | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
newBuf = Buffer._augment(this.subarray(start, end)) | |
} else { | |
var sliceLen = end - start | |
newBuf = new Buffer(sliceLen, undefined) | |
for (var i = 0; i < sliceLen; i++) { | |
newBuf[i] = this[i + start] | |
} | |
} | |
if (newBuf.length) newBuf.parent = this.parent || this | |
return newBuf | |
} | |
/* | |
* Need to make sure that buffer isn't trying to write out of bounds. | |
*/ | |
function checkOffset (offset, ext, length) { | |
if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') | |
if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') | |
} | |
Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) checkOffset(offset, byteLength, this.length) | |
var val = this[offset] | |
var mul = 1 | |
var i = 0 | |
while (++i < byteLength && (mul *= 0x100)) { | |
val += this[offset + i] * mul | |
} | |
return val | |
} | |
Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) { | |
checkOffset(offset, byteLength, this.length) | |
} | |
var val = this[offset + --byteLength] | |
var mul = 1 | |
while (byteLength > 0 && (mul *= 0x100)) { | |
val += this[offset + --byteLength] * mul | |
} | |
return val | |
} | |
Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 1, this.length) | |
return this[offset] | |
} | |
Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 2, this.length) | |
return this[offset] | (this[offset + 1] << 8) | |
} | |
Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 2, this.length) | |
return (this[offset] << 8) | this[offset + 1] | |
} | |
Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return ((this[offset]) | | |
(this[offset + 1] << 8) | | |
(this[offset + 2] << 16)) + | |
(this[offset + 3] * 0x1000000) | |
} | |
Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return (this[offset] * 0x1000000) + | |
((this[offset + 1] << 16) | | |
(this[offset + 2] << 8) | | |
this[offset + 3]) | |
} | |
Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) checkOffset(offset, byteLength, this.length) | |
var val = this[offset] | |
var mul = 1 | |
var i = 0 | |
while (++i < byteLength && (mul *= 0x100)) { | |
val += this[offset + i] * mul | |
} | |
mul *= 0x80 | |
if (val >= mul) val -= Math.pow(2, 8 * byteLength) | |
return val | |
} | |
Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) checkOffset(offset, byteLength, this.length) | |
var i = byteLength | |
var mul = 1 | |
var val = this[offset + --i] | |
while (i > 0 && (mul *= 0x100)) { | |
val += this[offset + --i] * mul | |
} | |
mul *= 0x80 | |
if (val >= mul) val -= Math.pow(2, 8 * byteLength) | |
return val | |
} | |
Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 1, this.length) | |
if (!(this[offset] & 0x80)) return (this[offset]) | |
return ((0xff - this[offset] + 1) * -1) | |
} | |
Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 2, this.length) | |
var val = this[offset] | (this[offset + 1] << 8) | |
return (val & 0x8000) ? val | 0xFFFF0000 : val | |
} | |
Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 2, this.length) | |
var val = this[offset + 1] | (this[offset] << 8) | |
return (val & 0x8000) ? val | 0xFFFF0000 : val | |
} | |
Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return (this[offset]) | | |
(this[offset + 1] << 8) | | |
(this[offset + 2] << 16) | | |
(this[offset + 3] << 24) | |
} | |
Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return (this[offset] << 24) | | |
(this[offset + 1] << 16) | | |
(this[offset + 2] << 8) | | |
(this[offset + 3]) | |
} | |
Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return ieee754.read(this, offset, true, 23, 4) | |
} | |
Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return ieee754.read(this, offset, false, 23, 4) | |
} | |
Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 8, this.length) | |
return ieee754.read(this, offset, true, 52, 8) | |
} | |
Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 8, this.length) | |
return ieee754.read(this, offset, false, 52, 8) | |
} | |
function checkInt (buf, value, offset, ext, max, min) { | |
if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance') | |
if (value > max || value < min) throw new RangeError('value is out of bounds') | |
if (offset + ext > buf.length) throw new RangeError('index out of range') | |
} | |
Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { | |
value = +value | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) | |
var mul = 1 | |
var i = 0 | |
this[offset] = value & 0xFF | |
while (++i < byteLength && (mul *= 0x100)) { | |
this[offset + i] = (value / mul) & 0xFF | |
} | |
return offset + byteLength | |
} | |
Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { | |
value = +value | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) | |
var i = byteLength - 1 | |
var mul = 1 | |
this[offset + i] = value & 0xFF | |
while (--i >= 0 && (mul *= 0x100)) { | |
this[offset + i] = (value / mul) & 0xFF | |
} | |
return offset + byteLength | |
} | |
Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) | |
if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) | |
this[offset] = (value & 0xff) | |
return offset + 1 | |
} | |
function objectWriteUInt16 (buf, value, offset, littleEndian) { | |
if (value < 0) value = 0xffff + value + 1 | |
for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) { | |
buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> | |
(littleEndian ? i : 1 - i) * 8 | |
} | |
} | |
Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value & 0xff) | |
this[offset + 1] = (value >>> 8) | |
} else { | |
objectWriteUInt16(this, value, offset, true) | |
} | |
return offset + 2 | |
} | |
Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value >>> 8) | |
this[offset + 1] = (value & 0xff) | |
} else { | |
objectWriteUInt16(this, value, offset, false) | |
} | |
return offset + 2 | |
} | |
function objectWriteUInt32 (buf, value, offset, littleEndian) { | |
if (value < 0) value = 0xffffffff + value + 1 | |
for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) { | |
buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff | |
} | |
} | |
Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset + 3] = (value >>> 24) | |
this[offset + 2] = (value >>> 16) | |
this[offset + 1] = (value >>> 8) | |
this[offset] = (value & 0xff) | |
} else { | |
objectWriteUInt32(this, value, offset, true) | |
} | |
return offset + 4 | |
} | |
Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value >>> 24) | |
this[offset + 1] = (value >>> 16) | |
this[offset + 2] = (value >>> 8) | |
this[offset + 3] = (value & 0xff) | |
} else { | |
objectWriteUInt32(this, value, offset, false) | |
} | |
return offset + 4 | |
} | |
Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) { | |
var limit = Math.pow(2, 8 * byteLength - 1) | |
checkInt(this, value, offset, byteLength, limit - 1, -limit) | |
} | |
var i = 0 | |
var mul = 1 | |
var sub = value < 0 ? 1 : 0 | |
this[offset] = value & 0xFF | |
while (++i < byteLength && (mul *= 0x100)) { | |
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF | |
} | |
return offset + byteLength | |
} | |
Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) { | |
var limit = Math.pow(2, 8 * byteLength - 1) | |
checkInt(this, value, offset, byteLength, limit - 1, -limit) | |
} | |
var i = byteLength - 1 | |
var mul = 1 | |
var sub = value < 0 ? 1 : 0 | |
this[offset + i] = value & 0xFF | |
while (--i >= 0 && (mul *= 0x100)) { | |
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF | |
} | |
return offset + byteLength | |
} | |
Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) | |
if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) | |
if (value < 0) value = 0xff + value + 1 | |
this[offset] = (value & 0xff) | |
return offset + 1 | |
} | |
Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value & 0xff) | |
this[offset + 1] = (value >>> 8) | |
} else { | |
objectWriteUInt16(this, value, offset, true) | |
} | |
return offset + 2 | |
} | |
Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value >>> 8) | |
this[offset + 1] = (value & 0xff) | |
} else { | |
objectWriteUInt16(this, value, offset, false) | |
} | |
return offset + 2 | |
} | |
Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value & 0xff) | |
this[offset + 1] = (value >>> 8) | |
this[offset + 2] = (value >>> 16) | |
this[offset + 3] = (value >>> 24) | |
} else { | |
objectWriteUInt32(this, value, offset, true) | |
} | |
return offset + 4 | |
} | |
Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) | |
if (value < 0) value = 0xffffffff + value + 1 | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value >>> 24) | |
this[offset + 1] = (value >>> 16) | |
this[offset + 2] = (value >>> 8) | |
this[offset + 3] = (value & 0xff) | |
} else { | |
objectWriteUInt32(this, value, offset, false) | |
} | |
return offset + 4 | |
} | |
function checkIEEE754 (buf, value, offset, ext, max, min) { | |
if (value > max || value < min) throw new RangeError('value is out of bounds') | |
if (offset + ext > buf.length) throw new RangeError('index out of range') | |
if (offset < 0) throw new RangeError('index out of range') | |
} | |
function writeFloat (buf, value, offset, littleEndian, noAssert) { | |
if (!noAssert) { | |
checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) | |
} | |
ieee754.write(buf, value, offset, littleEndian, 23, 4) | |
return offset + 4 | |
} | |
Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { | |
return writeFloat(this, value, offset, true, noAssert) | |
} | |
Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { | |
return writeFloat(this, value, offset, false, noAssert) | |
} | |
function writeDouble (buf, value, offset, littleEndian, noAssert) { | |
if (!noAssert) { | |
checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) | |
} | |
ieee754.write(buf, value, offset, littleEndian, 52, 8) | |
return offset + 8 | |
} | |
Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { | |
return writeDouble(this, value, offset, true, noAssert) | |
} | |
Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { | |
return writeDouble(this, value, offset, false, noAssert) | |
} | |
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) | |
Buffer.prototype.copy = function copy (target, targetStart, start, end) { | |
if (!start) start = 0 | |
if (!end && end !== 0) end = this.length | |
if (targetStart >= target.length) targetStart = target.length | |
if (!targetStart) targetStart = 0 | |
if (end > 0 && end < start) end = start | |
// Copy 0 bytes; we're done | |
if (end === start) return 0 | |
if (target.length === 0 || this.length === 0) return 0 | |
// Fatal error conditions | |
if (targetStart < 0) { | |
throw new RangeError('targetStart out of bounds') | |
} | |
if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') | |
if (end < 0) throw new RangeError('sourceEnd out of bounds') | |
// Are we oob? | |
if (end > this.length) end = this.length | |
if (target.length - targetStart < end - start) { | |
end = target.length - targetStart + start | |
} | |
var len = end - start | |
var i | |
if (this === target && start < targetStart && targetStart < end) { | |
// descending copy from end | |
for (i = len - 1; i >= 0; i--) { | |
target[i + targetStart] = this[i + start] | |
} | |
} else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { | |
// ascending copy from start | |
for (i = 0; i < len; i++) { | |
target[i + targetStart] = this[i + start] | |
} | |
} else { | |
target._set(this.subarray(start, start + len), targetStart) | |
} | |
return len | |
} | |
// fill(value, start=0, end=buffer.length) | |
Buffer.prototype.fill = function fill (value, start, end) { | |
if (!value) value = 0 | |
if (!start) start = 0 | |
if (!end) end = this.length | |
if (end < start) throw new RangeError('end < start') | |
// Fill 0 bytes; we're done | |
if (end === start) return | |
if (this.length === 0) return | |
if (start < 0 || start >= this.length) throw new RangeError('start out of bounds') | |
if (end < 0 || end > this.length) throw new RangeError('end out of bounds') | |
var i | |
if (typeof value === 'number') { | |
for (i = start; i < end; i++) { | |
this[i] = value | |
} | |
} else { | |
var bytes = utf8ToBytes(value.toString()) | |
var len = bytes.length | |
for (i = start; i < end; i++) { | |
this[i] = bytes[i % len] | |
} | |
} | |
return this | |
} | |
/** | |
* Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance. | |
* Added in Node 0.12. Only available in browsers that support ArrayBuffer. | |
*/ | |
Buffer.prototype.toArrayBuffer = function toArrayBuffer () { | |
if (typeof Uint8Array !== 'undefined') { | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
return (new Buffer(this)).buffer | |
} else { | |
var buf = new Uint8Array(this.length) | |
for (var i = 0, len = buf.length; i < len; i += 1) { | |
buf[i] = this[i] | |
} | |
return buf.buffer | |
} | |
} else { | |
throw new TypeError('Buffer.toArrayBuffer not supported in this browser') | |
} | |
} | |
// HELPER FUNCTIONS | |
// ================ | |
var BP = Buffer.prototype | |
/** | |
* Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods | |
*/ | |
Buffer._augment = function _augment (arr) { | |
arr.constructor = Buffer | |
arr._isBuffer = true | |
// save reference to original Uint8Array set method before overwriting | |
arr._set = arr.set | |
// deprecated | |
arr.get = BP.get | |
arr.set = BP.set | |
arr.write = BP.write | |
arr.toString = BP.toString | |
arr.toLocaleString = BP.toString | |
arr.toJSON = BP.toJSON | |
arr.equals = BP.equals | |
arr.compare = BP.compare | |
arr.indexOf = BP.indexOf | |
arr.copy = BP.copy | |
arr.slice = BP.slice | |
arr.readUIntLE = BP.readUIntLE | |
arr.readUIntBE = BP.readUIntBE | |
arr.readUInt8 = BP.readUInt8 | |
arr.readUInt16LE = BP.readUInt16LE | |
arr.readUInt16BE = BP.readUInt16BE | |
arr.readUInt32LE = BP.readUInt32LE | |
arr.readUInt32BE = BP.readUInt32BE | |
arr.readIntLE = BP.readIntLE | |
arr.readIntBE = BP.readIntBE | |
arr.readInt8 = BP.readInt8 | |
arr.readInt16LE = BP.readInt16LE | |
arr.readInt16BE = BP.readInt16BE | |
arr.readInt32LE = BP.readInt32LE | |
arr.readInt32BE = BP.readInt32BE | |
arr.readFloatLE = BP.readFloatLE | |
arr.readFloatBE = BP.readFloatBE | |
arr.readDoubleLE = BP.readDoubleLE | |
arr.readDoubleBE = BP.readDoubleBE | |
arr.writeUInt8 = BP.writeUInt8 | |
arr.writeUIntLE = BP.writeUIntLE | |
arr.writeUIntBE = BP.writeUIntBE | |
arr.writeUInt16LE = BP.writeUInt16LE | |
arr.writeUInt16BE = BP.writeUInt16BE | |
arr.writeUInt32LE = BP.writeUInt32LE | |
arr.writeUInt32BE = BP.writeUInt32BE | |
arr.writeIntLE = BP.writeIntLE | |
arr.writeIntBE = BP.writeIntBE | |
arr.writeInt8 = BP.writeInt8 | |
arr.writeInt16LE = BP.writeInt16LE | |
arr.writeInt16BE = BP.writeInt16BE | |
arr.writeInt32LE = BP.writeInt32LE | |
arr.writeInt32BE = BP.writeInt32BE | |
arr.writeFloatLE = BP.writeFloatLE | |
arr.writeFloatBE = BP.writeFloatBE | |
arr.writeDoubleLE = BP.writeDoubleLE | |
arr.writeDoubleBE = BP.writeDoubleBE | |
arr.fill = BP.fill | |
arr.inspect = BP.inspect | |
arr.toArrayBuffer = BP.toArrayBuffer | |
return arr | |
} | |
var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g | |
function base64clean (str) { | |
// Node strips out invalid characters like \n and \t from the string, base64-js does not | |
str = stringtrim(str).replace(INVALID_BASE64_RE, '') | |
// Node converts strings with length < 2 to '' | |
if (str.length < 2) return '' | |
// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not | |
while (str.length % 4 !== 0) { | |
str = str + '=' | |
} | |
return str | |
} | |
function stringtrim (str) { | |
if (str.trim) return str.trim() | |
return str.replace(/^\s+|\s+$/g, '') | |
} | |
function toHex (n) { | |
if (n < 16) return '0' + n.toString(16) | |
return n.toString(16) | |
} | |
function utf8ToBytes (string, units) { | |
units = units || Infinity | |
var codePoint | |
var length = string.length | |
var leadSurrogate = null | |
var bytes = [] | |
for (var i = 0; i < length; i++) { | |
codePoint = string.charCodeAt(i) | |
// is surrogate component | |
if (codePoint > 0xD7FF && codePoint < 0xE000) { | |
// last char was a lead | |
if (!leadSurrogate) { | |
// no lead yet | |
if (codePoint > 0xDBFF) { | |
// unexpected trail | |
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) | |
continue | |
} else if (i + 1 === length) { | |
// unpaired lead | |
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) | |
continue | |
} | |
// valid lead | |
leadSurrogate = codePoint | |
continue | |
} | |
// 2 leads in a row | |
if (codePoint < 0xDC00) { | |
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) | |
leadSurrogate = codePoint | |
continue | |
} | |
// valid surrogate pair | |
codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 | |
} else if (leadSurrogate) { | |
// valid bmp char, but last char was a lead | |
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) | |
} | |
leadSurrogate = null | |
// encode utf8 | |
if (codePoint < 0x80) { | |
if ((units -= 1) < 0) break | |
bytes.push(codePoint) | |
} else if (codePoint < 0x800) { | |
if ((units -= 2) < 0) break | |
bytes.push( | |
codePoint >> 0x6 | 0xC0, | |
codePoint & 0x3F | 0x80 | |
) | |
} else if (codePoint < 0x10000) { | |
if ((units -= 3) < 0) break | |
bytes.push( | |
codePoint >> 0xC | 0xE0, | |
codePoint >> 0x6 & 0x3F | 0x80, | |
codePoint & 0x3F | 0x80 | |
) | |
} else if (codePoint < 0x110000) { | |
if ((units -= 4) < 0) break | |
bytes.push( | |
codePoint >> 0x12 | 0xF0, | |
codePoint >> 0xC & 0x3F | 0x80, | |
codePoint >> 0x6 & 0x3F | 0x80, | |
codePoint & 0x3F | 0x80 | |
) | |
} else { | |
throw new Error('Invalid code point') | |
} | |
} | |
return bytes | |
} | |
function asciiToBytes (str) { | |
var byteArray = [] | |
for (var i = 0; i < str.length; i++) { | |
// Node's code seems to be doing this and not & 0x7F.. | |
byteArray.push(str.charCodeAt(i) & 0xFF) | |
} | |
return byteArray | |
} | |
function utf16leToBytes (str, units) { | |
var c, hi, lo | |
var byteArray = [] | |
for (var i = 0; i < str.length; i++) { | |
if ((units -= 2) < 0) break | |
c = str.charCodeAt(i) | |
hi = c >> 8 | |
lo = c % 256 | |
byteArray.push(lo) | |
byteArray.push(hi) | |
} | |
return byteArray | |
} | |
function base64ToBytes (str) { | |
return base64.toByteArray(base64clean(str)) | |
} | |
function blitBuffer (src, dst, offset, length) { | |
for (var i = 0; i < length; i++) { | |
if ((i + offset >= dst.length) || (i >= src.length)) break | |
dst[i + offset] = src[i] | |
} | |
return i | |
} | |
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9pbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIi8qIVxuICogVGhlIGJ1ZmZlciBtb2R1bGUgZnJvbSBub2RlLmpzLCBmb3IgdGhlIGJyb3dzZXIuXG4gKlxuICogQGF1dGhvciAgIEZlcm9zcyBBYm91a2hhZGlqZWggPGZlcm9zc0BmZXJvc3Mub3JnPiA8aHR0cDovL2Zlcm9zcy5vcmc+XG4gKiBAbGljZW5zZSAgTUlUXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLXByb3RvICovXG5cbid1c2Ugc3RyaWN0J1xuXG52YXIgYmFzZTY0ID0gcmVxdWlyZSgnYmFzZTY0LWpzJylcbnZhciBpZWVlNzU0ID0gcmVxdWlyZSgnaWVlZTc1NCcpXG52YXIgaXNBcnJheSA9IHJlcXVpcmUoJ2lzYXJyYXknKVxuXG5leHBvcnRzLkJ1ZmZlciA9IEJ1ZmZlclxuZXhwb3J0cy5TbG93QnVmZmVyID0gU2xvd0J1ZmZlclxuZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFUyA9IDUwXG5CdWZmZXIucG9vbFNpemUgPSA4MTkyIC8vIG5vdCB1c2VkIGJ5IHRoaXMgaW1wbGVtZW50YXRpb25cblxudmFyIHJvb3RQYXJlbnQgPSB7fVxuXG4vKipcbiAqIElmIGBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVGA6XG4gKiAgID09PSB0cnVlICAgIFVzZSBVaW50OEFycmF5IGltcGxlbWVudGF0aW9uIChmYXN0ZXN0KVxuICogICA9PT0gZmFsc2UgICBVc2UgT2JqZWN0IGltcGxlbWVudGF0aW9uIChtb3N0IGNvbXBhdGlibGUsIGV2ZW4gSUU2KVxuICpcbiAqIEJyb3dzZXJzIHRoYXQgc3VwcG9ydCB0eXBlZCBhcnJheXMgYXJlIElFIDEwKywgRmlyZWZveCA0KywgQ2hyb21lIDcrLCBTYWZhcmkgNS4xKyxcbiAqIE9wZXJhIDExLjYrLCBpT1MgNC4yKy5cbiAqXG4gKiBEdWUgdG8gdmFyaW91cyBicm93c2VyIGJ1Z3MsIHNvbWV0aW1lcyB0aGUgT2JqZWN0IGltcGxlbWVudGF0aW9uIHdpbGwgYmUgdXNlZCBldmVuXG4gKiB3aGVuIHRoZSBicm93c2VyIHN1cHBvcnRzIHR5cGVkIGFycmF5cy5cbiAqXG4gKiBOb3RlOlxuICpcbiAqICAgLSBGaXJlZm94IDQtMjkgbGFja3Mgc3VwcG9ydCBmb3IgYWRkaW5nIG5ldyBwcm9wZXJ0aWVzIHRvIGBVaW50OEFycmF5YCBpbnN0YW5jZXMsXG4gKiAgICAgU2VlOiBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD02OTU0MzguXG4gKlxuICogICAtIFNhZmFyaSA1LTcgbGFja3Mgc3VwcG9ydCBmb3IgY2hhbmdpbmcgdGhlIGBPYmplY3QucHJvdG90eXBlLmNvbnN0cnVjdG9yYCBwcm9wZXJ0eVxuICogICAgIG9uIG9iamVjdHMuXG4gKlxuICogICAtIENocm9tZSA5LTEwIGlzIG1pc3NpbmcgdGhlIGBUeXBlZEFycmF5LnByb3RvdHlwZS5zdWJhcnJheWAgZnVuY3Rpb24uXG4gKlxuICogICAtIElFMTAgaGFzIGEgYnJva2VuIGBUeXBlZEFycmF5LnByb3RvdHlwZS5zdWJhcnJheWAgZnVuY3Rpb24gd2hpY2ggcmV0dXJucyBhcnJheXMgb2ZcbiAqICAgICBpbmNvcnJlY3QgbGVuZ3RoIGluIHNvbWUgc2l0dWF0aW9ucy5cblxuICogV2UgZGV0ZWN0IHRoZXNlIGJ1Z2d5IGJyb3dzZXJzIGFuZCBzZXQgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYCB0byBgZmFsc2VgIHNvIHRoZXlcbiAqIGdldCB0aGUgT2JqZWN0IGltcGxlbWVudGF0aW9uLCB3aGljaCBpcyBzbG93ZXIgYnV0IGJlaGF2ZXMgY29ycmVjdGx5LlxuICovXG5CdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCA9IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUICE9PSB1bmRlZmluZWRcbiAgPyBnbG9iYWwuVFlQRURfQVJSQVlfU1VQUE9SVFxuICA6IHR5cGVkQXJyYXlTdXBwb3J0KClcblxuZnVuY3Rpb24gdHlwZWRBcnJheVN1cHBvcnQgKCkge1xuICBmdW5jdGlvbiBCYXIgKCkge31cbiAgdHJ5IHtcbiAgICB2YXIgYXJyID0gbmV3IFVpbnQ4QXJyYXkoMSlcbiAgICBhcnIuZm9vID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gNDIgfVxuICAgIGFyci5jb25zdHJ1Y3RvciA9IEJhclxuICAgIHJldHVybiBhcnIuZm9vKCkgPT09IDQyICYmIC8vIHR5cGVkIGFycmF5IGluc3RhbmNlcyBjYW4gYmUgYXVnbWVudGVkXG4gICAgICAgIGFyci5jb25zdHJ1Y3RvciA9PT0gQmFyICYmIC8vIGNvbnN0cnVjdG9yIGNhbiBiZSBzZXRcbiAgICAgICAgdHlwZW9mIGFyci5zdWJhcnJheSA9PT0gJ2Z1bmN0aW9uJyAmJiAvLyBjaHJvbWUgOS0xMCBsYWNrIGBzdWJhcnJheWBcbiAgICAgICAgYXJyLnN1YmFycmF5KDEsIDEpLmJ5dGVMZW5ndGggPT09IDAgLy8gaWUxMCBoYXMgYnJva2VuIGBzdWJhcnJheWBcbiAgfSBjYXRjaCAoZSkge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbmZ1bmN0aW9uIGtNYXhMZW5ndGggKCkge1xuICByZXR1cm4gQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRcbiAgICA/IDB4N2ZmZmZmZmZcbiAgICA6IDB4M2ZmZmZmZmZcbn1cblxuLyoqXG4gKiBDbGFzczogQnVmZmVyXG4gKiA9PT09PT09PT09PT09XG4gKlxuICogVGhlIEJ1ZmZlciBjb25zdHJ1Y3RvciByZXR1cm5zIGluc3RhbmNlcyBvZiBgVWludDhBcnJheWAgdGhhdCBhcmUgYXVnbWVudGVkXG4gKiB3aXRoIGZ1bmN0aW9uIHByb3BlcnRpZXMgZm9yIGFsbCB0aGUgbm9kZSBgQnVmZmVyYCBBUEkgZnVuY3Rpb25zLiBXZSB1c2VcbiAqIGBVaW50OEFycmF5YCBzbyB0aGF0IHNxdWFyZSBicmFja2V0IG5vdGF0aW9uIHdvcmtzIGFzIGV4cGVjdGVkIC0tIGl0IHJldHVybnNcbiAqIGEgc2luZ2xlIG9jdGV0LlxuICpcbiAqIEJ5IGF1Z21lbnRpbmcgdGhlIGluc3RhbmNlcywgd2UgY2FuIGF2b2lkIG1vZGlmeWluZyB0aGUgYFVpbnQ4QXJyYXlgXG4gKiBwcm90b3R5cGUuXG4gKi9cbmZ1bmN0aW9uIEJ1ZmZlciAoYXJnKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBCdWZmZXIpKSB7XG4gICAgLy8gQXZvaWQgZ29pbmcgdGhyb3VnaCBhbiBBcmd1bWVudHNBZGFwdG9yVHJhbXBvbGluZSBpbiB0aGUgY29tbW9uIGNhc2UuXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSByZXR1cm4gbmV3IEJ1ZmZlcihhcmcsIGFyZ3VtZW50c1sxXSlcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcihhcmcpXG4gIH1cblxuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpcy5sZW5ndGggPSAwXG4gICAgdGhpcy5wYXJlbnQgPSB1bmRlZmluZWRcbiAgfVxuXG4gIC8vIENvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ251bWJlcicpIHtcbiAgICByZXR1cm4gZnJvbU51bWJlcih0aGlzLCBhcmcpXG4gIH1cblxuICAvLyBTbGlnaHRseSBsZXNzIGNvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gZnJvbVN0cmluZyh0aGlzLCBhcmcsIGFyZ3VtZW50cy5sZW5ndGggPiAxID8gYXJndW1lbnRzWzFdIDogJ3V0ZjgnKVxuICB9XG5cbiAgLy8gVW51c3VhbC5cbiAgcmV0dXJuIGZyb21PYmplY3QodGhpcywgYXJnKVxufVxuXG5mdW5jdGlvbiBmcm9tTnVtYmVyICh0aGF0LCBsZW5ndGgpIHtcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aCA8IDAgPyAwIDogY2hlY2tlZChsZW5ndGgpIHwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHRoYXRbaV0gPSAwXG4gICAgfVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21TdHJpbmcgKHRoYXQsIHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBlbmNvZGluZyAhPT0gJ3N0cmluZycgfHwgZW5jb2RpbmcgPT09ICcnKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIC8vIEFzc3VtcHRpb246IGJ5dGVMZW5ndGgoKSByZXR1cm4gdmFsdWUgaXMgYWx3YXlzIDwga01heExlbmd0aC5cbiAgdmFyIGxlbmd0aCA9IGJ5dGVMZW5ndGgoc3RyaW5nLCBlbmNvZGluZykgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgdGhhdC53cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihvYmplY3QpKSByZXR1cm4gZnJvbUJ1ZmZlcih0aGF0LCBvYmplY3QpXG5cbiAgaWYgKGlzQXJyYXkob2JqZWN0KSkgcmV0dXJuIGZyb21BcnJheSh0aGF0LCBvYmplY3QpXG5cbiAgaWYgKG9iamVjdCA9PSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignbXVzdCBzdGFydCB3aXRoIG51bWJlciwgYnVmZmVyLCBhcnJheSBvciBzdHJpbmcnKVxuICB9XG5cbiAgaWYgKHR5cGVvZiBBcnJheUJ1ZmZlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAob2JqZWN0LmJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbVR5cGVkQXJyYXkodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgICBpZiAob2JqZWN0IGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICAgIHJldHVybiBmcm9tQXJyYXlCdWZmZXIodGhhdCwgb2JqZWN0KVxuICAgIH1cbiAgfVxuXG4gIGlmIChvYmplY3QubGVuZ3RoKSByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmplY3QpXG5cbiAgcmV0dXJuIGZyb21Kc29uT2JqZWN0KHRoYXQsIG9iamVjdClcbn1cblxuZnVuY3Rpb24gZnJvbUJ1ZmZlciAodGhhdCwgYnVmZmVyKSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGJ1ZmZlci5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBidWZmZXIuY29weSh0aGF0LCAwLCAwLCBsZW5ndGgpXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheSAodGhhdCwgYXJyYXkpIHtcbiAgdmFyIGxlbmd0aCA9IGNoZWNrZWQoYXJyYXkubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbi8vIER1cGxpY2F0ZSBvZiBmcm9tQXJyYXkoKSB0byBrZWVwIGZyb21BcnJheSgpIG1vbm9tb3JwaGljLlxuZnVuY3Rpb24gZnJvbVR5cGVkQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIC8vIFRydW5jYXRpbmcgdGhlIGVsZW1lbnRzIGlzIHByb2JhYmx5IG5vdCB3aGF0IHBlb3BsZSBleHBlY3QgZnJvbSB0eXBlZFxuICAvLyBhcnJheXMgd2l0aCBCWVRFU19QRVJfRUxFTUVOVCA+IDEgYnV0IGl0J3MgY29tcGF0aWJsZSB3aXRoIHRoZSBiZWhhdmlvclxuICAvLyBvZiB0aGUgb2xkIEJ1ZmZlciBjb25zdHJ1Y3Rvci5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUJ1ZmZlciAodGhhdCwgYXJyYXkpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgYXJyYXkuYnl0ZUxlbmd0aFxuICAgIHRoYXQgPSBCdWZmZXIuX2F1Z21lbnQobmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0ID0gZnJvbVR5cGVkQXJyYXkodGhhdCwgbmV3IFVpbnQ4QXJyYXkoYXJyYXkpKVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUxpa2UgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEZXNlcmlhbGl6ZSB7IHR5cGU6ICdCdWZmZXInLCBkYXRhOiBbMSwyLDMsLi4uXSB9IGludG8gYSBCdWZmZXIgb2JqZWN0LlxuLy8gUmV0dXJucyBhIHplcm8tbGVuZ3RoIGJ1ZmZlciBmb3IgaW5wdXRzIHRoYXQgZG9uJ3QgY29uZm9ybSB0byB0aGUgc3BlYy5cbmZ1bmN0aW9uIGZyb21Kc29uT2JqZWN0ICh0aGF0LCBvYmplY3QpIHtcbiAgdmFyIGFycmF5XG4gIHZhciBsZW5ndGggPSAwXG5cbiAgaWYgKG9iamVjdC50eXBlID09PSAnQnVmZmVyJyAmJiBpc0FycmF5KG9iamVjdC5kYXRhKSkge1xuICAgIGFycmF5ID0gb2JqZWN0LmRhdGFcbiAgICBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIH1cbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gIEJ1ZmZlci5wcm90b3R5cGUuX19wcm90b19fID0gVWludDhBcnJheS5wcm90b3R5cGVcbiAgQnVmZmVyLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXlcbn0gZWxzZSB7XG4gIC8vIHByZS1zZXQgZm9yIHZhbHVlcyB0aGF0IG1heSBleGlzdCBpbiB0aGUgZnV0dXJlXG4gIEJ1ZmZlci5wcm90b3R5cGUubGVuZ3RoID0gdW5kZWZpbmVkXG4gIEJ1ZmZlci5wcm90b3R5cGUucGFyZW50ID0gdW5kZWZpbmVkXG59XG5cbmZ1bmN0aW9uIGFsbG9jYXRlICh0aGF0LCBsZW5ndGgpIHtcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgdGhhdCA9IEJ1ZmZlci5fYXVnbWVudChuZXcgVWludDhBcnJheShsZW5ndGgpKVxuICAgIHRoYXQuX19wcm90b19fID0gQnVmZmVyLnByb3RvdHlwZVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0Lmxlbmd0aCA9IGxlbmd0aFxuICAgIHRoYXQuX2lzQnVmZmVyID0gdHJ1ZVxuICB9XG5cbiAgdmFyIGZyb21Qb29sID0gbGVuZ3RoICE9PSAwICYmIGxlbmd0aCA8PSBCdWZmZXIucG9vbFNpemUgPj4+IDFcbiAgaWYgKGZyb21Qb29sKSB0aGF0LnBhcmVudCA9IHJvb3RQYXJlbnRcblxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBjaGVja2VkIChsZW5ndGgpIHtcbiAgLy8gTm90ZTogY2Fubm90IHVzZSBgbGVuZ3RoIDwga01heExlbmd0aGAgaGVyZSBiZWNhdXNlIHRoYXQgZmFpbHMgd2hlblxuICAvLyBsZW5ndGggaXMgTmFOICh3aGljaCBpcyBvdGhlcndpc2UgY29lcmNlZCB0byB6ZXJvLilcbiAgaWYgKGxlbmd0aCA+PSBrTWF4TGVuZ3RoKCkpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignQXR0ZW1wdCB0byBhbGxvY2F0ZSBCdWZmZXIgbGFyZ2VyIHRoYW4gbWF4aW11bSAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAnc2l6ZTogMHgnICsga01heExlbmd0aCgpLnRvU3RyaW5nKDE2KSArICcgYnl0ZXMnKVxuICB9XG4gIHJldHVybiBsZW5ndGggfCAwXG59XG5cbmZ1bmN0aW9uIFNsb3dCdWZmZXIgKHN1YmplY3QsIGVuY29kaW5nKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBTbG93QnVmZmVyKSkgcmV0dXJuIG5ldyBTbG93QnVmZmVyKHN1YmplY3QsIGVuY29kaW5nKVxuXG4gIHZhciBidWYgPSBuZXcgQnVmZmVyKHN1YmplY3QsIGVuY29kaW5nKVxuICBkZWxldGUgYnVmLnBhcmVudFxuICByZXR1cm4gYnVmXG59XG5cbkJ1ZmZlci5pc0J1ZmZlciA9IGZ1bmN0aW9uIGlzQnVmZmVyIChiKSB7XG4gIHJldHVybiAhIShiICE9IG51bGwgJiYgYi5faXNCdWZmZXIpXG59XG5cbkJ1ZmZlci5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYSwgYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihhKSB8fCAhQnVmZmVyLmlzQnVmZmVyKGIpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnRzIG11c3QgYmUgQnVmZmVycycpXG4gIH1cblxuICBpZiAoYSA9PT0gYikgcmV0dXJuIDBcblxuICB2YXIgeCA9IGEubGVuZ3RoXG4gIHZhciB5ID0gYi5sZW5ndGhcblxuICB2YXIgaSA9IDBcbiAgdmFyIGxlbiA9IE1hdGgubWluKHgsIHkpXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgaWYgKGFbaV0gIT09IGJbaV0pIGJyZWFrXG5cbiAgICArK2lcbiAgfVxuXG4gIGlmIChpICE9PSBsZW4pIHtcbiAgICB4ID0gYVtpXVxuICAgIHkgPSBiW2ldXG4gIH1cblxuICBpZiAoeCA8IHkpIHJldHVybiAtMVxuICBpZiAoeSA8IHgpIHJldHVybiAxXG4gIHJldHVybiAwXG59XG5cbkJ1ZmZlci5pc0VuY29kaW5nID0gZnVuY3Rpb24gaXNFbmNvZGluZyAoZW5jb2RpbmcpIHtcbiAgc3dpdGNoIChTdHJpbmcoZW5jb2RpbmcpLnRvTG93ZXJDYXNlKCkpIHtcbiAgICBjYXNlICdoZXgnOlxuICAgIGNhc2UgJ3V0ZjgnOlxuICAgIGNhc2UgJ3V0Zi04JzpcbiAgICBjYXNlICdhc2NpaSc6XG4gICAgY2FzZSAnYmluYXJ5JzpcbiAgICBjYXNlICdiYXNlNjQnOlxuICAgIGNhc2UgJ3Jhdyc6XG4gICAgY2FzZSAndWNzMic6XG4gICAgY2FzZSAndWNzLTInOlxuICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgIHJldHVybiB0cnVlXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbkJ1ZmZlci5jb25jYXQgPSBmdW5jdGlvbiBjb25jYXQgKGxpc3QsIGxlbmd0aCkge1xuICBpZiAoIWlzQXJyYXkobGlzdCkpIHRocm93IG5ldyBUeXBlRXJyb3IoJ2xpc3QgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzLicpXG5cbiAgaWYgKGxpc3QubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIG5ldyBCdWZmZXIoMClcbiAgfVxuXG4gIHZhciBpXG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCkge1xuICAgIGxlbmd0aCA9IDBcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgICAgbGVuZ3RoICs9IGxpc3RbaV0ubGVuZ3RoXG4gICAgfVxuICB9XG5cbiAgdmFyIGJ1ZiA9IG5ldyBCdWZmZXIobGVuZ3RoKVxuICB2YXIgcG9zID0gMFxuICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgIHZhciBpdGVtID0gbGlzdFtpXVxuICAgIGl0ZW0uY29weShidWYsIHBvcylcbiAgICBwb3MgKz0gaXRlbS5sZW5ndGhcbiAgfVxuICByZXR1cm4gYnVmXG59XG5cbmZ1bmN0aW9uIGJ5dGVMZW5ndGggKHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBzdHJpbmcgIT09ICdzdHJpbmcnKSBzdHJpbmcgPSAnJyArIHN0cmluZ1xuXG4gIHZhciBsZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChsZW4gPT09IDApIHJldHVybiAwXG5cbiAgLy8gVXNlIGEgZm9yIGxvb3AgdG8gYXZvaWQgcmVjdXJzaW9uXG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG4gIGZvciAoOzspIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgLy8gRGVwcmVjYXRlZFxuICAgICAgY2FzZSAncmF3JzpcbiAgICAgIGNhc2UgJ3Jhd3MnOlxuICAgICAgICByZXR1cm4gbGVuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gbGVuICogMlxuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGxlbiA+Pj4gMVxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoIC8vIGFzc3VtZSB1dGY4XG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5CdWZmZXIuYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGhcblxuZnVuY3Rpb24gc2xvd1RvU3RyaW5nIChlbmNvZGluZywgc3RhcnQsIGVuZCkge1xuICB2YXIgbG93ZXJlZENhc2UgPSBmYWxzZVxuXG4gIHN0YXJ0ID0gc3RhcnQgfCAwXG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkIHx8IGVuZCA9PT0gSW5maW5pdHkgPyB0aGlzLmxlbmd0aCA6IGVuZCB8IDBcblxuICBpZiAoIWVuY29kaW5nKSBlbmNvZGluZyA9ICd1dGY4J1xuICBpZiAoc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgaWYgKGVuZCA+IHRoaXMubGVuZ3RoKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAoZW5kIDw9IHN0YXJ0KSByZXR1cm4gJydcblxuICB3aGlsZSAodHJ1ZSkge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBoZXhTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICAgIHJldHVybiBhc2NpaVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAgIHJldHVybiBiaW5hcnlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIHV0ZjE2bGVTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBlbmNvZGluZylcbiAgICAgICAgZW5jb2RpbmcgPSAoZW5jb2RpbmcgKyAnJykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS50b1N0cmluZyA9IGZ1bmN0aW9uIHRvU3RyaW5nICgpIHtcbiAgdmFyIGxlbmd0aCA9IHRoaXMubGVuZ3RoIHwgMFxuICBpZiAobGVuZ3RoID09PSAwKSByZXR1cm4gJydcbiAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDApIHJldHVybiB1dGY4U2xpY2UodGhpcywgMCwgbGVuZ3RoKVxuICByZXR1cm4gc2xvd1RvU3RyaW5nLmFwcGx5KHRoaXMsIGFyZ3VtZW50cylcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5lcXVhbHMgPSBmdW5jdGlvbiBlcXVhbHMgKGIpIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoYikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50IG11c3QgYmUgYSBCdWZmZXInKVxuICBpZiAodGhpcyA9PT0gYikgcmV0dXJuIHRydWVcbiAgcmV0dXJuIEJ1ZmZlci5jb21wYXJlKHRoaXMsIGIpID09PSAwXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuaW5zcGVjdCA9IGZ1bmN0aW9uIGluc3BlY3QgKCkge1xuICB2YXIgc3RyID0gJydcbiAgdmFyIG1heCA9IGV4cG9ydHMuSU5TUEVDVF9NQVhfQllURVNcbiAgaWYgKHRoaXMubGVuZ3RoID4gMCkge1xuICAgIHN0ciA9IHRoaXMudG9TdHJpbmcoJ2hleCcsIDAsIG1heCkubWF0Y2goLy57Mn0vZykuam9pbignICcpXG4gICAgaWYgKHRoaXMubGVuZ3RoID4gbWF4KSBzdHIgKz0gJyAuLi4gJ1xuICB9XG4gIHJldHVybiAnPEJ1ZmZlciAnICsgc3RyICsgJz4nXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuY29tcGFyZSA9IGZ1bmN0aW9uIGNvbXBhcmUgKGIpIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoYikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50IG11c3QgYmUgYSBCdWZmZXInKVxuICBpZiAodGhpcyA9PT0gYikgcmV0dXJuIDBcbiAgcmV0dXJuIEJ1ZmZlci5jb21wYXJlKHRoaXMsIGIpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuaW5kZXhPZiA9IGZ1bmN0aW9uIGluZGV4T2YgKHZhbCwgYnl0ZU9mZnNldCkge1xuICBpZiAoYnl0ZU9mZnNldCA+IDB4N2ZmZmZmZmYpIGJ5dGVPZmZzZXQgPSAweDdmZmZmZmZmXG4gIGVsc2UgaWYgKGJ5dGVPZmZzZXQgPCAtMHg4MDAwMDAwMCkgYnl0ZU9mZnNldCA9IC0weDgwMDAwMDAwXG4gIGJ5dGVPZmZzZXQgPj49IDBcblxuICBpZiAodGhpcy5sZW5ndGggPT09IDApIHJldHVybiAtMVxuICBpZiAoYnl0ZU9mZnNldCA+PSB0aGlzLmxlbmd0aCkgcmV0dXJuIC0xXG5cbiAgLy8gTmVnYXRpdmUgb2Zmc2V0cyBzdGFydCBmcm9tIHRoZSBlbmQgb2YgdGhlIGJ1ZmZlclxuICBpZiAoYnl0ZU9mZnNldCA8IDApIGJ5dGVPZmZzZXQgPSBNYXRoLm1heCh0aGlzLmxlbmd0aCArIGJ5dGVPZmZzZXQsIDApXG5cbiAgaWYgKHR5cGVvZiB2YWwgPT09ICdzdHJpbmcnKSB7XG4gICAgaWYgKHZhbC5sZW5ndGggPT09IDApIHJldHVybiAtMSAvLyBzcGVjaWFsIGNhc2U6IGxvb2tpbmcgZm9yIGVtcHR5IHN0cmluZyBhbHdheXMgZmFpbHNcbiAgICByZXR1cm4gU3RyaW5nLnByb3RvdHlwZS5pbmRleE9mLmNhbGwodGhpcywgdmFsLCBieXRlT2Zmc2V0KVxuICB9XG4gIGlmIChCdWZmZXIuaXNCdWZmZXIodmFsKSkge1xuICAgIHJldHVybiBhcnJheUluZGV4T2YodGhpcywgdmFsLCBieXRlT2Zmc2V0KVxuICB9XG4gIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCAmJiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgICB9XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCBbIHZhbCBdLCBieXRlT2Zmc2V0KVxuICB9XG5cbiAgZnVuY3Rpb24gYXJyYXlJbmRleE9mIChhcnIsIHZhbCwgYnl0ZU9mZnNldCkge1xuICAgIHZhciBmb3VuZEluZGV4ID0gLTFcbiAgICBmb3IgKHZhciBpID0gMDsgYnl0ZU9mZnNldCArIGkgPCBhcnIubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChhcnJbYnl0ZU9mZnNldCArIGldID09PSB2YWxbZm91bmRJbmRleCA9PT0gLTEgPyAwIDogaSAtIGZvdW5kSW5kZXhdKSB7XG4gICAgICAgIGlmIChmb3VuZEluZGV4ID09PSAtMSkgZm91bmRJbmRleCA9IGlcbiAgICAgICAgaWYgKGkgLSBmb3VuZEluZGV4ICsgMSA9PT0gdmFsLmxlbmd0aCkgcmV0dXJuIGJ5dGVPZmZzZXQgKyBmb3VuZEluZGV4XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBmb3VuZEluZGV4ID0gLTFcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIC0xXG4gIH1cblxuICB0aHJvdyBuZXcgVHlwZUVycm9yKCd2YWwgbXVzdCBiZSBzdHJpbmcsIG51bWJlciBvciBCdWZmZXInKVxufVxuXG4vLyBgZ2V0YCBpcyBkZXByZWNhdGVkXG5CdWZmZXIucHJvdG90eXBlLmdldCA9IGZ1bmN0aW9uIGdldCAob2Zmc2V0KSB7XG4gIGNvbnNvbGUubG9nKCcuZ2V0KCkgaXMgZGVwcmVjYXRlZC4gQWNjZXNzIHVzaW5nIGFycmF5IGluZGV4ZXMgaW5zdGVhZC4nKVxuICByZXR1cm4gdGhpcy5yZWFkVUludDgob2Zmc2V0KVxufVxuXG4vLyBgc2V0YCBpcyBkZXByZWNhdGVkXG5CdWZmZXIucHJvdG90eXBlLnNldCA9IGZ1bmN0aW9uIHNldCAodiwgb2Zmc2V0KSB7XG4gIGNvbnNvbGUubG9nKCcuc2V0KCkgaXMgZGVwcmVjYXRlZC4gQWNjZXNzIHVzaW5nIGFycmF5IGluZGV4ZXMgaW5zdGVhZC4nKVxuICByZXR1cm4gdGhpcy53cml0ZVVJbnQ4KHYsIG9mZnNldClcbn1cblxuZnVuY3Rpb24gaGV4V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICBvZmZzZXQgPSBOdW1iZXIob2Zmc2V0KSB8fCAwXG4gIHZhciByZW1haW5pbmcgPSBidWYubGVuZ3RoIC0gb2Zmc2V0XG4gIGlmICghbGVuZ3RoKSB7XG4gICAgbGVuZ3RoID0gcmVtYWluaW5nXG4gIH0gZWxzZSB7XG4gICAgbGVuZ3RoID0gTnVtYmVyKGxlbmd0aClcbiAgICBpZiAobGVuZ3RoID4gcmVtYWluaW5nKSB7XG4gICAgICBsZW5ndGggPSByZW1haW5pbmdcbiAgICB9XG4gIH1cblxuICAvLyBtdXN0IGJlIGFuIGV2ZW4gbnVtYmVyIG9mIGRpZ2l0c1xuICB2YXIgc3RyTGVuID0gc3RyaW5nLmxlbmd0aFxuICBpZiAoc3RyTGVuICUgMiAhPT0gMCkgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGhleCBzdHJpbmcnKVxuXG4gIGlmIChsZW5ndGggPiBzdHJMZW4gLyAyKSB7XG4gICAgbGVuZ3RoID0gc3RyTGVuIC8gMlxuICB9XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgcGFyc2VkID0gcGFyc2VJbnQoc3RyaW5nLnN1YnN0cihpICogMiwgMiksIDE2KVxuICAgIGlmIChpc05hTihwYXJzZWQpKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGV4IHN0cmluZycpXG4gICAgYnVmW29mZnNldCArIGldID0gcGFyc2VkXG4gIH1cbiAgcmV0dXJuIGlcbn1cblxuZnVuY3Rpb24gdXRmOFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIodXRmOFRvQnl0ZXMoc3RyaW5nLCBidWYubGVuZ3RoIC0gb2Zmc2V0KSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYXNjaWlXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKGFzY2lpVG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBiaW5hcnlXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBhc2NpaVdyaXRlKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmFzZTY0V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihiYXNlNjRUb0J5dGVzKHN0cmluZyksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIHVjczJXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjE2bGVUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGUgPSBmdW5jdGlvbiB3cml0ZSAoc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCwgZW5jb2RpbmcpIHtcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZylcbiAgaWYgKG9mZnNldCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgZW5jb2RpbmcgPSAndXRmOCdcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgZW5jb2RpbmcpXG4gIH0gZWxzZSBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQgJiYgdHlwZW9mIG9mZnNldCA9PT0gJ3N0cmluZycpIHtcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIGxlbmd0aCA9IHRoaXMubGVuZ3RoXG4gICAgb2Zmc2V0ID0gMFxuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nLCBvZmZzZXRbLCBsZW5ndGhdWywgZW5jb2RpbmddKVxuICB9IGVsc2UgaWYgKGlzRmluaXRlKG9mZnNldCkpIHtcbiAgICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gICAgaWYgKGlzRmluaXRlKGxlbmd0aCkpIHtcbiAgICAgIGxlbmd0aCA9IGxlbmd0aCB8IDBcbiAgICAgIGlmIChlbmNvZGluZyA9PT0gdW5kZWZpbmVkKSBlbmNvZGluZyA9ICd1dGY4J1xuICAgIH0gZWxzZSB7XG4gICAgICBlbmNvZGluZyA9IGxlbmd0aFxuICAgICAgbGVuZ3RoID0gdW5kZWZpbmVkXG4gICAgfVxuICAvLyBsZWdhY3kgd3JpdGUoc3RyaW5nLCBlbmNvZGluZywgb2Zmc2V0LCBsZW5ndGgpIC0gcmVtb3ZlIGluIHYwLjEzXG4gIH0gZWxzZSB7XG4gICAgdmFyIHN3YXAgPSBlbmNvZGluZ1xuICAgIGVuY29kaW5nID0gb2Zmc2V0XG4gICAgb2Zmc2V0ID0gbGVuZ3RoIHwgMFxuICAgIGxlbmd0aCA9IHN3YXBcbiAgfVxuXG4gIHZhciByZW1haW5pbmcgPSB0aGlzLmxlbmd0aCAtIG9mZnNldFxuICBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQgfHwgbGVuZ3RoID4gcmVtYWluaW5nKSBsZW5ndGggPSByZW1haW5pbmdcblxuICBpZiAoKHN0cmluZy5sZW5ndGggPiAwICYmIChsZW5ndGggPCAwIHx8IG9mZnNldCA8IDApKSB8fCBvZmZzZXQgPiB0aGlzLmxlbmd0aCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdhdHRlbXB0IHRvIHdyaXRlIG91dHNpZGUgYnVmZmVyIGJvdW5kcycpXG4gIH1cblxuICBpZiAoIWVuY29kaW5nKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG4gIGZvciAoOzspIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgLy8gV2FybmluZzogbWF4TGVuZ3RoIG5vdCB0YWtlbiBpbnRvIGFjY291bnQgaW4gYmFzZTY0V3JpdGVcbiAgICAgICAgcmV0dXJuIGJhc2U2NFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1Y3MyV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9KU09OID0gZnVuY3Rpb24gdG9KU09OICgpIHtcbiAgcmV0dXJuIHtcbiAgICB0eXBlOiAnQnVmZmVyJyxcbiAgICBkYXRhOiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCh0aGlzLl9hcnIgfHwgdGhpcywgMClcbiAgfVxufVxuXG5mdW5jdGlvbiBiYXNlNjRTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGlmIChzdGFydCA9PT0gMCAmJiBlbmQgPT09IGJ1Zi5sZW5ndGgpIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmKVxuICB9IGVsc2Uge1xuICAgIHJldHVybiBiYXNlNjQuZnJvbUJ5dGVBcnJheShidWYuc2xpY2Uoc3RhcnQsIGVuZCkpXG4gIH1cbn1cblxuZnVuY3Rpb24gdXRmOFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuICB2YXIgcmVzID0gW11cblxuICB2YXIgaSA9IHN0YXJ0XG4gIHdoaWxlIChpIDwgZW5kKSB7XG4gICAgdmFyIGZpcnN0Qnl0ZSA9IGJ1ZltpXVxuICAgIHZhciBjb2RlUG9pbnQgPSBudWxsXG4gICAgdmFyIGJ5dGVzUGVyU2VxdWVuY2UgPSAoZmlyc3RCeXRlID4gMHhFRikgPyA0XG4gICAgICA6IChmaXJzdEJ5dGUgPiAweERGKSA/IDNcbiAgICAgIDogKGZpcnN0Qnl0ZSA+IDB4QkYpID8gMlxuICAgICAgOiAxXG5cbiAgICBpZiAoaSArIGJ5dGVzUGVyU2VxdWVuY2UgPD0gZW5kKSB7XG4gICAgICB2YXIgc2Vjb25kQnl0ZSwgdGhpcmRCeXRlLCBmb3VydGhCeXRlLCB0ZW1wQ29kZVBvaW50XG5cbiAgICAgIHN3aXRjaCAoYnl0ZXNQZXJTZXF1ZW5jZSkge1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgaWYgKGZpcnN0Qnl0ZSA8IDB4ODApIHtcbiAgICAgICAgICAgIGNvZGVQb2ludCA9IGZpcnN0Qnl0ZVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweDFGKSA8PCAweDYgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0YpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4RikgPDwgMHhDIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAodGhpcmRCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHg3RkYgJiYgKHRlbXBDb2RlUG9pbnQgPCAweEQ4MDAgfHwgdGVtcENvZGVQb2ludCA+IDB4REZGRikpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgZm91cnRoQnl0ZSA9IGJ1ZltpICsgM11cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAodGhpcmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKGZvdXJ0aEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4MTIgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpIDw8IDB4QyB8ICh0aGlyZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAoZm91cnRoQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4RkZGRiAmJiB0ZW1wQ29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoY29kZVBvaW50ID09PSBudWxsKSB7XG4gICAgICAvLyB3ZSBkaWQgbm90IGdlbmVyYXRlIGEgdmFsaWQgY29kZVBvaW50IHNvIGluc2VydCBhXG4gICAgICAvLyByZXBsYWNlbWVudCBjaGFyIChVK0ZGRkQpIGFuZCBhZHZhbmNlIG9ubHkgMSBieXRlXG4gICAgICBjb2RlUG9pbnQgPSAweEZGRkRcbiAgICAgIGJ5dGVzUGVyU2VxdWVuY2UgPSAxXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPiAweEZGRkYpIHtcbiAgICAgIC8vIGVuY29kZSB0byB1dGYxNiAoc3Vycm9nYXRlIHBhaXIgZGFuY2UpXG4gICAgICBjb2RlUG9pbnQgLT0gMHgxMDAwMFxuICAgICAgcmVzLnB1c2goY29kZVBvaW50ID4+PiAxMCAmIDB4M0ZGIHwgMHhEODAwKVxuICAgICAgY29kZVBvaW50ID0gMHhEQzAwIHwgY29kZVBvaW50ICYgMHgzRkZcbiAgICB9XG5cbiAgICByZXMucHVzaChjb2RlUG9pbnQpXG4gICAgaSArPSBieXRlc1BlclNlcXVlbmNlXG4gIH1cblxuICByZXR1cm4gZGVjb2RlQ29kZVBvaW50c0FycmF5KHJlcylcbn1cblxuLy8gQmFzZWQgb24gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMjI3NDcyNzIvNjgwNzQyLCB0aGUgYnJvd3NlciB3aXRoXG4vLyB0aGUgbG93ZXN0IGxpbWl0IGlzIENocm9tZSwgd2l0aCAweDEwMDAwIGFyZ3MuXG4vLyBXZSBnbyAxIG1hZ25pdHVkZSBsZXNzLCBmb3Igc2FmZXR5XG52YXIgTUFYX0FSR1VNRU5UU19MRU5HVEggPSAweDEwMDBcblxuZnVuY3Rpb24gZGVjb2RlQ29kZVBvaW50c0FycmF5IChjb2RlUG9pbnRzKSB7XG4gIHZhciBsZW4gPSBjb2RlUG9pbnRzLmxlbmd0aFxuICBpZiAobGVuIDw9IE1BWF9BUkdVTUVOVFNfTEVOR1RIKSB7XG4gICAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoU3RyaW5nLCBjb2RlUG9pbnRzKSAvLyBhdm9pZCBleHRyYSBzbGljZSgpXG4gIH1cblxuICAvLyBEZWNvZGUgaW4gY2h1bmtzIHRvIGF2b2lkIFwiY2FsbCBzdGFjayBzaXplIGV4Y2VlZGVkXCIuXG4gIHZhciByZXMgPSAnJ1xuICB2YXIgaSA9IDBcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShcbiAgICAgIFN0cmluZyxcbiAgICAgIGNvZGVQb2ludHMuc2xpY2UoaSwgaSArPSBNQVhfQVJHVU1FTlRTX0xFTkdUSClcbiAgICApXG4gIH1cbiAgcmV0dXJuIHJlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIHJldCA9ICcnXG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcblxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIHJldCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSAmIDB4N0YpXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBiaW5hcnlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0pXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBoZXhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSBidWYubGVuZ3RoXG5cbiAgaWYgKCFzdGFydCB8fCBzdGFydCA8IDApIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCB8fCBlbmQgPCAwIHx8IGVuZCA+IGxlbikgZW5kID0gbGVuXG5cbiAgdmFyIG91dCA9ICcnXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgb3V0ICs9IHRvSGV4KGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gb3V0XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBieXRlcyA9IGJ1Zi5zbGljZShzdGFydCwgZW5kKVxuICB2YXIgcmVzID0gJydcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBieXRlcy5sZW5ndGg7IGkgKz0gMikge1xuICAgIHJlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ5dGVzW2ldICsgYnl0ZXNbaSArIDFdICogMjU2KVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zbGljZSA9IGZ1bmN0aW9uIHNsaWNlIChzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSB0aGlzLmxlbmd0aFxuICBzdGFydCA9IH5+c3RhcnRcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgPyBsZW4gOiB+fmVuZFxuXG4gIGlmIChzdGFydCA8IDApIHtcbiAgICBzdGFydCArPSBsZW5cbiAgICBpZiAoc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgfSBlbHNlIGlmIChzdGFydCA+IGxlbikge1xuICAgIHN0YXJ0ID0gbGVuXG4gIH1cblxuICBpZiAoZW5kIDwgMCkge1xuICAgIGVuZCArPSBsZW5cbiAgICBpZiAoZW5kIDwgMCkgZW5kID0gMFxuICB9IGVsc2UgaWYgKGVuZCA+IGxlbikge1xuICAgIGVuZCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIHZhciBuZXdCdWZcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgbmV3QnVmID0gQnVmZmVyLl9hdWdtZW50KHRoaXMuc3ViYXJyYXkoc3RhcnQsIGVuZCkpXG4gIH0gZWxzZSB7XG4gICAgdmFyIHNsaWNlTGVuID0gZW5kIC0gc3RhcnRcbiAgICBuZXdCdWYgPSBuZXcgQnVmZmVyKHNsaWNlTGVuLCB1bmRlZmluZWQpXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzbGljZUxlbjsgaSsrKSB7XG4gICAgICBuZXdCdWZbaV0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH1cblxuICBpZiAobmV3QnVmLmxlbmd0aCkgbmV3QnVmLnBhcmVudCA9IHRoaXMucGFyZW50IHx8IHRoaXNcblxuICByZXR1cm4gbmV3QnVmXG59XG5cbi8qXG4gKiBOZWVkIHRvIG1ha2Ugc3VyZSB0aGF0IGJ1ZmZlciBpc24ndCB0cnlpbmcgdG8gd3JpdGUgb3V0IG9mIGJvdW5kcy5cbiAqL1xuZnVuY3Rpb24gY2hlY2tPZmZzZXQgKG9mZnNldCwgZXh0LCBsZW5ndGgpIHtcbiAgaWYgKChvZmZzZXQgJSAxKSAhPT0gMCB8fCBvZmZzZXQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignb2Zmc2V0IGlzIG5vdCB1aW50JylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1RyeWluZyB0byBhY2Nlc3MgYmV5b25kIGJ1ZmZlciBsZW5ndGgnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50TEUgPSBmdW5jdGlvbiByZWFkVUludExFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XVxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyBpXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50QkUgPSBmdW5jdGlvbiByZWFkVUludEJFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuICB9XG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXVxuICB2YXIgbXVsID0gMVxuICB3aGlsZSAoYnl0ZUxlbmd0aCA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWJ5dGVMZW5ndGhdICogbXVsXG4gIH1cblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQ4ID0gZnVuY3Rpb24gcmVhZFVJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDE2TEUgPSBmdW5jdGlvbiByZWFkVUludDE2TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XSB8ICh0aGlzW29mZnNldCArIDFdIDw8IDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkJFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiAodGhpc1tvZmZzZXRdIDw8IDgpIHwgdGhpc1tvZmZzZXQgKyAxXVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRVSW50MzJMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAoKHRoaXNbb2Zmc2V0XSkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOCkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpKSArXG4gICAgICAodGhpc1tvZmZzZXQgKyAzXSAqIDB4MTAwMDAwMClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyQkUgPSBmdW5jdGlvbiByZWFkVUludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSAqIDB4MTAwMDAwMCkgK1xuICAgICgodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICB0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRMRSA9IGZ1bmN0aW9uIHJlYWRJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRCRSA9IGZ1bmN0aW9uIHJlYWRJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aFxuICB2YXIgbXVsID0gMVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAtLWldXG4gIHdoaWxlIChpID4gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIC0taV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQ4ID0gZnVuY3Rpb24gcmVhZEludDggKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAxLCB0aGlzLmxlbmd0aClcbiAgaWYgKCEodGhpc1tvZmZzZXRdICYgMHg4MCkpIHJldHVybiAodGhpc1tvZmZzZXRdKVxuICByZXR1cm4gKCgweGZmIC0gdGhpc1tvZmZzZXRdICsgMSkgKiAtMSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MTZMRSA9IGZ1bmN0aW9uIHJlYWRJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2QkUgPSBmdW5jdGlvbiByZWFkSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAxXSB8ICh0aGlzW29mZnNldF0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkxFID0gZnVuY3Rpb24gcmVhZEludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDNdIDw8IDI0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkJFID0gZnVuY3Rpb24gcmVhZEludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCAyNCkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgOCkgfFxuICAgICh0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdExFID0gZnVuY3Rpb24gcmVhZEZsb2F0TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDIzLCA0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdEJFID0gZnVuY3Rpb24gcmVhZEZsb2F0QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlTEUgPSBmdW5jdGlvbiByZWFkRG91YmxlTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDUyLCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWREb3VibGVCRSA9IGZ1bmN0aW9uIHJlYWREb3VibGVCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgZmFsc2UsIDUyLCA4KVxufVxuXG5mdW5jdGlvbiBjaGVja0ludCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGJ1ZikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ2J1ZmZlciBtdXN0IGJlIGEgQnVmZmVyIGluc3RhbmNlJylcbiAgaWYgKHZhbHVlID4gbWF4IHx8IHZhbHVlIDwgbWluKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcigndmFsdWUgaXMgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBidWYubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignaW5kZXggb3V0IG9mIHJhbmdlJylcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnRMRSA9IGZ1bmN0aW9uIHdyaXRlVUludExFICh2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCksIDApXG5cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHRoaXNbb2Zmc2V0XSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAodmFsdWUgLyBtdWwpICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnRCRSA9IGZ1bmN0aW9uIHdyaXRlVUludEJFICh2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCksIDApXG5cbiAgdmFyIGkgPSBieXRlTGVuZ3RoIC0gMVxuICB2YXIgbXVsID0gMVxuICB0aGlzW29mZnNldCArIGldID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgtLWkgPj0gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAodmFsdWUgLyBtdWwpICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQ4ID0gZnVuY3Rpb24gd3JpdGVVSW50OCAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAxLCAweGZmLCAwKVxuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB2YWx1ZSA9IE1hdGguZmxvb3IodmFsdWUpXG4gIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIHJldHVybiBvZmZzZXQgKyAxXG59XG5cbmZ1bmN0aW9uIG9iamVjdFdyaXRlVUludDE2IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbikge1xuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmZmZiArIHZhbHVlICsgMVxuICBmb3IgKHZhciBpID0gMCwgaiA9IE1hdGgubWluKGJ1Zi5sZW5ndGggLSBvZmZzZXQsIDIpOyBpIDwgajsgaSsrKSB7XG4gICAgYnVmW29mZnNldCArIGldID0gKHZhbHVlICYgKDB4ZmYgPDwgKDggKiAobGl0dGxlRW5kaWFuID8gaSA6IDEgLSBpKSkpKSA+Pj5cbiAgICAgIChsaXR0bGVFbmRpYW4gPyBpIDogMSAtIGkpICogOFxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZMRSA9IGZ1bmN0aW9uIHdyaXRlVUludDE2TEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHhmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDE2QkUgPSBmdW5jdGlvbiB3cml0ZVVJbnQxNkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4ZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbmZ1bmN0aW9uIG9iamVjdFdyaXRlVUludDMyIChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbikge1xuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmZmZmZmZmYgKyB2YWx1ZSArIDFcbiAgZm9yICh2YXIgaSA9IDAsIGogPSBNYXRoLm1pbihidWYubGVuZ3RoIC0gb2Zmc2V0LCA0KTsgaSA8IGo7IGkrKykge1xuICAgIGJ1ZltvZmZzZXQgKyBpXSA9ICh2YWx1ZSA+Pj4gKGxpdHRsZUVuZGlhbiA/IGkgOiAzIC0gaSkgKiA4KSAmIDB4ZmZcbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDMyTEUgPSBmdW5jdGlvbiB3cml0ZVVJbnQzMkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4ZmZmZmZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MzJCRSA9IGZ1bmN0aW9uIHdyaXRlVUludDMyQkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHhmZmZmZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnRMRSA9IGZ1bmN0aW9uIHdyaXRlSW50TEUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIHZhciBsaW1pdCA9IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoIC0gMSlcblxuICAgIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIGxpbWl0IC0gMSwgLWxpbWl0KVxuICB9XG5cbiAgdmFyIGkgPSAwXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSB2YWx1ZSA8IDAgPyAxIDogMFxuICB0aGlzW29mZnNldF0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKCh2YWx1ZSAvIG11bCkgPj4gMCkgLSBzdWIgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50QkUgPSBmdW5jdGlvbiB3cml0ZUludEJFICh2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbGltaXQgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCAtIDEpXG5cbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBsaW1pdCAtIDEsIC1saW1pdClcbiAgfVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aCAtIDFcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHN1YiA9IHZhbHVlIDwgMCA/IDEgOiAwXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDggPSBmdW5jdGlvbiB3cml0ZUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHg3ZiwgLTB4ODApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmICsgdmFsdWUgKyAxXG4gIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIHJldHVybiBvZmZzZXQgKyAxXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDE2QkUgPSBmdW5jdGlvbiB3cml0ZUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHg3ZmZmLCAtMHg4MDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDMyTEUgPSBmdW5jdGlvbiB3cml0ZUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHg3ZmZmZmZmZiwgLTB4ODAwMDAwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmZmZmZmZmYgKyB2YWx1ZSArIDFcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbmZ1bmN0aW9uIGNoZWNrSUVFRTc1NCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3ZhbHVlIGlzIG91dCBvZiBib3VuZHMnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gYnVmLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG4gIGlmIChvZmZzZXQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignaW5kZXggb3V0IG9mIHJhbmdlJylcbn1cblxuZnVuY3Rpb24gd3JpdGVGbG9hdCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICBjaGVja0lFRUU3NTQoYnVmLCB2YWx1ZSwgb2Zmc2V0LCA0LCAzLjQwMjgyMzQ2NjM4NTI4ODZlKzM4LCAtMy40MDI4MjM0NjYzODUyODg2ZSszOClcbiAgfVxuICBpZWVlNzU0LndyaXRlKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCAyMywgNClcbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUZsb2F0TEUgPSBmdW5jdGlvbiB3cml0ZUZsb2F0TEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZUZsb2F0KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUsIG5vQXNzZXJ0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRmxvYXRCRSA9IGZ1bmN0aW9uIHdyaXRlRmxvYXRCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRmxvYXQodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UsIG5vQXNzZXJ0KVxufVxuXG5mdW5jdGlvbiB3cml0ZURvdWJsZSAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICBjaGVja0lFRUU3NTQoYnVmLCB2YWx1ZSwgb2Zmc2V0LCA4LCAxLjc5NzY5MzEzNDg2MjMxNTdFKzMwOCwgLTEuNzk3NjkzMTM0ODYyMzE1N0UrMzA4KVxuICB9XG4gIGllZWU3NTQud3JpdGUoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIDUyLCA4KVxuICByZXR1cm4gb2Zmc2V0ICsgOFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRG91YmxlTEUgPSBmdW5jdGlvbiB3cml0ZURvdWJsZUxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVEb3VibGUodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSwgbm9Bc3NlcnQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVEb3VibGVCRSA9IGZ1bmN0aW9uIHdyaXRlRG91YmxlQkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbi8vIGNvcHkodGFyZ2V0QnVmZmVyLCB0YXJnZXRTdGFydD0wLCBzb3VyY2VTdGFydD0wLCBzb3VyY2VFbmQ9YnVmZmVyLmxlbmd0aClcbkJ1ZmZlci5wcm90b3R5cGUuY29weSA9IGZ1bmN0aW9uIGNvcHkgKHRhcmdldCwgdGFyZ2V0U3RhcnQsIHN0YXJ0LCBlbmQpIHtcbiAgaWYgKCFzdGFydCkgc3RhcnQgPSAwXG4gIGlmICghZW5kICYmIGVuZCAhPT0gMCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKHRhcmdldFN0YXJ0ID49IHRhcmdldC5sZW5ndGgpIHRhcmdldFN0YXJ0ID0gdGFyZ2V0Lmxlbmd0aFxuICBpZiAoIXRhcmdldFN0YXJ0KSB0YXJnZXRTdGFydCA9IDBcbiAgaWYgKGVuZCA+IDAgJiYgZW5kIDwgc3RhcnQpIGVuZCA9IHN0YXJ0XG5cbiAgLy8gQ29weSAwIGJ5dGVzOyB3ZSdyZSBkb25lXG4gIGlmIChlbmQgPT09IHN0YXJ0KSByZXR1cm4gMFxuICBpZiAodGFyZ2V0Lmxlbmd0aCA9PT0gMCB8fCB0aGlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIDBcblxuICAvLyBGYXRhbCBlcnJvciBjb25kaXRpb25zXG4gIGlmICh0YXJnZXRTdGFydCA8IDApIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcigndGFyZ2V0U3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIH1cbiAgaWYgKHN0YXJ0IDwgMCB8fCBzdGFydCA+PSB0aGlzLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3NvdXJjZVN0YXJ0IG91dCBvZiBib3VuZHMnKVxuICBpZiAoZW5kIDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3NvdXJjZUVuZCBvdXQgb2YgYm91bmRzJylcblxuICAvLyBBcmUgd2Ugb29iP1xuICBpZiAoZW5kID4gdGhpcy5sZW5ndGgpIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmICh0YXJnZXQubGVuZ3RoIC0gdGFyZ2V0U3RhcnQgPCBlbmQgLSBzdGFydCkge1xuICAgIGVuZCA9IHRhcmdldC5sZW5ndGggLSB0YXJnZXRTdGFydCArIHN0YXJ0XG4gIH1cblxuICB2YXIgbGVuID0gZW5kIC0gc3RhcnRcbiAgdmFyIGlcblxuICBpZiAodGhpcyA9PT0gdGFyZ2V0ICYmIHN0YXJ0IDwgdGFyZ2V0U3RhcnQgJiYgdGFyZ2V0U3RhcnQgPCBlbmQpIHtcbiAgICAvLyBkZXNjZW5kaW5nIGNvcHkgZnJvbSBlbmRcbiAgICBmb3IgKGkgPSBsZW4gLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgdGFyZ2V0W2kgKyB0YXJnZXRTdGFydF0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH0gZWxzZSBpZiAobGVuIDwgMTAwMCB8fCAhQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBhc2NlbmRpbmcgY29weSBmcm9tIHN0YXJ0XG4gICAgZm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICB0YXJnZXRbaSArIHRhcmdldFN0YXJ0XSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICB0YXJnZXQuX3NldCh0aGlzLnN1YmFycmF5KHN0YXJ0LCBzdGFydCArIGxlbiksIHRhcmdldFN0YXJ0KVxuICB9XG5cbiAgcmV0dXJuIGxlblxufVxuXG4vLyBmaWxsKHZhbHVlLCBzdGFydD0wLCBlbmQ9YnVmZmVyLmxlbmd0aClcbkJ1ZmZlci5wcm90b3R5cGUuZmlsbCA9IGZ1bmN0aW9uIGZpbGwgKHZhbHVlLCBzdGFydCwgZW5kKSB7XG4gIGlmICghdmFsdWUpIHZhbHVlID0gMFxuICBpZiAoIXN0YXJ0KSBzdGFydCA9IDBcbiAgaWYgKCFlbmQpIGVuZCA9IHRoaXMubGVuZ3RoXG5cbiAgaWYgKGVuZCA8IHN0YXJ0KSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignZW5kIDwgc3RhcnQnKVxuXG4gIC8vIEZpbGwgMCBieXRlczsgd2UncmUgZG9uZVxuICBpZiAoZW5kID09PSBzdGFydCkgcmV0dXJuXG4gIGlmICh0aGlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuXG5cbiAgaWYgKHN0YXJ0IDwgMCB8fCBzdGFydCA+PSB0aGlzLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3N0YXJ0IG91dCBvZiBib3VuZHMnKVxuICBpZiAoZW5kIDwgMCB8fCBlbmQgPiB0aGlzLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2VuZCBvdXQgb2YgYm91bmRzJylcblxuICB2YXIgaVxuICBpZiAodHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJykge1xuICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICAgIHRoaXNbaV0gPSB2YWx1ZVxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICB2YXIgYnl0ZXMgPSB1dGY4VG9CeXRlcyh2YWx1ZS50b1N0cmluZygpKVxuICAgIHZhciBsZW4gPSBieXRlcy5sZW5ndGhcbiAgICBmb3IgKGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICB0aGlzW2ldID0gYnl0ZXNbaSAlIGxlbl1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gdGhpc1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgYEFycmF5QnVmZmVyYCB3aXRoIHRoZSAqY29waWVkKiBtZW1vcnkgb2YgdGhlIGJ1ZmZlciBpbnN0YW5jZS5cbiAqIEFkZGVkIGluIE5vZGUgMC4xMi4gT25seSBhdmFpbGFibGUgaW4gYnJvd3NlcnMgdGhhdCBzdXBwb3J0IEFycmF5QnVmZmVyLlxuICovXG5CdWZmZXIucHJvdG90eXBlLnRvQXJyYXlCdWZmZXIgPSBmdW5jdGlvbiB0b0FycmF5QnVmZmVyICgpIHtcbiAgaWYgKHR5cGVvZiBVaW50OEFycmF5ICE9PSAndW5kZWZpbmVkJykge1xuICAgIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgICAgcmV0dXJuIChuZXcgQnVmZmVyKHRoaXMpKS5idWZmZXJcbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGJ1ZiA9IG5ldyBVaW50OEFycmF5KHRoaXMubGVuZ3RoKVxuICAgICAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IGJ1Zi5sZW5ndGg7IGkgPCBsZW47IGkgKz0gMSkge1xuICAgICAgICBidWZbaV0gPSB0aGlzW2ldXG4gICAgICB9XG4gICAgICByZXR1cm4gYnVmLmJ1ZmZlclxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdCdWZmZXIudG9BcnJheUJ1ZmZlciBub3Qgc3VwcG9ydGVkIGluIHRoaXMgYnJvd3NlcicpXG4gIH1cbn1cblxuLy8gSEVMUEVSIEZVTkNUSU9OU1xuLy8gPT09PT09PT09PT09PT09PVxuXG52YXIgQlAgPSBCdWZmZXIucHJvdG90eXBlXG5cbi8qKlxuICogQXVnbWVudCBhIFVpbnQ4QXJyYXkgKmluc3RhbmNlKiAobm90IHRoZSBVaW50OEFycmF5IGNsYXNzISkgd2l0aCBCdWZmZXIgbWV0aG9kc1xuICovXG5CdWZmZXIuX2F1Z21lbnQgPSBmdW5jdGlvbiBfYXVnbWVudCAoYXJyKSB7XG4gIGFyci5jb25zdHJ1Y3RvciA9IEJ1ZmZlclxuICBhcnIuX2lzQnVmZmVyID0gdHJ1ZVxuXG4gIC8vIHNhdmUgcmVmZXJlbmNlIHRvIG9yaWdpbmFsIFVpbnQ4QXJyYXkgc2V0IG1ldGhvZCBiZWZvcmUgb3ZlcndyaXRpbmdcbiAgYXJyLl9zZXQgPSBhcnIuc2V0XG5cbiAgLy8gZGVwcmVjYXRlZFxuICBhcnIuZ2V0ID0gQlAuZ2V0XG4gIGFyci5zZXQgPSBCUC5zZXRcblxuICBhcnIud3JpdGUgPSBCUC53cml0ZVxuICBhcnIudG9TdHJpbmcgPSBCUC50b1N0cmluZ1xuICBhcnIudG9Mb2NhbGVTdHJpbmcgPSBCUC50b1N0cmluZ1xuICBhcnIudG9KU09OID0gQlAudG9KU09OXG4gIGFyci5lcXVhbHMgPSBCUC5lcXVhbHNcbiAgYXJyLmNvbXBhcmUgPSBCUC5jb21wYXJlXG4gIGFyci5pbmRleE9mID0gQlAuaW5kZXhPZlxuICBhcnIuY29weSA9IEJQLmNvcHlcbiAgYXJyLnNsaWNlID0gQlAuc2xpY2VcbiAgYXJyLnJlYWRVSW50TEUgPSBCUC5yZWFkVUludExFXG4gIGFyci5yZWFkVUludEJFID0gQlAucmVhZFVJbnRCRVxuICBhcnIucmVhZFVJbnQ4ID0gQlAucmVhZFVJbnQ4XG4gIGFyci5yZWFkVUludDE2TEUgPSBCUC5yZWFkVUludDE2TEVcbiAgYXJyLnJlYWRVSW50MTZCRSA9IEJQLnJlYWRVSW50MTZCRVxuICBhcnIucmVhZFVJbnQzMkxFID0gQlAucmVhZFVJbnQzMkxFXG4gIGFyci5yZWFkVUludDMyQkUgPSBCUC5yZWFkVUludDMyQkVcbiAgYXJyLnJlYWRJbnRMRSA9IEJQLnJlYWRJbnRMRVxuICBhcnIucmVhZEludEJFID0gQlAucmVhZEludEJFXG4gIGFyci5yZWFkSW50OCA9IEJQLnJlYWRJbnQ4XG4gIGFyci5yZWFkSW50MTZMRSA9IEJQLnJlYWRJbnQxNkxFXG4gIGFyci5yZWFkSW50MTZCRSA9IEJQLnJlYWRJbnQxNkJFXG4gIGFyci5yZWFkSW50MzJMRSA9IEJQLnJlYWRJbnQzMkxFXG4gIGFyci5yZWFkSW50MzJCRSA9IEJQLnJlYWRJbnQzMkJFXG4gIGFyci5yZWFkRmxvYXRMRSA9IEJQLnJlYWRGbG9hdExFXG4gIGFyci5yZWFkRmxvYXRCRSA9IEJQLnJlYWRGbG9hdEJFXG4gIGFyci5yZWFkRG91YmxlTEUgPSBCUC5yZWFkRG91YmxlTEVcbiAgYXJyLnJlYWREb3VibGVCRSA9IEJQLnJlYWREb3VibGVCRVxuICBhcnIud3JpdGVVSW50OCA9IEJQLndyaXRlVUludDhcbiAgYXJyLndyaXRlVUludExFID0gQlAud3JpdGVVSW50TEVcbiAgYXJyLndyaXRlVUludEJFID0gQlAud3JpdGVVSW50QkVcbiAgYXJyLndyaXRlVUludDE2TEUgPSBCUC53cml0ZVVJbnQxNkxFXG4gIGFyci53cml0ZVVJbnQxNkJFID0gQlAud3JpdGVVSW50MTZCRVxuICBhcnIud3JpdGVVSW50MzJMRSA9IEJQLndyaXRlVUludDMyTEVcbiAgYXJyLndyaXRlVUludDMyQkUgPSBCUC53cml0ZVVJbnQzMkJFXG4gIGFyci53cml0ZUludExFID0gQlAud3JpdGVJbnRMRVxuICBhcnIud3JpdGVJbnRCRSA9IEJQLndyaXRlSW50QkVcbiAgYXJyLndyaXRlSW50OCA9IEJQLndyaXRlSW50OFxuICBhcnIud3JpdGVJbnQxNkxFID0gQlAud3JpdGVJbnQxNkxFXG4gIGFyci53cml0ZUludDE2QkUgPSBCUC53cml0ZUludDE2QkVcbiAgYXJyLndyaXRlSW50MzJMRSA9IEJQLndyaXRlSW50MzJMRVxuICBhcnIud3JpdGVJbnQzMkJFID0gQlAud3JpdGVJbnQzMkJFXG4gIGFyci53cml0ZUZsb2F0TEUgPSBCUC53cml0ZUZsb2F0TEVcbiAgYXJyLndyaXRlRmxvYXRCRSA9IEJQLndyaXRlRmxvYXRCRVxuICBhcnIud3JpdGVEb3VibGVMRSA9IEJQLndyaXRlRG91YmxlTEVcbiAgYXJyLndyaXRlRG91YmxlQkUgPSBCUC53cml0ZURvdWJsZUJFXG4gIGFyci5maWxsID0gQlAuZmlsbFxuICBhcnIuaW5zcGVjdCA9IEJQLmluc3BlY3RcbiAgYXJyLnRvQXJyYXlCdWZmZXIgPSBCUC50b0FycmF5QnVmZmVyXG5cbiAgcmV0dXJuIGFyclxufVxuXG52YXIgSU5WQUxJRF9CQVNFNjRfUkUgPSAvW14rXFwvMC05QS1aYS16LV9dL2dcblxuZnVuY3Rpb24gYmFzZTY0Y2xlYW4gKHN0cikge1xuICAvLyBOb2RlIHN0cmlwcyBvdXQgaW52YWxpZCBjaGFyYWN0ZXJzIGxpa2UgXFxuIGFuZCBcXHQgZnJvbSB0aGUgc3RyaW5nLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgc3RyID0gc3RyaW5ndHJpbShzdHIpLnJlcGxhY2UoSU5WQUxJRF9CQVNFNjRfUkUsICcnKVxuICAvLyBOb2RlIGNvbnZlcnRzIHN0cmluZ3Mgd2l0aCBsZW5ndGggPCAyIHRvICcnXG4gIGlmIChzdHIubGVuZ3RoIDwgMikgcmV0dXJuICcnXG4gIC8vIE5vZGUgYWxsb3dzIGZvciBub24tcGFkZGVkIGJhc2U2NCBzdHJpbmdzIChtaXNzaW5nIHRyYWlsaW5nID09PSksIGJhc2U2NC1qcyBkb2VzIG5vdFxuICB3aGlsZSAoc3RyLmxlbmd0aCAlIDQgIT09IDApIHtcbiAgICBzdHIgPSBzdHIgKyAnPSdcbiAgfVxuICByZXR1cm4gc3RyXG59XG5cbmZ1bmN0aW9uIHN0cmluZ3RyaW0gKHN0cikge1xuICBpZiAoc3RyLnRyaW0pIHJldHVybiBzdHIudHJpbSgpXG4gIHJldHVybiBzdHIucmVwbGFjZSgvXlxccyt8XFxzKyQvZywgJycpXG59XG5cbmZ1bmN0aW9uIHRvSGV4IChuKSB7XG4gIGlmIChuIDwgMTYpIHJldHVybiAnMCcgKyBuLnRvU3RyaW5nKDE2KVxuICByZXR1cm4gbi50b1N0cmluZygxNilcbn1cblxuZnVuY3Rpb24gdXRmOFRvQnl0ZXMgKHN0cmluZywgdW5pdHMpIHtcbiAgdW5pdHMgPSB1bml0cyB8fCBJbmZpbml0eVxuICB2YXIgY29kZVBvaW50XG4gIHZhciBsZW5ndGggPSBzdHJpbmcubGVuZ3RoXG4gIHZhciBsZWFkU3Vycm9nYXRlID0gbnVsbFxuICB2YXIgYnl0ZXMgPSBbXVxuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICBjb2RlUG9pbnQgPSBzdHJpbmcuY2hhckNvZGVBdChpKVxuXG4gICAgLy8gaXMgc3Vycm9nYXRlIGNvbXBvbmVudFxuICAgIGlmIChjb2RlUG9pbnQgPiAweEQ3RkYgJiYgY29kZVBvaW50IDwgMHhFMDAwKSB7XG4gICAgICAvLyBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCFsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAgIC8vIG5vIGxlYWQgeWV0XG4gICAgICAgIGlmIChjb2RlUG9pbnQgPiAweERCRkYpIHtcbiAgICAgICAgICAvLyB1bmV4cGVjdGVkIHRyYWlsXG4gICAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfSBlbHNlIGlmIChpICsgMSA9PT0gbGVuZ3RoKSB7XG4gICAgICAgICAgLy8gdW5wYWlyZWQgbGVhZFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH1cblxuICAgICAgICAvLyB2YWxpZCBsZWFkXG4gICAgICAgIGxlYWRTdXJyb2dhdGUgPSBjb2RlUG9pbnRcblxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyAyIGxlYWRzIGluIGEgcm93XG4gICAgICBpZiAoY29kZVBvaW50IDwgMHhEQzAwKSB7XG4gICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIC8vIHZhbGlkIHN1cnJvZ2F0ZSBwYWlyXG4gICAgICBjb2RlUG9pbnQgPSAobGVhZFN1cnJvZ2F0ZSAtIDB4RDgwMCA8PCAxMCB8IGNvZGVQb2ludCAtIDB4REMwMCkgKyAweDEwMDAwXG4gICAgfSBlbHNlIGlmIChsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAvLyB2YWxpZCBibXAgY2hhciwgYnV0IGxhc3QgY2hhciB3YXMgYSBsZWFkXG4gICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICB9XG5cbiAgICBsZWFkU3Vycm9nYXRlID0gbnVsbFxuXG4gICAgLy8gZW5jb2RlIHV0ZjhcbiAgICBpZiAoY29kZVBvaW50IDwgMHg4MCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAxKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKGNvZGVQb2ludClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4ODAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgfCAweEMwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMDAwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAzKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDIHwgMHhFMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gNCkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4MTIgfCAweEYwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNvZGUgcG9pbnQnKVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBieXRlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVRvQnl0ZXMgKHN0cikge1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcbiAgICAvLyBOb2RlJ3MgY29kZSBzZWVtcyB0byBiZSBkb2luZyB0aGlzIGFuZCBub3QgJiAweDdGLi5cbiAgICBieXRlQXJyYXkucHVzaChzdHIuY2hhckNvZGVBdChpKSAmIDB4RkYpXG4gIH1cbiAgcmV0dXJuIGJ5dGVBcnJheVxufVxuXG5mdW5jdGlvbiB1dGYxNmxlVG9CeXRlcyAoc3RyLCB1bml0cykge1xuICB2YXIgYywgaGksIGxvXG4gIHZhciBieXRlQXJyYXkgPSBbXVxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0ci5sZW5ndGg7IGkrKykge1xuICAgIGlmICgodW5pdHMgLT0gMikgPCAwKSBicmVha1xuXG4gICAgYyA9IHN0ci5jaGFyQ29kZUF0KGkpXG4gICAgaGkgPSBjID4+IDhcbiAgICBsbyA9IGMgJSAyNTZcbiAgICBieXRlQXJyYXkucHVzaChsbylcbiAgICBieXRlQXJyYXkucHVzaChoaSlcbiAgfVxuXG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gYmFzZTY0VG9CeXRlcyAoc3RyKSB7XG4gIHJldHVybiBiYXNlNjQudG9CeXRlQXJyYXkoYmFzZTY0Y2xlYW4oc3RyKSlcbn1cblxuZnVuY3Rpb24gYmxpdEJ1ZmZlciAoc3JjLCBkc3QsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoKGkgKyBvZmZzZXQgPj0gZHN0Lmxlbmd0aCkgfHwgKGkgPj0gc3JjLmxlbmd0aCkpIGJyZWFrXG4gICAgZHN0W2kgKyBvZmZzZXRdID0gc3JjW2ldXG4gIH1cbiAgcmV0dXJuIGlcbn1cbiJdfQ== | |
},{"base64-js":2,"ieee754":3,"isarray":4}],2:[function(require,module,exports){ | |
var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; | |
;(function (exports) { | |
'use strict'; | |
var Arr = (typeof Uint8Array !== 'undefined') | |
? Uint8Array | |
: Array | |
var PLUS = '+'.charCodeAt(0) | |
var SLASH = '/'.charCodeAt(0) | |
var NUMBER = '0'.charCodeAt(0) | |
var LOWER = 'a'.charCodeAt(0) | |
var UPPER = 'A'.charCodeAt(0) | |
var PLUS_URL_SAFE = '-'.charCodeAt(0) | |
var SLASH_URL_SAFE = '_'.charCodeAt(0) | |
function decode (elt) { | |
var code = elt.charCodeAt(0) | |
if (code === PLUS || | |
code === PLUS_URL_SAFE) | |
return 62 // '+' | |
if (code === SLASH || | |
code === SLASH_URL_SAFE) | |
return 63 // '/' | |
if (code < NUMBER) | |
return -1 //no match | |
if (code < NUMBER + 10) | |
return code - NUMBER + 26 + 26 | |
if (code < UPPER + 26) | |
return code - UPPER | |
if (code < LOWER + 26) | |
return code - LOWER + 26 | |
} | |
function b64ToByteArray (b64) { | |
var i, j, l, tmp, placeHolders, arr | |
if (b64.length % 4 > 0) { | |
throw new Error('Invalid string. Length must be a multiple of 4') | |
} | |
// the number of equal signs (place holders) | |
// if there are two placeholders, than the two characters before it | |
// represent one byte | |
// if there is only one, then the three characters before it represent 2 bytes | |
// this is just a cheap hack to not do indexOf twice | |
var len = b64.length | |
placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 | |
// base64 is 4/3 + up to two characters of the original data | |
arr = new Arr(b64.length * 3 / 4 - placeHolders) | |
// if there are placeholders, only get up to the last complete 4 chars | |
l = placeHolders > 0 ? b64.length - 4 : b64.length | |
var L = 0 | |
function push (v) { | |
arr[L++] = v | |
} | |
for (i = 0, j = 0; i < l; i += 4, j += 3) { | |
tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) | |
push((tmp & 0xFF0000) >> 16) | |
push((tmp & 0xFF00) >> 8) | |
push(tmp & 0xFF) | |
} | |
if (placeHolders === 2) { | |
tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) | |
push(tmp & 0xFF) | |
} else if (placeHolders === 1) { | |
tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) | |
push((tmp >> 8) & 0xFF) | |
push(tmp & 0xFF) | |
} | |
return arr | |
} | |
function uint8ToBase64 (uint8) { | |
var i, | |
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes | |
output = "", | |
temp, length | |
function encode (num) { | |
return lookup.charAt(num) | |
} | |
function tripletToBase64 (num) { | |
return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) | |
} | |
// go through the array every three bytes, we'll deal with trailing stuff later | |
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { | |
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) | |
output += tripletToBase64(temp) | |
} | |
// pad the end with zeros, but make sure to not forget the extra bytes | |
switch (extraBytes) { | |
case 1: | |
temp = uint8[uint8.length - 1] | |
output += encode(temp >> 2) | |
output += encode((temp << 4) & 0x3F) | |
output += '==' | |
break | |
case 2: | |
temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) | |
output += encode(temp >> 10) | |
output += encode((temp >> 4) & 0x3F) | |
output += encode((temp << 2) & 0x3F) | |
output += '=' | |
break | |
} | |
return output | |
} | |
exports.toByteArray = b64ToByteArray | |
exports.fromByteArray = uint8ToBase64 | |
}(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) | |
},{}],3:[function(require,module,exports){ | |
exports.read = function (buffer, offset, isLE, mLen, nBytes) { | |
var e, m | |
var eLen = nBytes * 8 - mLen - 1 | |
var eMax = (1 << eLen) - 1 | |
var eBias = eMax >> 1 | |
var nBits = -7 | |
var i = isLE ? (nBytes - 1) : 0 | |
var d = isLE ? -1 : 1 | |
var s = buffer[offset + i] | |
i += d | |
e = s & ((1 << (-nBits)) - 1) | |
s >>= (-nBits) | |
nBits += eLen | |
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} | |
m = e & ((1 << (-nBits)) - 1) | |
e >>= (-nBits) | |
nBits += mLen | |
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} | |
if (e === 0) { | |
e = 1 - eBias | |
} else if (e === eMax) { | |
return m ? NaN : ((s ? -1 : 1) * Infinity) | |
} else { | |
m = m + Math.pow(2, mLen) | |
e = e - eBias | |
} | |
return (s ? -1 : 1) * m * Math.pow(2, e - mLen) | |
} | |
exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { | |
var e, m, c | |
var eLen = nBytes * 8 - mLen - 1 | |
var eMax = (1 << eLen) - 1 | |
var eBias = eMax >> 1 | |
var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) | |
var i = isLE ? 0 : (nBytes - 1) | |
var d = isLE ? 1 : -1 | |
var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 | |
value = Math.abs(value) | |
if (isNaN(value) || value === Infinity) { | |
m = isNaN(value) ? 1 : 0 | |
e = eMax | |
} else { | |
e = Math.floor(Math.log(value) / Math.LN2) | |
if (value * (c = Math.pow(2, -e)) < 1) { | |
e-- | |
c *= 2 | |
} | |
if (e + eBias >= 1) { | |
value += rt / c | |
} else { | |
value += rt * Math.pow(2, 1 - eBias) | |
} | |
if (value * c >= 2) { | |
e++ | |
c /= 2 | |
} | |
if (e + eBias >= eMax) { | |
m = 0 | |
e = eMax | |
} else if (e + eBias >= 1) { | |
m = (value * c - 1) * Math.pow(2, mLen) | |
e = e + eBias | |
} else { | |
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) | |
e = 0 | |
} | |
} | |
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} | |
e = (e << mLen) | m | |
eLen += mLen | |
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} | |
buffer[offset + i - d] |= s * 128 | |
} | |
},{}],4:[function(require,module,exports){ | |
var toString = {}.toString; | |
module.exports = Array.isArray || function (arr) { | |
return toString.call(arr) == '[object Array]'; | |
}; | |
},{}],5:[function(require,module,exports){ | |
"use strict" | |
module.exports = KDTHeap | |
var pool = require("typedarray-pool") | |
function heapParent(i) { | |
if(i & 1) { | |
return (i - 1) >> 1 | |
} | |
return (i >> 1) - 1 | |
} | |
function KDTHeap(n, d) { | |
this.count = 0 | |
this.dataSize = d | |
this.index = pool.mallocInt32(n) | |
this.data = pool.mallocFloat64(n*d) | |
} | |
var proto = KDTHeap.prototype | |
proto.heapSwap = function(_i,_j) { | |
var data = this.data | |
var index = this.index | |
var d = this.dataSize | |
var tmp = index[_i] | |
index[_i] = index[_j] | |
index[_j] = tmp | |
var aptr = d*_i | |
var bptr = d*_j | |
for(var _k=0; _k<d; ++_k) { | |
var t2 = data[aptr] | |
data[aptr] = data[bptr] | |
data[bptr] = t2 | |
aptr += 1 | |
bptr += 1 | |
} | |
} | |
proto.heapUp = function(i) { | |
var d = this.dataSize | |
var index = this.index | |
var data = this.data | |
var w = data[d*i] | |
while(i>0) { | |
var parent = heapParent(i) | |
if(parent >= 0) { | |
var pw = data[d*parent] | |
if(w < pw) { | |
this.heapSwap(i, parent) | |
i = parent | |
continue | |
} | |
} | |
break | |
} | |
} | |
proto.heapDown = function(i) { | |
var d = this.dataSize | |
var index = this.index | |
var data = this.data | |
var count = this.count | |
var w = data[d*i] | |
while(true) { | |
var tw = w | |
var left = 2*i + 1 | |
var right = 2*(i + 1) | |
var next = i | |
if(left < count) { | |
var lw = data[d*left] | |
if(lw < tw) { | |
next = left | |
tw = lw | |
} | |
} | |
if(right < count) { | |
var rw = data[d*right] | |
if(rw < tw) { | |
next = right | |
} | |
} | |
if(next === i) { | |
break | |
} | |
this.heapSwap(i, next) | |
i = next | |
} | |
} | |
//Clear item from top of heap | |
proto.pop = function() { | |
this.count -= 1 | |
this.heapSwap(0, this.count) | |
this.heapDown(0) | |
} | |
//Assume object already written to data | |
proto.push = function() { | |
this.heapUp(this.count) | |
this.count += 1 | |
} | |
proto.dispose = function() { | |
pool.freeInt32(this.index) | |
pool.freeFloat64(this.data) | |
} | |
},{"typedarray-pool":26}],6:[function(require,module,exports){ | |
/** | |
* Bit twiddling hacks for JavaScript. | |
* | |
* Author: Mikola Lysenko | |
* | |
* Ported from Stanford bit twiddling hack library: | |
* http://graphics.stanford.edu/~seander/bithacks.html | |
*/ | |
"use strict"; "use restrict"; | |
//Number of bits in an integer | |
var INT_BITS = 32; | |
//Constants | |
exports.INT_BITS = INT_BITS; | |
exports.INT_MAX = 0x7fffffff; | |
exports.INT_MIN = -1<<(INT_BITS-1); | |
//Returns -1, 0, +1 depending on sign of x | |
exports.sign = function(v) { | |
return (v > 0) - (v < 0); | |
} | |
//Computes absolute value of integer | |
exports.abs = function(v) { | |
var mask = v >> (INT_BITS-1); | |
return (v ^ mask) - mask; | |
} | |
//Computes minimum of integers x and y | |
exports.min = function(x, y) { | |
return y ^ ((x ^ y) & -(x < y)); | |
} | |
//Computes maximum of integers x and y | |
exports.max = function(x, y) { | |
return x ^ ((x ^ y) & -(x < y)); | |
} | |
//Checks if a number is a power of two | |
exports.isPow2 = function(v) { | |
return !(v & (v-1)) && (!!v); | |
} | |
//Computes log base 2 of v | |
exports.log2 = function(v) { | |
var r, shift; | |
r = (v > 0xFFFF) << 4; v >>>= r; | |
shift = (v > 0xFF ) << 3; v >>>= shift; r |= shift; | |
shift = (v > 0xF ) << 2; v >>>= shift; r |= shift; | |
shift = (v > 0x3 ) << 1; v >>>= shift; r |= shift; | |
return r | (v >> 1); | |
} | |
//Computes log base 10 of v | |
exports.log10 = function(v) { | |
return (v >= 1000000000) ? 9 : (v >= 100000000) ? 8 : (v >= 10000000) ? 7 : | |
(v >= 1000000) ? 6 : (v >= 100000) ? 5 : (v >= 10000) ? 4 : | |
(v >= 1000) ? 3 : (v >= 100) ? 2 : (v >= 10) ? 1 : 0; | |
} | |
//Counts number of bits | |
exports.popCount = function(v) { | |
v = v - ((v >>> 1) & 0x55555555); | |
v = (v & 0x33333333) + ((v >>> 2) & 0x33333333); | |
return ((v + (v >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24; | |
} | |
//Counts number of trailing zeros | |
function countTrailingZeros(v) { | |
var c = 32; | |
v &= -v; | |
if (v) c--; | |
if (v & 0x0000FFFF) c -= 16; | |
if (v & 0x00FF00FF) c -= 8; | |
if (v & 0x0F0F0F0F) c -= 4; | |
if (v & 0x33333333) c -= 2; | |
if (v & 0x55555555) c -= 1; | |
return c; | |
} | |
exports.countTrailingZeros = countTrailingZeros; | |
//Rounds to next power of 2 | |
exports.nextPow2 = function(v) { | |
v += v === 0; | |
--v; | |
v |= v >>> 1; | |
v |= v >>> 2; | |
v |= v >>> 4; | |
v |= v >>> 8; | |
v |= v >>> 16; | |
return v + 1; | |
} | |
//Rounds down to previous power of 2 | |
exports.prevPow2 = function(v) { | |
v |= v >>> 1; | |
v |= v >>> 2; | |
v |= v >>> 4; | |
v |= v >>> 8; | |
v |= v >>> 16; | |
return v - (v>>>1); | |
} | |
//Computes parity of word | |
exports.parity = function(v) { | |
v ^= v >>> 16; | |
v ^= v >>> 8; | |
v ^= v >>> 4; | |
v &= 0xf; | |
return (0x6996 >>> v) & 1; | |
} | |
var REVERSE_TABLE = new Array(256); | |
(function(tab) { | |
for(var i=0; i<256; ++i) { | |
var v = i, r = i, s = 7; | |
for (v >>>= 1; v; v >>>= 1) { | |
r <<= 1; | |
r |= v & 1; | |
--s; | |
} | |
tab[i] = (r << s) & 0xff; | |
} | |
})(REVERSE_TABLE); | |
//Reverse bits in a 32 bit word | |
exports.reverse = function(v) { | |
return (REVERSE_TABLE[ v & 0xff] << 24) | | |
(REVERSE_TABLE[(v >>> 8) & 0xff] << 16) | | |
(REVERSE_TABLE[(v >>> 16) & 0xff] << 8) | | |
REVERSE_TABLE[(v >>> 24) & 0xff]; | |
} | |
//Interleave bits of 2 coordinates with 16 bits. Useful for fast quadtree codes | |
exports.interleave2 = function(x, y) { | |
x &= 0xFFFF; | |
x = (x | (x << 8)) & 0x00FF00FF; | |
x = (x | (x << 4)) & 0x0F0F0F0F; | |
x = (x | (x << 2)) & 0x33333333; | |
x = (x | (x << 1)) & 0x55555555; | |
y &= 0xFFFF; | |
y = (y | (y << 8)) & 0x00FF00FF; | |
y = (y | (y << 4)) & 0x0F0F0F0F; | |
y = (y | (y << 2)) & 0x33333333; | |
y = (y | (y << 1)) & 0x55555555; | |
return x | (y << 1); | |
} | |
//Extracts the nth interleaved component | |
exports.deinterleave2 = function(v, n) { | |
v = (v >>> n) & 0x55555555; | |
v = (v | (v >>> 1)) & 0x33333333; | |
v = (v | (v >>> 2)) & 0x0F0F0F0F; | |
v = (v | (v >>> 4)) & 0x00FF00FF; | |
v = (v | (v >>> 16)) & 0x000FFFF; | |
return (v << 16) >> 16; | |
} | |
//Interleave bits of 3 coordinates, each with 10 bits. Useful for fast octree codes | |
exports.interleave3 = function(x, y, z) { | |
x &= 0x3FF; | |
x = (x | (x<<16)) & 4278190335; | |
x = (x | (x<<8)) & 251719695; | |
x = (x | (x<<4)) & 3272356035; | |
x = (x | (x<<2)) & 1227133513; | |
y &= 0x3FF; | |
y = (y | (y<<16)) & 4278190335; | |
y = (y | (y<<8)) & 251719695; | |
y = (y | (y<<4)) & 3272356035; | |
y = (y | (y<<2)) & 1227133513; | |
x |= (y << 1); | |
z &= 0x3FF; | |
z = (z | (z<<16)) & 4278190335; | |
z = (z | (z<<8)) & 251719695; | |
z = (z | (z<<4)) & 3272356035; | |
z = (z | (z<<2)) & 1227133513; | |
return x | (z << 2); | |
} | |
//Extracts nth interleaved component of a 3-tuple | |
exports.deinterleave3 = function(v, n) { | |
v = (v >>> n) & 1227133513; | |
v = (v | (v>>>2)) & 3272356035; | |
v = (v | (v>>>4)) & 251719695; | |
v = (v | (v>>>8)) & 4278190335; | |
v = (v | (v>>>16)) & 0x3FF; | |
return (v<<22)>>22; | |
} | |
//Computes next combination in colexicographic order (this is mistakenly called nextPermutation on the bit twiddling hacks page) | |
exports.nextCombination = function(v) { | |
var t = v | (v - 1); | |
return (t + 1) | (((~t & -~t) - 1) >>> (countTrailingZeros(v) + 1)); | |
} | |
},{}],7:[function(require,module,exports){ | |
"use strict" | |
var bits = require("bit-twiddle") | |
function rootInorder(n) { | |
var ptree = (bits.nextPow2(n+1)>>>1) - 1 | |
var f = n - ptree | |
if(bits.nextPow2(f)-1 >= ptree) { | |
return ptree | |
} | |
return (ptree>>>1)+f | |
} | |
exports.root = rootInorder | |
function beginInorder(n) { | |
return 0 | |
} | |
exports.begin = beginInorder | |
function endInorder(n) { | |
return n-1 | |
} | |
exports.end = endInorder | |
//This is really horrible because n is not necessarily a power of 2 | |
// If it was, we could just do: | |
// | |
// height = bits.countTrailingZeros(~x) | |
// | |
// Instead, we just binary search because doing the right thing here is way too complicated. | |
function heightInorder(n, x) { | |
if(n <= 0) { | |
return 0 | |
} | |
var r = rootInorder(n) | |
if(x > r) { | |
return heightInorder(n-r-1, x-r-1) | |
} else if(x === r) { | |
return bits.log2(n) | |
} | |
return heightInorder(r, x) | |
} | |
exports.height = heightInorder | |
function prevInorder(n, x) { | |
return Math.max(x-1,0) | |
} | |
exports.prev = prevInorder | |
function nextInorder(n, x) { | |
return Math.min(x+1,n-1) | |
} | |
exports.next = nextInorder | |
//The version for n = (1<<k)-1: | |
// | |
// parent = (x & ~(1<<(h+1))) + (1<<h) | |
// | |
function parentInorder(n, x) { | |
if(n <= 0) { | |
return -1 | |
} | |
var r = rootInorder(n) | |
if(x > r) { | |
var q = parentInorder(n-r-1, x-r-1) | |
if(q < 0) { | |
return r | |
} else { | |
return q + r + 1 | |
} | |
} else if(x === r) { | |
return -1 | |
} | |
var q = parentInorder(r, x) | |
if(q < 0) { | |
return r | |
} | |
return q | |
} | |
exports.parent = parentInorder | |
//Again, we get screwed because n is not a power of two -1. If it was, we could do: | |
// | |
// left = x - (1 << (h-1) ) | |
// | |
// Where h is the height of the node | |
// | |
function leftInorder(n, x) { | |
if(n <= 0) { | |
return 0 | |
} | |
var r = rootInorder(n) | |
if(x > r) { | |
return leftInorder(n-r-1, x-r-1) + r + 1 | |
} else if(x === r) { | |
return rootInorder(x) | |
} | |
return leftInorder(r, x) | |
} | |
exports.left = leftInorder | |
//for power of two minus one: | |
// | |
// right = x + (1<<(h-1)) | |
// | |
function rightInorder(n, x) { | |
if(n <= 0) { | |
return 0 | |
} | |
var r = rootInorder(n) | |
if(x > r) { | |
return rightInorder(n-r-1, x-r-1) + r + 1 | |
} else if(x === r) { | |
return rootInorder(n-r-1) + r + 1 | |
} | |
return rightInorder(r, x) | |
} | |
exports.right = rightInorder | |
function leafInorder(n, x) { | |
return heightInorder(n, x) === 0 | |
} | |
exports.leaf = leafInorder | |
function loInorder(n, x) { | |
n |= 0 | |
x |= 0 | |
var l = 0 | |
while(n > 1) { | |
var r = rootInorder(n) | |
if(x > r) { | |
l += r + 1 | |
n -= r + 1 | |
x -= r + 1 | |
} else if(x === r) { | |
break | |
} else { | |
n = r | |
} | |
} | |
return l | |
} | |
exports.lo = loInorder | |
function hiInorder(n, x) { | |
n |= 0 | |
x |= 0 | |
var l = 0 | |
while(n > 1) { | |
var r = rootInorder(n) | |
if(x > r) { | |
l += r + 1 | |
n -= r + 1 | |
x -= r + 1 | |
} else if(x === r) { | |
l += n-1 | |
break | |
} else { | |
n = r | |
} | |
} | |
return l | |
} | |
exports.hi = hiInorder | |
},{"bit-twiddle":8}],8:[function(require,module,exports){ | |
arguments[4][6][0].apply(exports,arguments) | |
},{"dup":6}],9:[function(require,module,exports){ | |
"use strict" | |
var compile = require("cwise-compiler") | |
var EmptyProc = { | |
body: "", | |
args: [], | |
thisVars: [], | |
localVars: [] | |
} | |
function fixup(x) { | |
if(!x) { | |
return EmptyProc | |
} | |
for(var i=0; i<x.args.length; ++i) { | |
var a = x.args[i] | |
if(i === 0) { | |
x.args[i] = {name: a, lvalue:true, rvalue: !!x.rvalue, count:x.count||1 } | |
} else { | |
x.args[i] = {name: a, lvalue:false, rvalue:true, count: 1} | |
} | |
} | |
if(!x.thisVars) { | |
x.thisVars = [] | |
} | |
if(!x.localVars) { | |
x.localVars = [] | |
} | |
return x | |
} | |
function pcompile(user_args) { | |
return compile({ | |
args: user_args.args, | |
pre: fixup(user_args.pre), | |
body: fixup(user_args.body), | |
post: fixup(user_args.proc), | |
funcName: user_args.funcName | |
}) | |
} | |
function makeOp(user_args) { | |
var args = [] | |
for(var i=0; i<user_args.args.length; ++i) { | |
args.push("a"+i) | |
} | |
var wrapper = new Function("P", [ | |
"return function ", user_args.funcName, "_ndarrayops(", args.join(","), ") {P(", args.join(","), ");return a0}" | |
].join("")) | |
return wrapper(pcompile(user_args)) | |
} | |
var assign_ops = { | |
add: "+", | |
sub: "-", | |
mul: "*", | |
div: "/", | |
mod: "%", | |
band: "&", | |
bor: "|", | |
bxor: "^", | |
lshift: "<<", | |
rshift: ">>", | |
rrshift: ">>>" | |
} | |
;(function(){ | |
for(var id in assign_ops) { | |
var op = assign_ops[id] | |
exports[id] = makeOp({ | |
args: ["array","array","array"], | |
body: {args:["a","b","c"], | |
body: "a=b"+op+"c"}, | |
funcName: id | |
}) | |
exports[id+"eq"] = makeOp({ | |
args: ["array","array"], | |
body: {args:["a","b"], | |
body:"a"+op+"=b"}, | |
rvalue: true, | |
funcName: id+"eq" | |
}) | |
exports[id+"s"] = makeOp({ | |
args: ["array", "array", "scalar"], | |
body: {args:["a","b","s"], | |
body:"a=b"+op+"s"}, | |
funcName: id+"s" | |
}) | |
exports[id+"seq"] = makeOp({ | |
args: ["array","scalar"], | |
body: {args:["a","s"], | |
body:"a"+op+"=s"}, | |
rvalue: true, | |
funcName: id+"seq" | |
}) | |
} | |
})(); | |
var unary_ops = { | |
not: "!", | |
bnot: "~", | |
neg: "-", | |
recip: "1.0/" | |
} | |
;(function(){ | |
for(var id in unary_ops) { | |
var op = unary_ops[id] | |
exports[id] = makeOp({ | |
args: ["array", "array"], | |
body: {args:["a","b"], | |
body:"a="+op+"b"}, | |
funcName: id | |
}) | |
exports[id+"eq"] = makeOp({ | |
args: ["array"], | |
body: {args:["a"], | |
body:"a="+op+"a"}, | |
rvalue: true, | |
count: 2, | |
funcName: id+"eq" | |
}) | |
} | |
})(); | |
var binary_ops = { | |
and: "&&", | |
or: "||", | |
eq: "===", | |
neq: "!==", | |
lt: "<", | |
gt: ">", | |
leq: "<=", | |
geq: ">=" | |
} | |
;(function() { | |
for(var id in binary_ops) { | |
var op = binary_ops[id] | |
exports[id] = makeOp({ | |
args: ["array","array","array"], | |
body: {args:["a", "b", "c"], | |
body:"a=b"+op+"c"}, | |
funcName: id | |
}) | |
exports[id+"s"] = makeOp({ | |
args: ["array","array","scalar"], | |
body: {args:["a", "b", "s"], | |
body:"a=b"+op+"s"}, | |
funcName: id+"s" | |
}) | |
exports[id+"eq"] = makeOp({ | |
args: ["array", "array"], | |
body: {args:["a", "b"], | |
body:"a=a"+op+"b"}, | |
rvalue:true, | |
count:2, | |
funcName: id+"eq" | |
}) | |
exports[id+"seq"] = makeOp({ | |
args: ["array", "scalar"], | |
body: {args:["a","s"], | |
body:"a=a"+op+"s"}, | |
rvalue:true, | |
count:2, | |
funcName: id+"seq" | |
}) | |
} | |
})(); | |
var math_unary = [ | |
"abs", | |
"acos", | |
"asin", | |
"atan", | |
"ceil", | |
"cos", | |
"exp", | |
"floor", | |
"log", | |
"round", | |
"sin", | |
"sqrt", | |
"tan" | |
] | |
;(function() { | |
for(var i=0; i<math_unary.length; ++i) { | |
var f = math_unary[i] | |
exports[f] = makeOp({ | |
args: ["array", "array"], | |
pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]}, | |
body: {args:["a","b"], body:"a=this_f(b)", thisVars:["this_f"]}, | |
funcName: f | |
}) | |
exports[f+"eq"] = makeOp({ | |
args: ["array"], | |
pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]}, | |
body: {args: ["a"], body:"a=this_f(a)", thisVars:["this_f"]}, | |
rvalue: true, | |
count: 2, | |
funcName: f+"eq" | |
}) | |
} | |
})(); | |
var math_comm = [ | |
"max", | |
"min", | |
"atan2", | |
"pow" | |
] | |
;(function(){ | |
for(var i=0; i<math_comm.length; ++i) { | |
var f= math_comm[i] | |
exports[f] = makeOp({ | |
args:["array", "array", "array"], | |
pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]}, | |
body: {args:["a","b","c"], body:"a=this_f(b,c)", thisVars:["this_f"]}, | |
funcName: f | |
}) | |
exports[f+"s"] = makeOp({ | |
args:["array", "array", "scalar"], | |
pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]}, | |
body: {args:["a","b","c"], body:"a=this_f(b,c)", thisVars:["this_f"]}, | |
funcName: f+"s" | |
}) | |
exports[f+"eq"] = makeOp({ args:["array", "array"], | |
pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]}, | |
body: {args:["a","b"], body:"a=this_f(a,b)", thisVars:["this_f"]}, | |
rvalue: true, | |
count: 2, | |
funcName: f+"eq" | |
}) | |
exports[f+"seq"] = makeOp({ args:["array", "scalar"], | |
pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]}, | |
body: {args:["a","b"], body:"a=this_f(a,b)", thisVars:["this_f"]}, | |
rvalue:true, | |
count:2, | |
funcName: f+"seq" | |
}) | |
} | |
})(); | |
var math_noncomm = [ | |
"atan2", | |
"pow" | |
] | |
;(function(){ | |
for(var i=0; i<math_noncomm.length; ++i) { | |
var f= math_noncomm[i] | |
exports[f+"op"] = makeOp({ | |
args:["array", "array", "array"], | |
pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]}, | |
body: {args:["a","b","c"], body:"a=this_f(c,b)", thisVars:["this_f"]}, | |
funcName: f+"op" | |
}) | |
exports[f+"ops"] = makeOp({ | |
args:["array", "array", "scalar"], | |
pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]}, | |
body: {args:["a","b","c"], body:"a=this_f(c,b)", thisVars:["this_f"]}, | |
funcName: f+"ops" | |
}) | |
exports[f+"opeq"] = makeOp({ args:["array", "array"], | |
pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]}, | |
body: {args:["a","b"], body:"a=this_f(b,a)", thisVars:["this_f"]}, | |
rvalue: true, | |
count: 2, | |
funcName: f+"opeq" | |
}) | |
exports[f+"opseq"] = makeOp({ args:["array", "scalar"], | |
pre: {args:[], body:"this_f=Math."+f, thisVars:["this_f"]}, | |
body: {args:["a","b"], body:"a=this_f(b,a)", thisVars:["this_f"]}, | |
rvalue:true, | |
count:2, | |
funcName: f+"opseq" | |
}) | |
} | |
})(); | |
exports.any = compile({ | |
args:["array"], | |
pre: EmptyProc, | |
body: {args:[{name:"a", lvalue:false, rvalue:true, count:1}], body: "if(a){return true}", localVars: [], thisVars: []}, | |
post: {args:[], localVars:[], thisVars:[], body:"return false"}, | |
funcName: "any" | |
}) | |
exports.all = compile({ | |
args:["array"], | |
pre: EmptyProc, | |
body: {args:[{name:"x", lvalue:false, rvalue:true, count:1}], body: "if(!x){return false}", localVars: [], thisVars: []}, | |
post: {args:[], localVars:[], thisVars:[], body:"return true"}, | |
funcName: "all" | |
}) | |
exports.sum = compile({ | |
args:["array"], | |
pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=0"}, | |
body: {args:[{name:"a", lvalue:false, rvalue:true, count:1}], body: "this_s+=a", localVars: [], thisVars: ["this_s"]}, | |
post: {args:[], localVars:[], thisVars:["this_s"], body:"return this_s"}, | |
funcName: "sum" | |
}) | |
exports.prod = compile({ | |
args:["array"], | |
pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=1"}, | |
body: {args:[{name:"a", lvalue:false, rvalue:true, count:1}], body: "this_s*=a", localVars: [], thisVars: ["this_s"]}, | |
post: {args:[], localVars:[], thisVars:["this_s"], body:"return this_s"}, | |
funcName: "prod" | |
}) | |
exports.norm2squared = compile({ | |
args:["array"], | |
pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=0"}, | |
body: {args:[{name:"a", lvalue:false, rvalue:true, count:2}], body: "this_s+=a*a", localVars: [], thisVars: ["this_s"]}, | |
post: {args:[], localVars:[], thisVars:["this_s"], body:"return this_s"}, | |
funcName: "norm2squared" | |
}) | |
exports.norm2 = compile({ | |
args:["array"], | |
pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=0"}, | |
body: {args:[{name:"a", lvalue:false, rvalue:true, count:2}], body: "this_s+=a*a", localVars: [], thisVars: ["this_s"]}, | |
post: {args:[], localVars:[], thisVars:["this_s"], body:"return Math.sqrt(this_s)"}, | |
funcName: "norm2" | |
}) | |
exports.norminf = compile({ | |
args:["array"], | |
pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=0"}, | |
body: {args:[{name:"a", lvalue:false, rvalue:true, count:4}], body:"if(-a>this_s){this_s=-a}else if(a>this_s){this_s=a}", localVars: [], thisVars: ["this_s"]}, | |
post: {args:[], localVars:[], thisVars:["this_s"], body:"return this_s"}, | |
funcName: "norminf" | |
}) | |
exports.norm1 = compile({ | |
args:["array"], | |
pre: {args:[], localVars:[], thisVars:["this_s"], body:"this_s=0"}, | |
body: {args:[{name:"a", lvalue:false, rvalue:true, count:3}], body: "this_s+=a<0?-a:a", localVars: [], thisVars: ["this_s"]}, | |
post: {args:[], localVars:[], thisVars:["this_s"], body:"return this_s"}, | |
funcName: "norm1" | |
}) | |
exports.sup = compile({ | |
args: [ "array" ], | |
pre: | |
{ body: "this_h=-Infinity", | |
args: [], | |
thisVars: [ "this_h" ], | |
localVars: [] }, | |
body: | |
{ body: "if(_inline_1_arg0_>this_h)this_h=_inline_1_arg0_", | |
args: [{"name":"_inline_1_arg0_","lvalue":false,"rvalue":true,"count":2} ], | |
thisVars: [ "this_h" ], | |
localVars: [] }, | |
post: | |
{ body: "return this_h", | |
args: [], | |
thisVars: [ "this_h" ], | |
localVars: [] } | |
}) | |
exports.inf = compile({ | |
args: [ "array" ], | |
pre: | |
{ body: "this_h=Infinity", | |
args: [], | |
thisVars: [ "this_h" ], | |
localVars: [] }, | |
body: | |
{ body: "if(_inline_1_arg0_<this_h)this_h=_inline_1_arg0_", | |
args: [{"name":"_inline_1_arg0_","lvalue":false,"rvalue":true,"count":2} ], | |
thisVars: [ "this_h" ], | |
localVars: [] }, | |
post: | |
{ body: "return this_h", | |
args: [], | |
thisVars: [ "this_h" ], | |
localVars: [] } | |
}) | |
exports.argmin = compile({ | |
args:["index","array","shape"], | |
pre:{ | |
body:"{this_v=Infinity;this_i=_inline_0_arg2_.slice(0)}", | |
args:[ | |
{name:"_inline_0_arg0_",lvalue:false,rvalue:false,count:0}, | |
{name:"_inline_0_arg1_",lvalue:false,rvalue:false,count:0}, | |
{name:"_inline_0_arg2_",lvalue:false,rvalue:true,count:1} | |
], | |
thisVars:["this_i","this_v"], | |
localVars:[]}, | |
body:{ | |
body:"{if(_inline_1_arg1_<this_v){this_v=_inline_1_arg1_;for(var _inline_1_k=0;_inline_1_k<_inline_1_arg0_.length;++_inline_1_k){this_i[_inline_1_k]=_inline_1_arg0_[_inline_1_k]}}}", | |
args:[ | |
{name:"_inline_1_arg0_",lvalue:false,rvalue:true,count:2}, | |
{name:"_inline_1_arg1_",lvalue:false,rvalue:true,count:2}], | |
thisVars:["this_i","this_v"], | |
localVars:["_inline_1_k"]}, | |
post:{ | |
body:"{return this_i}", | |
args:[], | |
thisVars:["this_i"], | |
localVars:[]} | |
}) | |
exports.argmax = compile({ | |
args:["index","array","shape"], | |
pre:{ | |
body:"{this_v=-Infinity;this_i=_inline_0_arg2_.slice(0)}", | |
args:[ | |
{name:"_inline_0_arg0_",lvalue:false,rvalue:false,count:0}, | |
{name:"_inline_0_arg1_",lvalue:false,rvalue:false,count:0}, | |
{name:"_inline_0_arg2_",lvalue:false,rvalue:true,count:1} | |
], | |
thisVars:["this_i","this_v"], | |
localVars:[]}, | |
body:{ | |
body:"{if(_inline_1_arg1_>this_v){this_v=_inline_1_arg1_;for(var _inline_1_k=0;_inline_1_k<_inline_1_arg0_.length;++_inline_1_k){this_i[_inline_1_k]=_inline_1_arg0_[_inline_1_k]}}}", | |
args:[ | |
{name:"_inline_1_arg0_",lvalue:false,rvalue:true,count:2}, | |
{name:"_inline_1_arg1_",lvalue:false,rvalue:true,count:2}], | |
thisVars:["this_i","this_v"], | |
localVars:["_inline_1_k"]}, | |
post:{ | |
body:"{return this_i}", | |
args:[], | |
thisVars:["this_i"], | |
localVars:[]} | |
}) | |
exports.random = makeOp({ | |
args: ["array"], | |
pre: {args:[], body:"this_f=Math.random", thisVars:["this_f"]}, | |
body: {args: ["a"], body:"a=this_f()", thisVars:["this_f"]}, | |
funcName: "random" | |
}) | |
exports.assign = makeOp({ | |
args:["array", "array"], | |
body: {args:["a", "b"], body:"a=b"}, | |
funcName: "assign" }) | |
exports.assigns = makeOp({ | |
args:["array", "scalar"], | |
body: {args:["a", "b"], body:"a=b"}, | |
funcName: "assigns" }) | |
exports.equals = compile({ | |
args:["array", "array"], | |
pre: EmptyProc, | |
body: {args:[{name:"x", lvalue:false, rvalue:true, count:1}, | |
{name:"y", lvalue:false, rvalue:true, count:1}], | |
body: "if(x!==y){return false}", | |
localVars: [], | |
thisVars: []}, | |
post: {args:[], localVars:[], thisVars:[], body:"return true"}, | |
funcName: "equals" | |
}) | |
},{"cwise-compiler":10}],10:[function(require,module,exports){ | |
"use strict" | |
var createThunk = require("./lib/thunk.js") | |
function Procedure() { | |
this.argTypes = [] | |
this.shimArgs = [] | |
this.arrayArgs = [] | |
this.arrayBlockIndices = [] | |
this.scalarArgs = [] | |
this.offsetArgs = [] | |
this.offsetArgIndex = [] | |
this.indexArgs = [] | |
this.shapeArgs = [] | |
this.funcName = "" | |
this.pre = null | |
this.body = null | |
this.post = null | |
this.debug = false | |
} | |
function compileCwise(user_args) { | |
//Create procedure | |
var proc = new Procedure() | |
//Parse blocks | |
proc.pre = user_args.pre | |
proc.body = user_args.body | |
proc.post = user_args.post | |
//Parse arguments | |
var proc_args = user_args.args.slice(0) | |
proc.argTypes = proc_args | |
for(var i=0; i<proc_args.length; ++i) { | |
var arg_type = proc_args[i] | |
if(arg_type === "array" || (typeof arg_type === "object" && arg_type.blockIndices)) { | |
proc.argTypes[i] = "array" | |
proc.arrayArgs.push(i) | |
proc.arrayBlockIndices.push(arg_type.blockIndices ? arg_type.blockIndices : 0) | |
proc.shimArgs.push("array" + i) | |
if(i < proc.pre.args.length && proc.pre.args[i].count>0) { | |
throw new Error("cwise: pre() block may not reference array args") | |
} | |
if(i < proc.post.args.length && proc.post.args[i].count>0) { | |
throw new Error("cwise: post() block may not reference array args") | |
} | |
} else if(arg_type === "scalar") { | |
proc.scalarArgs.push(i) | |
proc.shimArgs.push("scalar" + i) | |
} else if(arg_type === "index") { | |
proc.indexArgs.push(i) | |
if(i < proc.pre.args.length && proc.pre.args[i].count > 0) { | |
throw new Error("cwise: pre() block may not reference array index") | |
} | |
if(i < proc.body.args.length && proc.body.args[i].lvalue) { | |
throw new Error("cwise: body() block may not write to array index") | |
} | |
if(i < proc.post.args.length && proc.post.args[i].count > 0) { | |
throw new Error("cwise: post() block may not reference array index") | |
} | |
} else if(arg_type === "shape") { | |
proc.shapeArgs.push(i) | |
if(i < proc.pre.args.length && proc.pre.args[i].lvalue) { | |
throw new Error("cwise: pre() block may not write to array shape") | |
} | |
if(i < proc.body.args.length && proc.body.args[i].lvalue) { | |
throw new Error("cwise: body() block may not write to array shape") | |
} | |
if(i < proc.post.args.length && proc.post.args[i].lvalue) { | |
throw new Error("cwise: post() block may not write to array shape") | |
} | |
} else if(typeof arg_type === "object" && arg_type.offset) { | |
proc.argTypes[i] = "offset" | |
proc.offsetArgs.push({ array: arg_type.array, offset:arg_type.offset }) | |
proc.offsetArgIndex.push(i) | |
} else { | |
throw new Error("cwise: Unknown argument type " + proc_args[i]) | |
} | |
} | |
//Make sure at least one array argument was specified | |
if(proc.arrayArgs.length <= 0) { | |
throw new Error("cwise: No array arguments specified") | |
} | |
//Make sure arguments are correct | |
if(proc.pre.args.length > proc_args.length) { | |
throw new Error("cwise: Too many arguments in pre() block") | |
} | |
if(proc.body.args.length > proc_args.length) { | |
throw new Error("cwise: Too many arguments in body() block") | |
} | |
if(proc.post.args.length > proc_args.length) { | |
throw new Error("cwise: Too many arguments in post() block") | |
} | |
//Check debug flag | |
proc.debug = !!user_args.printCode || !!user_args.debug | |
//Retrieve name | |
proc.funcName = user_args.funcName || "cwise" | |
//Read in block size | |
proc.blockSize = user_args.blockSize || 64 | |
return createThunk(proc) | |
} | |
module.exports = compileCwise | |
},{"./lib/thunk.js":12}],11:[function(require,module,exports){ | |
"use strict" | |
var uniq = require("uniq") | |
// This function generates very simple loops analogous to how you typically traverse arrays (the outermost loop corresponds to the slowest changing index, the innermost loop to the fastest changing index) | |
// TODO: If two arrays have the same strides (and offsets) there is potential for decreasing the number of "pointers" and related variables. The drawback is that the type signature would become more specific and that there would thus be less potential for caching, but it might still be worth it, especially when dealing with large numbers of arguments. | |
function innerFill(order, proc, body) { | |
var dimension = order.length | |
, nargs = proc.arrayArgs.length | |
, has_index = proc.indexArgs.length>0 | |
, code = [] | |
, vars = [] | |
, idx=0, pidx=0, i, j | |
for(i=0; i<dimension; ++i) { // Iteration variables | |
vars.push(["i",i,"=0"].join("")) | |
} | |
//Compute scan deltas | |
for(j=0; j<nargs; ++j) { | |
for(i=0; i<dimension; ++i) { | |
pidx = idx | |
idx = order[i] | |
if(i === 0) { // The innermost/fastest dimension's delta is simply its stride | |
vars.push(["d",j,"s",i,"=t",j,"p",idx].join("")) | |
} else { // For other dimensions the delta is basically the stride minus something which essentially "rewinds" the previous (more inner) dimension | |
vars.push(["d",j,"s",i,"=(t",j,"p",idx,"-s",pidx,"*t",j,"p",pidx,")"].join("")) | |
} | |
} | |
} | |
code.push("var " + vars.join(",")) | |
//Scan loop | |
for(i=dimension-1; i>=0; --i) { // Start at largest stride and work your way inwards | |
idx = order[i] | |
code.push(["for(i",i,"=0;i",i,"<s",idx,";++i",i,"){"].join("")) | |
} | |
//Push body of inner loop | |
code.push(body) | |
//Advance scan pointers | |
for(i=0; i<dimension; ++i) { | |
pidx = idx | |
idx = order[i] | |
for(j=0; j<nargs; ++j) { | |
code.push(["p",j,"+=d",j,"s",i].join("")) | |
} | |
if(has_index) { | |
if(i > 0) { | |
code.push(["index[",pidx,"]-=s",pidx].join("")) | |
} | |
code.push(["++index[",idx,"]"].join("")) | |
} | |
code.push("}") | |
} | |
return code.join("\n") | |
} | |
// Generate "outer" loops that loop over blocks of data, applying "inner" loops to the blocks by manipulating the local variables in such a way that the inner loop only "sees" the current block. | |
// TODO: If this is used, then the previous declaration (done by generateCwiseOp) of s* is essentially unnecessary. | |
// I believe the s* are not used elsewhere (in particular, I don't think they're used in the pre/post parts and "shape" is defined independently), so it would be possible to make defining the s* dependent on what loop method is being used. | |
function outerFill(matched, order, proc, body) { | |
var dimension = order.length | |
, nargs = proc.arrayArgs.length | |
, blockSize = proc.blockSize | |
, has_index = proc.indexArgs.length > 0 | |
, code = [] | |
for(var i=0; i<nargs; ++i) { | |
code.push(["var offset",i,"=p",i].join("")) | |
} | |
//Generate loops for unmatched dimensions | |
// The order in which these dimensions are traversed is fairly arbitrary (from small stride to large stride, for the first argument) | |
// TODO: It would be nice if the order in which these loops are placed would also be somehow "optimal" (at the very least we should check that it really doesn't hurt us if they're not). | |
for(var i=matched; i<dimension; ++i) { | |
code.push(["for(var j"+i+"=SS[", order[i], "]|0;j", i, ">0;){"].join("")) // Iterate back to front | |
code.push(["if(j",i,"<",blockSize,"){"].join("")) // Either decrease j by blockSize (s = blockSize), or set it to zero (after setting s = j). | |
code.push(["s",order[i],"=j",i].join("")) | |
code.push(["j",i,"=0"].join("")) | |
code.push(["}else{s",order[i],"=",blockSize].join("")) | |
code.push(["j",i,"-=",blockSize,"}"].join("")) | |
if(has_index) { | |
code.push(["index[",order[i],"]=j",i].join("")) | |
} | |
} | |
for(var i=0; i<nargs; ++i) { | |
var indexStr = ["offset"+i] | |
for(var j=matched; j<dimension; ++j) { | |
indexStr.push(["j",j,"*t",i,"p",order[j]].join("")) | |
} | |
code.push(["p",i,"=(",indexStr.join("+"),")"].join("")) | |
} | |
code.push(innerFill(order, proc, body)) | |
for(var i=matched; i<dimension; ++i) { | |
code.push("}") | |
} | |
return code.join("\n") | |
} | |
//Count the number of compatible inner orders | |
// This is the length of the longest common prefix of the arrays in orders. | |
// Each array in orders lists the dimensions of the correspond ndarray in order of increasing stride. | |
// This is thus the maximum number of dimensions that can be efficiently traversed by simple nested loops for all arrays. | |
function countMatches(orders) { | |
var matched = 0, dimension = orders[0].length | |
while(matched < dimension) { | |
for(var j=1; j<orders.length; ++j) { | |
if(orders[j][matched] !== orders[0][matched]) { | |
return matched | |
} | |
} | |
++matched | |
} | |
return matched | |
} | |
//Processes a block according to the given data types | |
// Replaces variable names by different ones, either "local" ones (that are then ferried in and out of the given array) or ones matching the arguments that the function performing the ultimate loop will accept. | |
function processBlock(block, proc, dtypes) { | |
var code = block.body | |
var pre = [] | |
var post = [] | |
for(var i=0; i<block.args.length; ++i) { | |
var carg = block.args[i] | |
if(carg.count <= 0) { | |
continue | |
} | |
var re = new RegExp(carg.name, "g") | |
var ptrStr = "" | |
var arrNum = proc.arrayArgs.indexOf(i) | |
switch(proc.argTypes[i]) { | |
case "offset": | |
var offArgIndex = proc.offsetArgIndex.indexOf(i) | |
var offArg = proc.offsetArgs[offArgIndex] | |
arrNum = offArg.array | |
ptrStr = "+q" + offArgIndex // Adds offset to the "pointer" in the array | |
case "array": | |
ptrStr = "p" + arrNum + ptrStr | |
var localStr = "l" + i | |
var arrStr = "a" + arrNum | |
if (proc.arrayBlockIndices[arrNum] === 0) { // Argument to body is just a single value from this array | |
if(carg.count === 1) { // Argument/array used only once(?) | |
if(dtypes[arrNum] === "generic") { | |
if(carg.lvalue) { | |
pre.push(["var ", localStr, "=", arrStr, ".get(", ptrStr, ")"].join("")) // Is this necessary if the argument is ONLY used as an lvalue? (keep in mind that we can have a += something, so we would actually need to check carg.rvalue) | |
code = code.replace(re, localStr) | |
post.push([arrStr, ".set(", ptrStr, ",", localStr,")"].join("")) | |
} else { | |
code = code.replace(re, [arrStr, ".get(", ptrStr, ")"].join("")) | |
} | |
} else { | |
code = code.replace(re, [arrStr, "[", ptrStr, "]"].join("")) | |
} | |
} else if(dtypes[arrNum] === "generic") { | |
pre.push(["var ", localStr, "=", arrStr, ".get(", ptrStr, ")"].join("")) // TODO: Could we optimize by checking for carg.rvalue? | |
code = code.replace(re, localStr) | |
if(carg.lvalue) { | |
post.push([arrStr, ".set(", ptrStr, ",", localStr,")"].join("")) | |
} | |
} else { | |
pre.push(["var ", localStr, "=", arrStr, "[", ptrStr, "]"].join("")) // TODO: Could we optimize by checking for carg.rvalue? | |
code = code.replace(re, localStr) | |
if(carg.lvalue) { | |
post.push([arrStr, "[", ptrStr, "]=", localStr].join("")) | |
} | |
} | |
} else { // Argument to body is a "block" | |
var reStrArr = [carg.name], ptrStrArr = [ptrStr] | |
for(var j=0; j<Math.abs(proc.arrayBlockIndices[arrNum]); j++) { | |
reStrArr.push("\\s*\\[([^\\]]+)\\]") | |
ptrStrArr.push("$" + (j+1) + "*t" + arrNum + "b" + j) // Matched index times stride | |
} | |
re = new RegExp(reStrArr.join(""), "g") | |
ptrStr = ptrStrArr.join("+") | |
if(dtypes[arrNum] === "generic") { | |
/*if(carg.lvalue) { | |
pre.push(["var ", localStr, "=", arrStr, ".get(", ptrStr, ")"].join("")) // Is this necessary if the argument is ONLY used as an lvalue? (keep in mind that we can have a += something, so we would actually need to check carg.rvalue) | |
code = code.replace(re, localStr) | |
post.push([arrStr, ".set(", ptrStr, ",", localStr,")"].join("")) | |
} else { | |
code = code.replace(re, [arrStr, ".get(", ptrStr, ")"].join("")) | |
}*/ | |
throw new Error("cwise: Generic arrays not supported in combination with blocks!") | |
} else { | |
// This does not produce any local variables, even if variables are used multiple times. It would be possible to do so, but it would complicate things quite a bit. | |
code = code.replace(re, [arrStr, "[", ptrStr, "]"].join("")) | |
} | |
} | |
break | |
case "scalar": | |
code = code.replace(re, "Y" + proc.scalarArgs.indexOf(i)) | |
break | |
case "index": | |
code = code.replace(re, "index") | |
break | |
case "shape": | |
code = code.replace(re, "shape") | |
break | |
} | |
} | |
return [pre.join("\n"), code, post.join("\n")].join("\n").trim() | |
} | |
function typeSummary(dtypes) { | |
var summary = new Array(dtypes.length) | |
var allEqual = true | |
for(var i=0; i<dtypes.length; ++i) { | |
var t = dtypes[i] | |
var digits = t.match(/\d+/) | |
if(!digits) { | |
digits = "" | |
} else { | |
digits = digits[0] | |
} | |
if(t.charAt(0) === 0) { | |
summary[i] = "u" + t.charAt(1) + digits | |
} else { | |
summary[i] = t.charAt(0) + digits | |
} | |
if(i > 0) { | |
allEqual = allEqual && summary[i] === summary[i-1] | |
} | |
} | |
if(allEqual) { | |
return summary[0] | |
} | |
return summary.join("") | |
} | |
//Generates a cwise operator | |
function generateCWiseOp(proc, typesig) { | |
//Compute dimension | |
// Arrays get put first in typesig, and there are two entries per array (dtype and order), so this gets the number of dimensions in the first array arg. | |
var dimension = (typesig[1].length - Math.abs(proc.arrayBlockIndices[0]))|0 | |
var orders = new Array(proc.arrayArgs.length) | |
var dtypes = new Array(proc.arrayArgs.length) | |
for(var i=0; i<proc.arrayArgs.length; ++i) { | |
dtypes[i] = typesig[2*i] | |
orders[i] = typesig[2*i+1] | |
} | |
//Determine where block and loop indices start and end | |
var blockBegin = [], blockEnd = [] // These indices are exposed as blocks | |
var loopBegin = [], loopEnd = [] // These indices are iterated over | |
var loopOrders = [] // orders restricted to the loop indices | |
for(var i=0; i<proc.arrayArgs.length; ++i) { | |
if (proc.arrayBlockIndices[i]<0) { | |
loopBegin.push(0) | |
loopEnd.push(dimension) | |
blockBegin.push(dimension) | |
blockEnd.push(dimension+proc.arrayBlockIndices[i]) | |
} else { | |
loopBegin.push(proc.arrayBlockIndices[i]) // Non-negative | |
loopEnd.push(proc.arrayBlockIndices[i]+dimension) | |
blockBegin.push(0) | |
blockEnd.push(proc.arrayBlockIndices[i]) | |
} | |
var newOrder = [] | |
for(var j=0; j<orders[i].length; j++) { | |
if (loopBegin[i]<=orders[i][j] && orders[i][j]<loopEnd[i]) { | |
newOrder.push(orders[i][j]-loopBegin[i]) // If this is a loop index, put it in newOrder, subtracting loopBegin, to make sure that all loopOrders are using a common set of indices. | |
} | |
} | |
loopOrders.push(newOrder) | |
} | |
//First create arguments for procedure | |
var arglist = ["SS"] // SS is the overall shape over which we iterate | |
var code = ["'use strict'"] | |
var vars = [] | |
for(var j=0; j<dimension; ++j) { | |
vars.push(["s", j, "=SS[", j, "]"].join("")) // The limits for each dimension. | |
} | |
for(var i=0; i<proc.arrayArgs.length; ++i) { | |
arglist.push("a"+i) // Actual data array | |
arglist.push("t"+i) // Strides | |
arglist.push("p"+i) // Offset in the array at which the data starts (also used for iterating over the data) | |
for(var j=0; j<dimension; ++j) { // Unpack the strides into vars for looping | |
vars.push(["t",i,"p",j,"=t",i,"[",loopBegin[i]+j,"]"].join("")) | |
} | |
for(var j=0; j<Math.abs(proc.arrayBlockIndices[i]); ++j) { // Unpack the strides into vars for block iteration | |
vars.push(["t",i,"b",j,"=t",i,"[",blockBegin[i]+j,"]"].join("")) | |
} | |
} | |
for(var i=0; i<proc.scalarArgs.length; ++i) { | |
arglist.push("Y" + i) | |
} | |
if(proc.shapeArgs.length > 0) { | |
vars.push("shape=SS.slice(0)") // Makes the shape over which we iterate available to the user defined functions (so you can use width/height for example) | |
} | |
if(proc.indexArgs.length > 0) { | |
// Prepare an array to keep track of the (logical) indices, initialized to dimension zeroes. | |
var zeros = new Array(dimension) | |
for(var i=0; i<dimension; ++i) { | |
zeros[i] = "0" | |
} | |
vars.push(["index=[", zeros.join(","), "]"].join("")) | |
} | |
for(var i=0; i<proc.offsetArgs.length; ++i) { // Offset arguments used for stencil operations | |
var off_arg = proc.offsetArgs[i] | |
var init_string = [] | |
for(var j=0; j<off_arg.offset.length; ++j) { | |
if(off_arg.offset[j] === 0) { | |
continue | |
} else if(off_arg.offset[j] === 1) { | |
init_string.push(["t", off_arg.array, "p", j].join("")) | |
} else { | |
init_string.push([off_arg.offset[j], "*t", off_arg.array, "p", j].join("")) | |
} | |
} | |
if(init_string.length === 0) { | |
vars.push("q" + i + "=0") | |
} else { | |
vars.push(["q", i, "=", init_string.join("+")].join("")) | |
} | |
} | |
//Prepare this variables | |
var thisVars = uniq([].concat(proc.pre.thisVars) | |
.concat(proc.body.thisVars) | |
.concat(proc.post.thisVars)) | |
vars = vars.concat(thisVars) | |
code.push("var " + vars.join(",")) | |
for(var i=0; i<proc.arrayArgs.length; ++i) { | |
code.push("p"+i+"|=0") | |
} | |
//Inline prelude | |
if(proc.pre.body.length > 3) { | |
code.push(processBlock(proc.pre, proc, dtypes)) | |
} | |
//Process body | |
var body = processBlock(proc.body, proc, dtypes) | |
var matched = countMatches(loopOrders) | |
if(matched < dimension) { | |
code.push(outerFill(matched, loopOrders[0], proc, body)) // TODO: Rather than passing loopOrders[0], it might be interesting to look at passing an order that represents the majority of the arguments for example. | |
} else { | |
code.push(innerFill(loopOrders[0], proc, body)) | |
} | |
//Inline epilog | |
if(proc.post.body.length > 3) { | |
code.push(processBlock(proc.post, proc, dtypes)) | |
} | |
if(proc.debug) { | |
console.log("-----Generated cwise routine for ", typesig, ":\n" + code.join("\n") + "\n----------") | |
} | |
var loopName = [(proc.funcName||"unnamed"), "_cwise_loop_", orders[0].join("s"),"m",matched,typeSummary(dtypes)].join("") | |
var f = new Function(["function ",loopName,"(", arglist.join(","),"){", code.join("\n"),"} return ", loopName].join("")) | |
return f() | |
} | |
module.exports = generateCWiseOp | |
},{"uniq":13}],12:[function(require,module,exports){ | |
"use strict" | |
// The function below is called when constructing a cwise function object, and does the following: | |
// A function object is constructed which accepts as argument a compilation function and returns another function. | |
// It is this other function that is eventually returned by createThunk, and this function is the one that actually | |
// checks whether a certain pattern of arguments has already been used before and compiles new loops as needed. | |
// The compilation passed to the first function object is used for compiling new functions. | |
// Once this function object is created, it is called with compile as argument, where the first argument of compile | |
// is bound to "proc" (essentially containing a preprocessed version of the user arguments to cwise). | |
// So createThunk roughly works like this: | |
// function createThunk(proc) { | |
// var thunk = function(compileBound) { | |
// var CACHED = {} | |
// return function(arrays and scalars) { | |
// if (dtype and order of arrays in CACHED) { | |
// var func = CACHED[dtype and order of arrays] | |
// } else { | |
// var func = CACHED[dtype and order of arrays] = compileBound(dtype and order of arrays) | |
// } | |
// return func(arrays and scalars) | |
// } | |
// } | |
// return thunk(compile.bind1(proc)) | |
// } | |
var compile = require("./compile.js") | |
function createThunk(proc) { | |
var code = ["'use strict'", "var CACHED={}"] | |
var vars = [] | |
var thunkName = proc.funcName + "_cwise_thunk" | |
//Build thunk | |
code.push(["return function ", thunkName, "(", proc.shimArgs.join(","), "){"].join("")) | |
var typesig = [] | |
var string_typesig = [] | |
var proc_args = [["array",proc.arrayArgs[0],".shape.slice(", // Slice shape so that we only retain the shape over which we iterate (which gets passed to the cwise operator as SS). | |
Math.max(0,proc.arrayBlockIndices[0]),proc.arrayBlockIndices[0]<0?(","+proc.arrayBlockIndices[0]+")"):")"].join("")] | |
var shapeLengthConditions = [], shapeConditions = [] | |
// Process array arguments | |
for(var i=0; i<proc.arrayArgs.length; ++i) { | |
var j = proc.arrayArgs[i] | |
vars.push(["t", j, "=array", j, ".dtype,", | |
"r", j, "=array", j, ".order"].join("")) | |
typesig.push("t" + j) | |
typesig.push("r" + j) | |
string_typesig.push("t"+j) | |
string_typesig.push("r"+j+".join()") | |
proc_args.push("array" + j + ".data") | |
proc_args.push("array" + j + ".stride") | |
proc_args.push("array" + j + ".offset|0") | |
if (i>0) { // Gather conditions to check for shape equality (ignoring block indices) | |
shapeLengthConditions.push("array" + proc.arrayArgs[0] + ".shape.length===array" + j + ".shape.length+" + (Math.abs(proc.arrayBlockIndices[0])-Math.abs(proc.arrayBlockIndices[i]))) | |
shapeConditions.push("array" + proc.arrayArgs[0] + ".shape[shapeIndex+" + Math.max(0,proc.arrayBlockIndices[0]) + "]===array" + j + ".shape[shapeIndex+" + Math.max(0,proc.arrayBlockIndices[i]) + "]") | |
} | |
} | |
// Check for shape equality | |
if (proc.arrayArgs.length > 1) { | |
code.push("if (!(" + shapeLengthConditions.join(" && ") + ")) throw new Error('cwise: Arrays do not all have the same dimensionality!')") | |
code.push("for(var shapeIndex=array" + proc.arrayArgs[0] + ".shape.length-" + Math.abs(proc.arrayBlockIndices[0]) + "; shapeIndex-->0;) {") | |
code.push("if (!(" + shapeConditions.join(" && ") + ")) throw new Error('cwise: Arrays do not all have the same shape!')") | |
code.push("}") | |
} | |
// Process scalar arguments | |
for(var i=0; i<proc.scalarArgs.length; ++i) { | |
proc_args.push("scalar" + proc.scalarArgs[i]) | |
} | |
// Check for cached function (and if not present, generate it) | |
vars.push(["type=[", string_typesig.join(","), "].join()"].join("")) | |
vars.push("proc=CACHED[type]") | |
code.push("var " + vars.join(",")) | |
code.push(["if(!proc){", | |
"CACHED[type]=proc=compile([", typesig.join(","), "])}", | |
"return proc(", proc_args.join(","), ")}"].join("")) | |
if(proc.debug) { | |
console.log("-----Generated thunk:\n" + code.join("\n") + "\n----------") | |
} | |
//Compile thunk | |
var thunk = new Function("compile", code.join("\n")) | |
return thunk(compile.bind(undefined, proc)) | |
} | |
module.exports = createThunk | |
},{"./compile.js":11}],13:[function(require,module,exports){ | |
"use strict" | |
function unique_pred(list, compare) { | |
var ptr = 1 | |
, len = list.length | |
, a=list[0], b=list[0] | |
for(var i=1; i<len; ++i) { | |
b = a | |
a = list[i] | |
if(compare(a, b)) { | |
if(i === ptr) { | |
ptr++ | |
continue | |
} | |
list[ptr++] = a | |
} | |
} | |
list.length = ptr | |
return list | |
} | |
function unique_eq(list) { | |
var ptr = 1 | |
, len = list.length | |
, a=list[0], b = list[0] | |
for(var i=1; i<len; ++i, b=a) { | |
b = a | |
a = list[i] | |
if(a !== b) { | |
if(i === ptr) { | |
ptr++ | |
continue | |
} | |
list[ptr++] = a | |
} | |
} | |
list.length = ptr | |
return list | |
} | |
function unique(list, compare, sorted) { | |
if(list.length === 0) { | |
return list | |
} | |
if(compare) { | |
if(!sorted) { | |
list.sort(compare) | |
} | |
return unique_pred(list, compare) | |
} | |
if(!sorted) { | |
list.sort() | |
} | |
return unique_eq(list) | |
} | |
module.exports = unique | |
},{}],14:[function(require,module,exports){ | |
"use strict" | |
var ndarray = require("ndarray") | |
var do_convert = require("./doConvert.js") | |
module.exports = function convert(arr, result) { | |
var shape = [], c = arr, sz = 1 | |
while(Array.isArray(c)) { | |
shape.push(c.length) | |
sz *= c.length | |
c = c[0] | |
} | |
if(shape.length === 0) { | |
return ndarray() | |
} | |
if(!result) { | |
result = ndarray(new Float64Array(sz), shape) | |
} | |
do_convert(result, arr) | |
return result | |
} | |
},{"./doConvert.js":15,"ndarray":22}],15:[function(require,module,exports){ | |
module.exports=require('cwise-compiler')({"args":["array","scalar","index"],"pre":{"body":"{}","args":[],"thisVars":[],"localVars":[]},"body":{"body":"{\nvar _inline_1_v=_inline_1_arg1_,_inline_1_i\nfor(_inline_1_i=0;_inline_1_i<_inline_1_arg2_.length-1;++_inline_1_i) {\n_inline_1_v=_inline_1_v[_inline_1_arg2_[_inline_1_i]]\n}\n_inline_1_arg0_=_inline_1_v[_inline_1_arg2_[_inline_1_arg2_.length-1]]\n}","args":[{"name":"_inline_1_arg0_","lvalue":true,"rvalue":false,"count":1},{"name":"_inline_1_arg1_","lvalue":false,"rvalue":true,"count":1},{"name":"_inline_1_arg2_","lvalue":false,"rvalue":true,"count":4}],"thisVars":[],"localVars":["_inline_1_i","_inline_1_v"]},"post":{"body":"{}","args":[],"thisVars":[],"localVars":[]},"funcName":"convert","blockSize":64}) | |
},{"cwise-compiler":16}],16:[function(require,module,exports){ | |
arguments[4][10][0].apply(exports,arguments) | |
},{"./lib/thunk.js":18,"dup":10}],17:[function(require,module,exports){ | |
arguments[4][11][0].apply(exports,arguments) | |
},{"dup":11,"uniq":19}],18:[function(require,module,exports){ | |
arguments[4][12][0].apply(exports,arguments) | |
},{"./compile.js":17,"dup":12}],19:[function(require,module,exports){ | |
arguments[4][13][0].apply(exports,arguments) | |
},{"dup":13}],20:[function(require,module,exports){ | |
"use strict" | |
var ndarray = require("ndarray") | |
var ops = require("ndarray-ops") | |
var pool = require("typedarray-pool") | |
function clone(array) { | |
var dtype = array.dtype | |
if(dtype === "generic" || dtype === "array") { | |
dtype = "double" | |
} | |
var data = pool.malloc(array.size, dtype) | |
var result = ndarray(data, array.shape) | |
ops.assign(result, array) | |
return result | |
} | |
exports.clone = clone | |
function malloc(shape, dtype) { | |
if(!dtype) { | |
dtype = "double" | |
} | |
var sz = 1 | |
var stride = new Array(shape.length) | |
for(var i=shape.length-1; i>=0; --i) { | |
stride[i] = sz | |
sz *= shape[i] | |
} | |
return ndarray(pool.malloc(sz, dtype), shape, stride, 0) | |
} | |
exports.malloc = malloc | |
function free(array) { | |
if(array.dtype === "generic" || array.dtype === "array") { | |
return | |
} | |
pool.free(array.data) | |
} | |
exports.free = free | |
function zeros(shape, dtype) { | |
if(!dtype) { | |
dtype = "double" | |
} | |
var sz = 1 | |
var stride = new Array(shape.length) | |
for(var i=shape.length-1; i>=0; --i) { | |
stride[i] = sz | |
sz *= shape[i] | |
} | |
var buf = pool.malloc(sz, dtype) | |
for(var i=0; i<sz; ++i) { | |
buf[i] = 0 | |
} | |
return ndarray(buf, shape, stride, 0) | |
} | |
exports.zeros = zeros | |
function ones(shape, dtype) { | |
if(!dtype) { | |
dtype = "double" | |
} | |
var sz = 1 | |
var stride = new Array(shape.length) | |
for(var i=shape.length-1; i>=0; --i) { | |
stride[i] = sz | |
sz *= shape[i] | |
} | |
var buf = pool.malloc(sz, dtype) | |
for(var i=0; i<sz; ++i) { | |
buf[i] = 1 | |
} | |
return ndarray(buf, shape, stride, 0) | |
} | |
exports.ones = ones | |
function eye(shape, dtype) { | |
var i, offset | |
if(!dtype) { | |
dtype = "double" | |
} | |
var sz = 1 | |
var stride = new Array(shape.length) | |
for(i=shape.length-1; i>=0; --i) { | |
stride[i] = sz | |
sz *= shape[i] | |
} | |
var buf = pool.malloc(sz, dtype) | |
for(i=0; i<sz; ++i) { | |
buf[i] = 0 | |
} | |
var mindim = Infinity | |
var offsum = 0 | |
for( i=shape.length-1; i>=0; i--) { | |
offsum += stride[i] | |
mindim = Math.min(mindim,shape[i]) | |
} | |
for(i=0,offset=0; i<mindim; i++,offset+=offsum) { | |
buf[offset] = 1 | |
} | |
return ndarray(buf, shape, stride, 0) | |
} | |
exports.eye = eye | |
},{"ndarray":22,"ndarray-ops":9,"typedarray-pool":26}],21:[function(require,module,exports){ | |
"use strict" | |
module.exports = ndSelect | |
module.exports.compile = lookupCache | |
//Macros | |
var ARRAY = "a" | |
var RANK = "K" | |
var CMP = "C" | |
var DATA = "d" | |
var OFFSET = "o" | |
var RND = "R" | |
var TMP = "T" | |
var LO = "L" | |
var HI = "H" | |
var PIVOT = "X" | |
function SHAPE(i) { | |
return "s" + i | |
} | |
function STRIDE(i) { | |
return "t" + i | |
} | |
function STEP(i) { | |
return "u" + i | |
} | |
function STEP_CMP(i) { | |
return "v" + i | |
} | |
function INDEX(i) { | |
return "i" + i | |
} | |
function PICK(i) { | |
return "p" + i | |
} | |
function PTR(i) { | |
return "x" + i | |
} | |
//Create new order where index 0 is slowest index | |
function permuteOrder(order) { | |
var norder = order.slice() | |
norder.splice(order.indexOf(0), 1) | |
norder.unshift(0) | |
return norder | |
} | |
//Generate quick select procedure | |
function compileQuickSelect(order, useCompare, dtype) { | |
order = permuteOrder(order) | |
var dimension = order.length | |
var useGetter = (dtype === "generic") | |
var funcName = "ndSelect" + dtype + order.join("_") + "_" + (useCompare ? "cmp" : "lex") | |
var code = [] | |
//Get arguments for code | |
var args = [ARRAY, RANK] | |
if(useCompare) { | |
args.push(CMP) | |
} | |
//Unpack ndarray variables | |
var vars = [ | |
DATA + "=" + ARRAY + ".data", | |
OFFSET + "=" + ARRAY + ".offset|0", | |
RND + "=Math.random", | |
TMP] | |
for(var i=0; i<2; ++i) { | |
vars.push(PTR(i) + "=0") | |
} | |
for(var i=0; i<dimension; ++i) { | |
vars.push( | |
SHAPE(i) + "=" + ARRAY + ".shape[" + i + "]|0", | |
STRIDE(i) + "=" + ARRAY + ".stride[" + i + "]|0", | |
INDEX(i) + "=0") | |
} | |
for(var i=1; i<dimension; ++i) { | |
if(i > 1) { | |
vars.push(STEP_CMP(i) + "=(" + STRIDE(i) + "-" + SHAPE(i-1) + "*" + STRIDE(i-1) + ")|0", | |
STEP(order[i]) + "=(" + STRIDE(order[i]) + "-" + SHAPE(order[i-1]) + "*" + STRIDE(order[i-1]) + ")|0") | |
} else { | |
vars.push(STEP_CMP(i) + "=" + STRIDE(i), | |
STEP(order[i]) + "=" + STRIDE(order[i])) | |
} | |
} | |
if(useCompare) { | |
for(var i=0; i<2; ++i) { | |
vars.push(PICK(i) + "=" + ARRAY + ".pick(0)") | |
} | |
} | |
vars.push( | |
PIVOT + "=0", | |
LO + "=0", | |
HI + "=" + SHAPE(order[0]) + "-1") | |
function compare(out, i0, i1) { | |
if(useCompare) { | |
code.push( | |
PICK(0), ".offset=", OFFSET, "+", STRIDE(order[0]), "*(", i0, ");", | |
PICK(1), ".offset=", OFFSET, "+", STRIDE(order[0]), "*(", i1, ");", | |
out, "=", CMP, "(", PICK(0), ",", PICK(1), ");") | |
} else { | |
code.push( | |
PTR(0), "=", OFFSET, "+", STRIDE(0), "*(", i0, ");", | |
PTR(1), "=", OFFSET, "+", STRIDE(0), "*(", i1, ");") | |
if(dimension > 1) { | |
code.push("_cmp:") | |
} | |
for(var i=dimension-1; i>0; --i) { | |
code.push("for(", INDEX(i), "=0;", | |
INDEX(i), "<", SHAPE(i), ";", | |
INDEX(i), "++){") | |
} | |
if(useGetter) { | |
code.push(out, "=", DATA, ".get(", PTR(0), ")-", | |
DATA, ".get(", PTR(1), ");") | |
} else { | |
code.push(out, "=", DATA, "[", PTR(0), "]-", | |
DATA, "[", PTR(1), "];") | |
} | |
if(dimension > 1) { | |
code.push("if(", out, ")break _cmp;") | |
} | |
for(var i=1; i<dimension; ++i) { | |
code.push( | |
PTR(0), "+=", STEP_CMP(i), ";", | |
PTR(1), "+=", STEP_CMP(i), | |
"}") | |
} | |
} | |
} | |
function swap(i0, i1) { | |
code.push( | |
PTR(0), "=", OFFSET, "+", STRIDE(order[0]), "*(", i0, ");", | |
PTR(1), "=", OFFSET, "+", STRIDE(order[0]), "*(", i1, ");") | |
for(var i=dimension-1; i>0; --i) { | |
code.push("for(", INDEX(order[i]), "=0;", | |
INDEX(order[i]), "<", SHAPE(order[i]), ";", | |
INDEX(order[i]), "++){") | |
} | |
if(useGetter) { | |
code.push(TMP, "=", DATA, ".get(", PTR(0), ");", | |
DATA, ".set(", PTR(0), ",", DATA, ".get(", PTR(1), "));", | |
DATA, ".set(", PTR(1), ",", TMP, ");") | |
} else { | |
code.push(TMP, "=", DATA, "[", PTR(0), "];", | |
DATA, "[", PTR(0), "]=", DATA, "[", PTR(1), "];", | |
DATA, "[", PTR(1), "]=", TMP, ";") | |
} | |
for(var i=1; i<dimension; ++i) { | |
code.push( | |
PTR(0), "+=", STEP(order[i]), ";", | |
PTR(1), "+=", STEP(order[i]), | |
"}") | |
} | |
} | |
code.push( | |
"while(", LO, "<", HI, "){", | |
PIVOT, "=(", RND, "()*(", HI, "-", LO, "+1)+", LO, ")|0;") | |
//Partition array by pivot | |
swap(PIVOT, HI) // Store pivot temporarily at the end of the array | |
code.push( | |
PIVOT, "=", LO, ";", // PIVOT will now be used to keep track of the end of the interval of elements less than the pivot | |
"for(", INDEX(0), "=", LO, ";", | |
INDEX(0), "<", HI, ";", | |
INDEX(0), "++){") // Loop over other elements (unequal to the pivot), note that HI now points to the pivot | |
compare(TMP, INDEX(0), HI) // Lexicographical compare of element with pivot | |
code.push("if(", TMP, "<0){") | |
swap(PIVOT, INDEX(0)) // Swap current element with element at index PIVOT if it is less than the pivot | |
code.push(PIVOT, "++;") | |
code.push("}}") | |
swap(PIVOT, HI) // Store pivot right after all elements that are less than the pivot (implying that all elements >= the pivot are behind the pivot) | |
//Check pivot bounds | |
code.push( | |
"if(", PIVOT, "===", RANK, "){", | |
LO, "=", PIVOT, ";", | |
"break;", | |
"}else if(", RANK, "<", PIVOT, "){", | |
HI, "=", PIVOT, "-1;", | |
"}else{", | |
LO, "=", PIVOT, "+1;", | |
"}", | |
"}") | |
if(useCompare) { | |
code.push(PICK(0), ".offset=", OFFSET, "+", LO, "*", STRIDE(0), ";", | |
"return ", PICK(0), ";") | |
} else { | |
code.push("return ", ARRAY, ".pick(", LO, ");") | |
} | |
//Compile and link js together | |
var procCode = [ | |
"'use strict';function ", funcName, "(", args, "){", | |
"var ", vars.join(), ";", | |
code.join(""), | |
"};return ", funcName | |
].join("") | |
var proc = new Function(procCode) | |
return proc() | |
} | |
var CACHE = {} | |
function lookupCache(order, useCompare, dtype) { | |
var typesig = order.join() + useCompare + dtype | |
var proc = CACHE[typesig] | |
if(proc) { | |
return proc | |
} | |
return CACHE[typesig] = compileQuickSelect(order, useCompare, dtype) | |
} | |
function ndSelect(array, k, compare) { | |
k |= 0 | |
if((array.dimension === 0) || | |
(array.shape[0] <= k) || | |
(k < 0)) { | |
return null | |
} | |
var useCompare = !!compare | |
var proc = lookupCache(array.order, useCompare, array.dtype) | |
if(useCompare) { | |
return proc(array, k, compare) | |
} else { | |
return proc(array, k) | |
} | |
} | |
},{}],22:[function(require,module,exports){ | |
var iota = require("iota-array") | |
var isBuffer = require("is-buffer") | |
var hasTypedArrays = ((typeof Float64Array) !== "undefined") | |
function compare1st(a, b) { | |
return a[0] - b[0] | |
} | |
function order() { | |
var stride = this.stride | |
var terms = new Array(stride.length) | |
var i | |
for(i=0; i<terms.length; ++i) { | |
terms[i] = [Math.abs(stride[i]), i] | |
} | |
terms.sort(compare1st) | |
var result = new Array(terms.length) | |
for(i=0; i<result.length; ++i) { | |
result[i] = terms[i][1] | |
} | |
return result | |
} | |
function compileConstructor(dtype, dimension) { | |
var className = ["View", dimension, "d", dtype].join("") | |
if(dimension < 0) { | |
className = "View_Nil" + dtype | |
} | |
var useGetters = (dtype === "generic") | |
if(dimension === -1) { | |
//Special case for trivial arrays | |
var code = | |
"function "+className+"(a){this.data=a;};\ | |
var proto="+className+".prototype;\ | |
proto.dtype='"+dtype+"';\ | |
proto.index=function(){return -1};\ | |
proto.size=0;\ | |
proto.dimension=-1;\ | |
proto.shape=proto.stride=proto.order=[];\ | |
proto.lo=proto.hi=proto.transpose=proto.step=\ | |
function(){return new "+className+"(this.data);};\ | |
proto.get=proto.set=function(){};\ | |
proto.pick=function(){return null};\ | |
return function construct_"+className+"(a){return new "+className+"(a);}" | |
var procedure = new Function(code) | |
return procedure() | |
} else if(dimension === 0) { | |
//Special case for 0d arrays | |
var code = | |
"function "+className+"(a,d) {\ | |
this.data = a;\ | |
this.offset = d\ | |
};\ | |
var proto="+className+".prototype;\ | |
proto.dtype='"+dtype+"';\ | |
proto.index=function(){return this.offset};\ | |
proto.dimension=0;\ | |
proto.size=1;\ | |
proto.shape=\ | |
proto.stride=\ | |
proto.order=[];\ | |
proto.lo=\ | |
proto.hi=\ | |
proto.transpose=\ | |
proto.step=function "+className+"_copy() {\ | |
return new "+className+"(this.data,this.offset)\ | |
};\ | |
proto.pick=function "+className+"_pick(){\ | |
return TrivialArray(this.data);\ | |
};\ | |
proto.valueOf=proto.get=function "+className+"_get(){\ | |
return "+(useGetters ? "this.data.get(this.offset)" : "this.data[this.offset]")+ | |
"};\ | |
proto.set=function "+className+"_set(v){\ | |
return "+(useGetters ? "this.data.set(this.offset,v)" : "this.data[this.offset]=v")+"\ | |
};\ | |
return function construct_"+className+"(a,b,c,d){return new "+className+"(a,d)}" | |
var procedure = new Function("TrivialArray", code) | |
return procedure(CACHED_CONSTRUCTORS[dtype][0]) | |
} | |
var code = ["'use strict'"] | |
//Create constructor for view | |
var indices = iota(dimension) | |
var args = indices.map(function(i) { return "i"+i }) | |
var index_str = "this.offset+" + indices.map(function(i) { | |
return "this.stride[" + i + "]*i" + i | |
}).join("+") | |
var shapeArg = indices.map(function(i) { | |
return "b"+i | |
}).join(",") | |
var strideArg = indices.map(function(i) { | |
return "c"+i | |
}).join(",") | |
code.push( | |
"function "+className+"(a," + shapeArg + "," + strideArg + ",d){this.data=a", | |
"this.shape=[" + shapeArg + "]", | |
"this.stride=[" + strideArg + "]", | |
"this.offset=d|0}", | |
"var proto="+className+".prototype", | |
"proto.dtype='"+dtype+"'", | |
"proto.dimension="+dimension) | |
//view.size: | |
code.push("Object.defineProperty(proto,'size',{get:function "+className+"_size(){\ | |
return "+indices.map(function(i) { return "this.shape["+i+"]" }).join("*"), | |
"}})") | |
//view.order: | |
if(dimension === 1) { | |
code.push("proto.order=[0]") | |
} else { | |
code.push("Object.defineProperty(proto,'order',{get:") | |
if(dimension < 4) { | |
code.push("function "+className+"_order(){") | |
if(dimension === 2) { | |
code.push("return (Math.abs(this.stride[0])>Math.abs(this.stride[1]))?[1,0]:[0,1]}})") | |
} else if(dimension === 3) { | |
code.push( | |
"var s0=Math.abs(this.stride[0]),s1=Math.abs(this.stride[1]),s2=Math.abs(this.stride[2]);\ | |
if(s0>s1){\ | |
if(s1>s2){\ | |
return [2,1,0];\ | |
}else if(s0>s2){\ | |
return [1,2,0];\ | |
}else{\ | |
return [1,0,2];\ | |
}\ | |
}else if(s0>s2){\ | |
return [2,0,1];\ | |
}else if(s2>s1){\ | |
return [0,1,2];\ | |
}else{\ | |
return [0,2,1];\ | |
}}})") | |
} | |
} else { | |
code.push("ORDER})") | |
} | |
} | |
//view.set(i0, ..., v): | |
code.push( | |
"proto.set=function "+className+"_set("+args.join(",")+",v){") | |
if(useGetters) { | |
code.push("return this.data.set("+index_str+",v)}") | |
} else { | |
code.push("return this.data["+index_str+"]=v}") | |
} | |
//view.get(i0, ...): | |
code.push("proto.get=function "+className+"_get("+args.join(",")+"){") | |
if(useGetters) { | |
code.push("return this.data.get("+index_str+")}") | |
} else { | |
code.push("return this.data["+index_str+"]}") | |
} | |
//view.index: | |
code.push( | |
"proto.index=function "+className+"_index(", args.join(), "){return "+index_str+"}") | |
//view.hi(): | |
code.push("proto.hi=function "+className+"_hi("+args.join(",")+"){return new "+className+"(this.data,"+ | |
indices.map(function(i) { | |
return ["(typeof i",i,"!=='number'||i",i,"<0)?this.shape[", i, "]:i", i,"|0"].join("") | |
}).join(",")+","+ | |
indices.map(function(i) { | |
return "this.stride["+i + "]" | |
}).join(",")+",this.offset)}") | |
//view.lo(): | |
var a_vars = indices.map(function(i) { return "a"+i+"=this.shape["+i+"]" }) | |
var c_vars = indices.map(function(i) { return "c"+i+"=this.stride["+i+"]" }) | |
code.push("proto.lo=function "+className+"_lo("+args.join(",")+"){var b=this.offset,d=0,"+a_vars.join(",")+","+c_vars.join(",")) | |
for(var i=0; i<dimension; ++i) { | |
code.push( | |
"if(typeof i"+i+"==='number'&&i"+i+">=0){\ | |
d=i"+i+"|0;\ | |
b+=c"+i+"*d;\ | |
a"+i+"-=d}") | |
} | |
code.push("return new "+className+"(this.data,"+ | |
indices.map(function(i) { | |
return "a"+i | |
}).join(",")+","+ | |
indices.map(function(i) { | |
return "c"+i | |
}).join(",")+",b)}") | |
//view.step(): | |
code.push("proto.step=function "+className+"_step("+args.join(",")+"){var "+ | |
indices.map(function(i) { | |
return "a"+i+"=this.shape["+i+"]" | |
}).join(",")+","+ | |
indices.map(function(i) { | |
return "b"+i+"=this.stride["+i+"]" | |
}).join(",")+",c=this.offset,d=0,ceil=Math.ceil") | |
for(var i=0; i<dimension; ++i) { | |
code.push( | |
"if(typeof i"+i+"==='number'){\ | |
d=i"+i+"|0;\ | |
if(d<0){\ | |
c+=b"+i+"*(a"+i+"-1);\ | |
a"+i+"=ceil(-a"+i+"/d)\ | |
}else{\ | |
a"+i+"=ceil(a"+i+"/d)\ | |
}\ | |
b"+i+"*=d\ | |
}") | |
} | |
code.push("return new "+className+"(this.data,"+ | |
indices.map(function(i) { | |
return "a" + i | |
}).join(",")+","+ | |
indices.map(function(i) { | |
return "b" + i | |
}).join(",")+",c)}") | |
//view.transpose(): | |
var tShape = new Array(dimension) | |
var tStride = new Array(dimension) | |
for(var i=0; i<dimension; ++i) { | |
tShape[i] = "a[i"+i+"]" | |
tStride[i] = "b[i"+i+"]" | |
} | |
code.push("proto.transpose=function "+className+"_transpose("+args+"){"+ | |
args.map(function(n,idx) { return n + "=(" + n + "===undefined?" + idx + ":" + n + "|0)"}).join(";"), | |
"var a=this.shape,b=this.stride;return new "+className+"(this.data,"+tShape.join(",")+","+tStride.join(",")+",this.offset)}") | |
//view.pick(): | |
code.push("proto.pick=function "+className+"_pick("+args+"){var a=[],b=[],c=this.offset") | |
for(var i=0; i<dimension; ++i) { | |
code.push("if(typeof i"+i+"==='number'&&i"+i+">=0){c=(c+this.stride["+i+"]*i"+i+")|0}else{a.push(this.shape["+i+"]);b.push(this.stride["+i+"])}") | |
} | |
code.push("var ctor=CTOR_LIST[a.length+1];return ctor(this.data,a,b,c)}") | |
//Add return statement | |
code.push("return function construct_"+className+"(data,shape,stride,offset){return new "+className+"(data,"+ | |
indices.map(function(i) { | |
return "shape["+i+"]" | |
}).join(",")+","+ | |
indices.map(function(i) { | |
return "stride["+i+"]" | |
}).join(",")+",offset)}") | |
//Compile procedure | |
var procedure = new Function("CTOR_LIST", "ORDER", code.join("\n")) | |
return procedure(CACHED_CONSTRUCTORS[dtype], order) | |
} | |
function arrayDType(data) { | |
if(isBuffer(data)) { | |
return "buffer" | |
} | |
if(hasTypedArrays) { | |
switch(Object.prototype.toString.call(data)) { | |
case "[object Float64Array]": | |
return "float64" | |
case "[object Float32Array]": | |
return "float32" | |
case "[object Int8Array]": | |
return "int8" | |
case "[object Int16Array]": | |
return "int16" | |
case "[object Int32Array]": | |
return "int32" | |
case "[object Uint8Array]": | |
return "uint8" | |
case "[object Uint16Array]": | |
return "uint16" | |
case "[object Uint32Array]": | |
return "uint32" | |
case "[object Uint8ClampedArray]": | |
return "uint8_clamped" | |
} | |
} | |
if(Array.isArray(data)) { | |
return "array" | |
} | |
return "generic" | |
} | |
var CACHED_CONSTRUCTORS = { | |
"float32":[], | |
"float64":[], | |
"int8":[], | |
"int16":[], | |
"int32":[], | |
"uint8":[], | |
"uint16":[], | |
"uint32":[], | |
"array":[], | |
"uint8_clamped":[], | |
"buffer":[], | |
"generic":[] | |
} | |
;(function() { | |
for(var id in CACHED_CONSTRUCTORS) { | |
CACHED_CONSTRUCTORS[id].push(compileConstructor(id, -1)) | |
} | |
}); | |
function wrappedNDArrayCtor(data, shape, stride, offset) { | |
if(data === undefined) { | |
var ctor = CACHED_CONSTRUCTORS.array[0] | |
return ctor([]) | |
} else if(typeof data === "number") { | |
data = [data] | |
} | |
if(shape === undefined) { | |
shape = [ data.length ] | |
} | |
var d = shape.length | |
if(stride === undefined) { | |
stride = new Array(d) | |
for(var i=d-1, sz=1; i>=0; --i) { | |
stride[i] = sz | |
sz *= shape[i] | |
} | |
} | |
if(offset === undefined) { | |
offset = 0 | |
for(var i=0; i<d; ++i) { | |
if(stride[i] < 0) { | |
offset -= (shape[i]-1)*stride[i] | |
} | |
} | |
} | |
var dtype = arrayDType(data) | |
var ctor_list = CACHED_CONSTRUCTORS[dtype] | |
while(ctor_list.length <= d+1) { | |
ctor_list.push(compileConstructor(dtype, ctor_list.length-1)) | |
} | |
var ctor = ctor_list[d+1] | |
return ctor(data, shape, stride, offset) | |
} | |
module.exports = wrappedNDArrayCtor | |
},{"iota-array":23,"is-buffer":24}],23:[function(require,module,exports){ | |
"use strict" | |
function iota(n) { | |
var result = new Array(n) | |
for(var i=0; i<n; ++i) { | |
result[i] = i | |
} | |
return result | |
} | |
module.exports = iota | |
},{}],24:[function(require,module,exports){ | |
/*! | |
* Determine if an object is a Buffer | |
* | |
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org> | |
* @license MIT | |
*/ | |
// The _isBuffer check is for Safari 5-7 support, because it's missing | |
// Object.prototype.constructor. Remove this eventually | |
module.exports = function (obj) { | |
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) | |
} | |
function isBuffer (obj) { | |
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) | |
} | |
// For Node v0.10 support. Remove this eventually. | |
function isSlowBuffer (obj) { | |
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) | |
} | |
},{}],25:[function(require,module,exports){ | |
"use strict" | |
function dupe_array(count, value, i) { | |
var c = count[i]|0 | |
if(c <= 0) { | |
return [] | |
} | |
var result = new Array(c), j | |
if(i === count.length-1) { | |
for(j=0; j<c; ++j) { | |
result[j] = value | |
} | |
} else { | |
for(j=0; j<c; ++j) { | |
result[j] = dupe_array(count, value, i+1) | |
} | |
} | |
return result | |
} | |
function dupe_number(count, value) { | |
var result, i | |
result = new Array(count) | |
for(i=0; i<count; ++i) { | |
result[i] = value | |
} | |
return result | |
} | |
function dupe(count, value) { | |
if(typeof value === "undefined") { | |
value = 0 | |
} | |
switch(typeof count) { | |
case "number": | |
if(count > 0) { | |
return dupe_number(count|0, value) | |
} | |
break | |
case "object": | |
if(typeof (count.length) === "number") { | |
return dupe_array(count, value, 0) | |
} | |
break | |
} | |
return [] | |
} | |
module.exports = dupe | |
},{}],26:[function(require,module,exports){ | |
(function (global,Buffer){ | |
'use strict' | |
var bits = require('bit-twiddle') | |
var dup = require('dup') | |
//Legacy pool support | |
if(!global.__TYPEDARRAY_POOL) { | |
global.__TYPEDARRAY_POOL = { | |
UINT8 : dup([32, 0]) | |
, UINT16 : dup([32, 0]) | |
, UINT32 : dup([32, 0]) | |
, INT8 : dup([32, 0]) | |
, INT16 : dup([32, 0]) | |
, INT32 : dup([32, 0]) | |
, FLOAT : dup([32, 0]) | |
, DOUBLE : dup([32, 0]) | |
, DATA : dup([32, 0]) | |
, UINT8C : dup([32, 0]) | |
, BUFFER : dup([32, 0]) | |
} | |
} | |
var hasUint8C = (typeof Uint8ClampedArray) !== 'undefined' | |
var POOL = global.__TYPEDARRAY_POOL | |
//Upgrade pool | |
if(!POOL.UINT8C) { | |
POOL.UINT8C = dup([32, 0]) | |
} | |
if(!POOL.BUFFER) { | |
POOL.BUFFER = dup([32, 0]) | |
} | |
//New technique: Only allocate from ArrayBufferView and Buffer | |
var DATA = POOL.DATA | |
, BUFFER = POOL.BUFFER | |
exports.free = function free(array) { | |
if(Buffer.isBuffer(array)) { | |
BUFFER[bits.log2(array.length)].push(array) | |
} else { | |
if(Object.prototype.toString.call(array) !== '[object ArrayBuffer]') { | |
array = array.buffer | |
} | |
if(!array) { | |
return | |
} | |
var n = array.length || array.byteLength | |
var log_n = bits.log2(n)|0 | |
DATA[log_n].push(array) | |
} | |
} | |
function freeArrayBuffer(buffer) { | |
if(!buffer) { | |
return | |
} | |
var n = buffer.length || buffer.byteLength | |
var log_n = bits.log2(n) | |
DATA[log_n].push(buffer) | |
} | |
function freeTypedArray(array) { | |
freeArrayBuffer(array.buffer) | |
} | |
exports.freeUint8 = | |
exports.freeUint16 = | |
exports.freeUint32 = | |
exports.freeInt8 = | |
exports.freeInt16 = | |
exports.freeInt32 = | |
exports.freeFloat32 = | |
exports.freeFloat = | |
exports.freeFloat64 = | |
exports.freeDouble = | |
exports.freeUint8Clamped = | |
exports.freeDataView = freeTypedArray | |
exports.freeArrayBuffer = freeArrayBuffer | |
exports.freeBuffer = function freeBuffer(array) { | |
BUFFER[bits.log2(array.length)].push(array) | |
} | |
exports.malloc = function malloc(n, dtype) { | |
if(dtype === undefined || dtype === 'arraybuffer') { | |
return mallocArrayBuffer(n) | |
} else { | |
switch(dtype) { | |
case 'uint8': | |
return mallocUint8(n) | |
case 'uint16': | |
return mallocUint16(n) | |
case 'uint32': | |
return mallocUint32(n) | |
case 'int8': | |
return mallocInt8(n) | |
case 'int16': | |
return mallocInt16(n) | |
case 'int32': | |
return mallocInt32(n) | |
case 'float': | |
case 'float32': | |
return mallocFloat(n) | |
case 'double': | |
case 'float64': | |
return mallocDouble(n) | |
case 'uint8_clamped': | |
return mallocUint8Clamped(n) | |
case 'buffer': | |
return mallocBuffer(n) | |
case 'data': | |
case 'dataview': | |
return mallocDataView(n) | |
default: | |
return null | |
} | |
} | |
return null | |
} | |
function mallocArrayBuffer(n) { | |
var n = bits.nextPow2(n) | |
var log_n = bits.log2(n) | |
var d = DATA[log_n] | |
if(d.length > 0) { | |
return d.pop() | |
} | |
return new ArrayBuffer(n) | |
} | |
exports.mallocArrayBuffer = mallocArrayBuffer | |
function mallocUint8(n) { | |
return new Uint8Array(mallocArrayBuffer(n), 0, n) | |
} | |
exports.mallocUint8 = mallocUint8 | |
function mallocUint16(n) { | |
return new Uint16Array(mallocArrayBuffer(2*n), 0, n) | |
} | |
exports.mallocUint16 = mallocUint16 | |
function mallocUint32(n) { | |
return new Uint32Array(mallocArrayBuffer(4*n), 0, n) | |
} | |
exports.mallocUint32 = mallocUint32 | |
function mallocInt8(n) { | |
return new Int8Array(mallocArrayBuffer(n), 0, n) | |
} | |
exports.mallocInt8 = mallocInt8 | |
function mallocInt16(n) { | |
return new Int16Array(mallocArrayBuffer(2*n), 0, n) | |
} | |
exports.mallocInt16 = mallocInt16 | |
function mallocInt32(n) { | |
return new Int32Array(mallocArrayBuffer(4*n), 0, n) | |
} | |
exports.mallocInt32 = mallocInt32 | |
function mallocFloat(n) { | |
return new Float32Array(mallocArrayBuffer(4*n), 0, n) | |
} | |
exports.mallocFloat32 = exports.mallocFloat = mallocFloat | |
function mallocDouble(n) { | |
return new Float64Array(mallocArrayBuffer(8*n), 0, n) | |
} | |
exports.mallocFloat64 = exports.mallocDouble = mallocDouble | |
function mallocUint8Clamped(n) { | |
if(hasUint8C) { | |
return new Uint8ClampedArray(mallocArrayBuffer(n), 0, n) | |
} else { | |
return mallocUint8(n) | |
} | |
} | |
exports.mallocUint8Clamped = mallocUint8Clamped | |
function mallocDataView(n) { | |
return new DataView(mallocArrayBuffer(n), 0, n) | |
} | |
exports.mallocDataView = mallocDataView | |
function mallocBuffer(n) { | |
n = bits.nextPow2(n) | |
var log_n = bits.log2(n) | |
var cache = BUFFER[log_n] | |
if(cache.length > 0) { | |
return cache.pop() | |
} | |
return new Buffer(n) | |
} | |
exports.mallocBuffer = mallocBuffer | |
exports.clearCache = function clearCache() { | |
for(var i=0; i<32; ++i) { | |
POOL.UINT8[i].length = 0 | |
POOL.UINT16[i].length = 0 | |
POOL.UINT32[i].length = 0 | |
POOL.INT8[i].length = 0 | |
POOL.INT16[i].length = 0 | |
POOL.INT32[i].length = 0 | |
POOL.FLOAT[i].length = 0 | |
POOL.DOUBLE[i].length = 0 | |
POOL.UINT8C[i].length = 0 | |
DATA[i].length = 0 | |
BUFFER[i].length = 0 | |
} | |
} | |
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer) | |
//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy90eXBlZGFycmF5LXBvb2wvcG9vbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIid1c2Ugc3RyaWN0J1xuXG52YXIgYml0cyA9IHJlcXVpcmUoJ2JpdC10d2lkZGxlJylcbnZhciBkdXAgPSByZXF1aXJlKCdkdXAnKVxuXG4vL0xlZ2FjeSBwb29sIHN1cHBvcnRcbmlmKCFnbG9iYWwuX19UWVBFREFSUkFZX1BPT0wpIHtcbiAgZ2xvYmFsLl9fVFlQRURBUlJBWV9QT09MID0ge1xuICAgICAgVUlOVDggICA6IGR1cChbMzIsIDBdKVxuICAgICwgVUlOVDE2ICA6IGR1cChbMzIsIDBdKVxuICAgICwgVUlOVDMyICA6IGR1cChbMzIsIDBdKVxuICAgICwgSU5UOCAgICA6IGR1cChbMzIsIDBdKVxuICAgICwgSU5UMTYgICA6IGR1cChbMzIsIDBdKVxuICAgICwgSU5UMzIgICA6IGR1cChbMzIsIDBdKVxuICAgICwgRkxPQVQgICA6IGR1cChbMzIsIDBdKVxuICAgICwgRE9VQkxFICA6IGR1cChbMzIsIDBdKVxuICAgICwgREFUQSAgICA6IGR1cChbMzIsIDBdKVxuICAgICwgVUlOVDhDICA6IGR1cChbMzIsIDBdKVxuICAgICwgQlVGRkVSICA6IGR1cChbMzIsIDBdKVxuICB9XG59XG5cbnZhciBoYXNVaW50OEMgPSAodHlwZW9mIFVpbnQ4Q2xhbXBlZEFycmF5KSAhPT0gJ3VuZGVmaW5lZCdcbnZhciBQT09MID0gZ2xvYmFsLl9fVFlQRURBUlJBWV9QT09MXG5cbi8vVXBncmFkZSBwb29sXG5pZighUE9PTC5VSU5UOEMpIHtcbiAgUE9PTC5VSU5UOEMgPSBkdXAoWzMyLCAwXSlcbn1cbmlmKCFQT09MLkJVRkZFUikge1xuICBQT09MLkJVRkZFUiA9IGR1cChbMzIsIDBdKVxufVxuXG4vL05ldyB0ZWNobmlxdWU6IE9ubHkgYWxsb2NhdGUgZnJvbSBBcnJheUJ1ZmZlclZpZXcgYW5kIEJ1ZmZlclxudmFyIERBVEEgICAgPSBQT09MLkRBVEFcbiAgLCBCVUZGRVIgID0gUE9PTC5CVUZGRVJcblxuZXhwb3J0cy5mcmVlID0gZnVuY3Rpb24gZnJlZShhcnJheSkge1xuICBpZihCdWZmZXIuaXNCdWZmZXIoYXJyYXkpKSB7XG4gICAgQlVGRkVSW2JpdHMubG9nMihhcnJheS5sZW5ndGgpXS5wdXNoKGFycmF5KVxuICB9IGVsc2Uge1xuICAgIGlmKE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChhcnJheSkgIT09ICdbb2JqZWN0IEFycmF5QnVmZmVyXScpIHtcbiAgICAgIGFycmF5ID0gYXJyYXkuYnVmZmVyXG4gICAgfVxuICAgIGlmKCFhcnJheSkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuICAgIHZhciBuID0gYXJyYXkubGVuZ3RoIHx8IGFycmF5LmJ5dGVMZW5ndGhcbiAgICB2YXIgbG9nX24gPSBiaXRzLmxvZzIobil8MFxuICAgIERBVEFbbG9nX25dLnB1c2goYXJyYXkpXG4gIH1cbn1cblxuZnVuY3Rpb24gZnJlZUFycmF5QnVmZmVyKGJ1ZmZlcikge1xuICBpZighYnVmZmVyKSB7XG4gICAgcmV0dXJuXG4gIH1cbiAgdmFyIG4gPSBidWZmZXIubGVuZ3RoIHx8IGJ1ZmZlci5ieXRlTGVuZ3RoXG4gIHZhciBsb2dfbiA9IGJpdHMubG9nMihuKVxuICBEQVRBW2xvZ19uXS5wdXNoKGJ1ZmZlcilcbn1cblxuZnVuY3Rpb24gZnJlZVR5cGVkQXJyYXkoYXJyYXkpIHtcbiAgZnJlZUFycmF5QnVmZmVyKGFycmF5LmJ1ZmZlcilcbn1cblxuZXhwb3J0cy5mcmVlVWludDggPVxuZXhwb3J0cy5mcmVlVWludDE2ID1cbmV4cG9ydHMuZnJlZVVpbnQzMiA9XG5leHBvcnRzLmZyZWVJbnQ4ID1cbmV4cG9ydHMuZnJlZUludDE2ID1cbmV4cG9ydHMuZnJlZUludDMyID1cbmV4cG9ydHMuZnJlZUZsb2F0MzIgPSBcbmV4cG9ydHMuZnJlZUZsb2F0ID1cbmV4cG9ydHMuZnJlZUZsb2F0NjQgPSBcbmV4cG9ydHMuZnJlZURvdWJsZSA9IFxuZXhwb3J0cy5mcmVlVWludDhDbGFtcGVkID0gXG5leHBvcnRzLmZyZWVEYXRhVmlldyA9IGZyZWVUeXBlZEFycmF5XG5cbmV4cG9ydHMuZnJlZUFycmF5QnVmZmVyID0gZnJlZUFycmF5QnVmZmVyXG5cbmV4cG9ydHMuZnJlZUJ1ZmZlciA9IGZ1bmN0aW9uIGZyZWVCdWZmZXIoYXJyYXkpIHtcbiAgQlVGRkVSW2JpdHMubG9nMihhcnJheS5sZW5ndGgpXS5wdXNoKGFycmF5KVxufVxuXG5leHBvcnRzLm1hbGxvYyA9IGZ1bmN0aW9uIG1hbGxvYyhuLCBkdHlwZSkge1xuICBpZihkdHlwZSA9PT0gdW5kZWZpbmVkIHx8IGR0eXBlID09PSAnYXJyYXlidWZmZXInKSB7XG4gICAgcmV0dXJuIG1hbGxvY0FycmF5QnVmZmVyKG4pXG4gIH0gZWxzZSB7XG4gICAgc3dpdGNoKGR0eXBlKSB7XG4gICAgICBjYXNlICd1aW50OCc6XG4gICAgICAgIHJldHVybiBtYWxsb2NVaW50OChuKVxuICAgICAgY2FzZSAndWludDE2JzpcbiAgICAgICAgcmV0dXJuIG1hbGxvY1VpbnQxNihuKVxuICAgICAgY2FzZSAndWludDMyJzpcbiAgICAgICAgcmV0dXJuIG1hbGxvY1VpbnQzMihuKVxuICAgICAgY2FzZSAnaW50OCc6XG4gICAgICAgIHJldHVybiBtYWxsb2NJbnQ4KG4pXG4gICAgICBjYXNlICdpbnQxNic6XG4gICAgICAgIHJldHVybiBtYWxsb2NJbnQxNihuKVxuICAgICAgY2FzZSAnaW50MzInOlxuICAgICAgICByZXR1cm4gbWFsbG9jSW50MzIobilcbiAgICAgIGNhc2UgJ2Zsb2F0JzpcbiAgICAgIGNhc2UgJ2Zsb2F0MzInOlxuICAgICAgICByZXR1cm4gbWFsbG9jRmxvYXQobilcbiAgICAgIGNhc2UgJ2RvdWJsZSc6XG4gICAgICBjYXNlICdmbG9hdDY0JzpcbiAgICAgICAgcmV0dXJuIG1hbGxvY0RvdWJsZShuKVxuICAgICAgY2FzZSAndWludDhfY2xhbXBlZCc6XG4gICAgICAgIHJldHVybiBtYWxsb2NVaW50OENsYW1wZWQobilcbiAgICAgIGNhc2UgJ2J1ZmZlcic6XG4gICAgICAgIHJldHVybiBtYWxsb2NCdWZmZXIobilcbiAgICAgIGNhc2UgJ2RhdGEnOlxuICAgICAgY2FzZSAnZGF0YXZpZXcnOlxuICAgICAgICByZXR1cm4gbWFsbG9jRGF0YVZpZXcobilcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIG51bGxcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG51bGxcbn1cblxuZnVuY3Rpb24gbWFsbG9jQXJyYXlCdWZmZXIobikge1xuICB2YXIgbiA9IGJpdHMubmV4dFBvdzIobilcbiAgdmFyIGxvZ19uID0gYml0cy5sb2cyKG4pXG4gIHZhciBkID0gREFUQVtsb2dfbl1cbiAgaWYoZC5sZW5ndGggPiAwKSB7XG4gICAgcmV0dXJuIGQucG9wKClcbiAgfVxuICByZXR1cm4gbmV3IEFycmF5QnVmZmVyKG4pXG59XG5leHBvcnRzLm1hbGxvY0FycmF5QnVmZmVyID0gbWFsbG9jQXJyYXlCdWZmZXJcblxuZnVuY3Rpb24gbWFsbG9jVWludDgobikge1xuICByZXR1cm4gbmV3IFVpbnQ4QXJyYXkobWFsbG9jQXJyYXlCdWZmZXIobiksIDAsIG4pXG59XG5leHBvcnRzLm1hbGxvY1VpbnQ4ID0gbWFsbG9jVWludDhcblxuZnVuY3Rpb24gbWFsbG9jVWludDE2KG4pIHtcbiAgcmV0dXJuIG5ldyBVaW50MTZBcnJheShtYWxsb2NBcnJheUJ1ZmZlcigyKm4pLCAwLCBuKVxufVxuZXhwb3J0cy5tYWxsb2NVaW50MTYgPSBtYWxsb2NVaW50MTZcblxuZnVuY3Rpb24gbWFsbG9jVWludDMyKG4pIHtcbiAgcmV0dXJuIG5ldyBVaW50MzJBcnJheShtYWxsb2NBcnJheUJ1ZmZlcig0Km4pLCAwLCBuKVxufVxuZXhwb3J0cy5tYWxsb2NVaW50MzIgPSBtYWxsb2NVaW50MzJcblxuZnVuY3Rpb24gbWFsbG9jSW50OChuKSB7XG4gIHJldHVybiBuZXcgSW50OEFycmF5KG1hbGxvY0FycmF5QnVmZmVyKG4pLCAwLCBuKVxufVxuZXhwb3J0cy5tYWxsb2NJbnQ4ID0gbWFsbG9jSW50OFxuXG5mdW5jdGlvbiBtYWxsb2NJbnQxNihuKSB7XG4gIHJldHVybiBuZXcgSW50MTZBcnJheShtYWxsb2NBcnJheUJ1ZmZlcigyKm4pLCAwLCBuKVxufVxuZXhwb3J0cy5tYWxsb2NJbnQxNiA9IG1hbGxvY0ludDE2XG5cbmZ1bmN0aW9uIG1hbGxvY0ludDMyKG4pIHtcbiAgcmV0dXJuIG5ldyBJbnQzMkFycmF5KG1hbGxvY0FycmF5QnVmZmVyKDQqbiksIDAsIG4pXG59XG5leHBvcnRzLm1hbGxvY0ludDMyID0gbWFsbG9jSW50MzJcblxuZnVuY3Rpb24gbWFsbG9jRmxvYXQobikge1xuICByZXR1cm4gbmV3IEZsb2F0MzJBcnJheShtYWxsb2NBcnJheUJ1ZmZlcig0Km4pLCAwLCBuKVxufVxuZXhwb3J0cy5tYWxsb2NGbG9hdDMyID0gZXhwb3J0cy5tYWxsb2NGbG9hdCA9IG1hbGxvY0Zsb2F0XG5cbmZ1bmN0aW9uIG1hbGxvY0RvdWJsZShuKSB7XG4gIHJldHVybiBuZXcgRmxvYXQ2NEFycmF5KG1hbGxvY0FycmF5QnVmZmVyKDgqbiksIDAsIG4pXG59XG5leHBvcnRzLm1hbGxvY0Zsb2F0NjQgPSBleHBvcnRzLm1hbGxvY0RvdWJsZSA9IG1hbGxvY0RvdWJsZVxuXG5mdW5jdGlvbiBtYWxsb2NVaW50OENsYW1wZWQobikge1xuICBpZihoYXNVaW50OEMpIHtcbiAgICByZXR1cm4gbmV3IFVpbnQ4Q2xhbXBlZEFycmF5KG1hbGxvY0FycmF5QnVmZmVyKG4pLCAwLCBuKVxuICB9IGVsc2Uge1xuICAgIHJldHVybiBtYWxsb2NVaW50OChuKVxuICB9XG59XG5leHBvcnRzLm1hbGxvY1VpbnQ4Q2xhbXBlZCA9IG1hbGxvY1VpbnQ4Q2xhbXBlZFxuXG5mdW5jdGlvbiBtYWxsb2NEYXRhVmlldyhuKSB7XG4gIHJldHVybiBuZXcgRGF0YVZpZXcobWFsbG9jQXJyYXlCdWZmZXIobiksIDAsIG4pXG59XG5leHBvcnRzLm1hbGxvY0RhdGFWaWV3ID0gbWFsbG9jRGF0YVZpZXdcblxuZnVuY3Rpb24gbWFsbG9jQnVmZmVyKG4pIHtcbiAgbiA9IGJpdHMubmV4dFBvdzIobilcbiAgdmFyIGxvZ19uID0gYml0cy5sb2cyKG4pXG4gIHZhciBjYWNoZSA9IEJVRkZFUltsb2dfbl1cbiAgaWYoY2FjaGUubGVuZ3RoID4gMCkge1xuICAgIHJldHVybiBjYWNoZS5wb3AoKVxuICB9XG4gIHJldHVybiBuZXcgQnVmZmVyKG4pXG59XG5leHBvcnRzLm1hbGxvY0J1ZmZlciA9IG1hbGxvY0J1ZmZlclxuXG5leHBvcnRzLmNsZWFyQ2FjaGUgPSBmdW5jdGlvbiBjbGVhckNhY2hlKCkge1xuICBmb3IodmFyIGk9MDsgaTwzMjsgKytpKSB7XG4gICAgUE9PTC5VSU5UOFtpXS5sZW5ndGggPSAwXG4gICAgUE9PTC5VSU5UMTZbaV0ubGVuZ3RoID0gMFxuICAgIFBPT0wuVUlOVDMyW2ldLmxlbmd0aCA9IDBcbiAgICBQT09MLklOVDhbaV0ubGVuZ3RoID0gMFxuICAgIFBPT0wuSU5UMTZbaV0ubGVuZ3RoID0gMFxuICAgIFBPT0wuSU5UMzJbaV0ubGVuZ3RoID0gMFxuICAgIFBPT0wuRkxPQVRbaV0ubGVuZ3RoID0gMFxuICAgIFBPT0wuRE9VQkxFW2ldLmxlbmd0aCA9IDBcbiAgICBQT09MLlVJTlQ4Q1tpXS5sZW5ndGggPSAwXG4gICAgREFUQVtpXS5sZW5ndGggPSAwXG4gICAgQlVGRkVSW2ldLmxlbmd0aCA9IDBcbiAgfVxufSJdfQ== | |
},{"bit-twiddle":6,"buffer":1,"dup":25}],"static-kdtree":[function(require,module,exports){ | |
"use strict" | |
module.exports = createKDTree | |
module.exports.deserialize = deserializeKDTree | |
var ndarray = require("ndarray") | |
var ndselect = require("ndarray-select") | |
var pack = require("ndarray-pack") | |
var ops = require("ndarray-ops") | |
var ndscratch = require("ndarray-scratch") | |
var pool = require("typedarray-pool") | |
var inorderTree = require("inorder-tree-layout") | |
var bits = require("bit-twiddle") | |
var KDTHeap = require("./lib/heap.js") | |
function KDTree(points, ids, n, d) { | |
this.points = points | |
this.ids = ids | |
this.dimension = d | |
this.length = n | |
} | |
var proto = KDTree.prototype | |
proto.serialize = function() { | |
if(this.length > 0) { | |
return { | |
p: Array.prototype.slice.call(this.points.data, 0, this.length*this.dimension), | |
i: Array.prototype.slice.call(this.ids, 0, this.length) | |
} | |
} else { | |
return { d: this.dimension } | |
} | |
} | |
//Range query | |
proto.range = function kdtRangeQuery(lo, hi, visit) { | |
var n = this.length | |
if(n < 1) { | |
return | |
} | |
//Check degenerate case | |
var d = this.dimension | |
for(var i=0; i<d; ++i) { | |
if(hi[i] < lo[i]) { | |
return | |
} | |
} | |
var points = this.points | |
var ids = this.ids | |
//Walk tree in level order, skipping subtrees which do not intersect range | |
var visitRange = ndscratch.malloc([n, 2, d]) | |
var visitIndex = pool.mallocInt32(n) | |
var rangeData = visitRange.data | |
var pointData = points.data | |
var visitCount = 1 | |
var visitTop = 0 | |
var retval | |
visitIndex[0] = 0 | |
pack(lo, visitRange.pick(0,0)) | |
pack(hi, visitRange.pick(0,1)) | |
while(visitTop < visitCount) { | |
var idx = visitIndex[visitTop] | |
var k = bits.log2(idx+1)%d | |
var loidx = visitRange.index(visitTop, 0, 0) | |
var hiidx = visitRange.index(visitTop, 1, 0) | |
var pidx = points.index(idx, 0) | |
var visitPoint = true | |
for(var i=0; i<d; ++i) { | |
var pc = pointData[pidx+i] | |
if((pc < rangeData[loidx + i]) || | |
(rangeData[hiidx + i] < pc)) { | |
visitPoint = false | |
break | |
} | |
} | |
if(visitPoint) { | |
retval = visit(ids[idx]) | |
if(retval !== undefined) { | |
break | |
} | |
} | |
//Visit children | |
var pk = pointData[pidx+k] | |
var hk = rangeData[hiidx+k] | |
var lk = rangeData[loidx+k] | |
if(lk <= pk) { | |
var left = 2 * idx + 1 | |
if(left < n) { | |
visitIndex[visitCount] = left | |
var y = visitRange.index(visitCount, 0, 0) | |
for(var i=0; i<d; ++i) { | |
rangeData[y+i] = rangeData[loidx+i] | |
} | |
var z = visitRange.index(visitCount, 1, 0) | |
for(var i=0; i<d; ++i) { | |
rangeData[z+i] = rangeData[hiidx+i] | |
} | |
rangeData[z+k] = Math.min(hk, pk) | |
visitCount += 1 | |
} | |
} | |
if(pk <= hk) { | |
var right = 2 * (idx + 1) | |
if(right < n) { | |
visitIndex[visitCount] = right | |
var y = visitRange.index(visitCount, 0, 0) | |
for(var i=0; i<d; ++i) { | |
rangeData[y+i] = rangeData[loidx+i] | |
} | |
var z = visitRange.index(visitCount, 1, 0) | |
for(var i=0; i<d; ++i) { | |
rangeData[z+i] = rangeData[hiidx+i] | |
} | |
rangeData[y+k] = Math.max(lk, pk) | |
visitCount += 1 | |
} | |
} | |
//Increment pointer | |
visitTop += 1 | |
} | |
ndscratch.free(visitRange) | |
pool.free(visitIndex) | |
return retval | |
} | |
proto.rnn = function(point, radius, visit) { | |
if(radius < 0) { | |
return | |
} | |
var n = this.length | |
if(n < 1) { | |
return | |
} | |
var d = this.dimension | |
var points = this.points | |
var ids = this.ids | |
//Walk tree in level order, skipping subtrees which do not intersect sphere | |
var visitDistance = ndscratch.malloc([n, d]) | |
var visitIndex = pool.mallocInt32(n) | |
var distanceData = visitDistance.data | |
var pointData = points.data | |
var visitCount = 1 | |
var visitTop = 0 | |
var r2 = radius*radius | |
var retval | |
//Initialize top of queue | |
visitIndex[0] = 0 | |
for(var i=0; i<d; ++i) { | |
visitDistance.set(0, i, 0) | |
} | |
//Walk over queue | |
while(visitTop < visitCount) { | |
var idx = visitIndex[visitTop] | |
var pidx = points.index(idx, 0) | |
//Check if point in sphere | |
var d2 = 0.0 | |
for(var i=0; i<d; ++i) { | |
d2 += Math.pow(point[i] - pointData[pidx+i], 2) | |
} | |
if(d2 <= r2) { | |
retval = visit(ids[idx]) | |
if(retval !== undefined) { | |
break | |
} | |
} | |
//Visit children | |
var k = bits.log2(idx+1)%d | |
var ds = 0.0 | |
var didx = visitDistance.index(visitTop, 0) | |
for(var i=0; i<d; ++i) { | |
if(i !== k) { | |
ds += distanceData[didx + i] | |
} | |
} | |
//Handle split axis | |
var qk = point[k] | |
var pk = pointData[pidx+k] | |
var dk = distanceData[didx+k] | |
var lk = dk | |
var hk = dk | |
if(qk < pk) { | |
hk = Math.max(dk, Math.pow(pk - qk, 2)) | |
} else { | |
lk = Math.max(dk, Math.pow(pk - qk, 2)) | |
} | |
var d2l = lk + ds | |
var d2h = hk + ds | |
if(d2l <= r2) { | |
var left = 2 * idx + 1 | |
if(left < n) { | |
visitIndex[visitCount] = left | |
var y = visitDistance.index(visitCount, 0) | |
for(var i=0; i<d; ++i) { | |
distanceData[y+i] = distanceData[didx+i] | |
} | |
distanceData[y+k] = lk | |
visitCount += 1 | |
} | |
} | |
if(d2h <= r2) { | |
var right = 2 * (idx + 1) | |
if(right < n) { | |
visitIndex[visitCount] = right | |
var y = visitDistance.index(visitCount, 0) | |
for(var i=0; i<d; ++i) { | |
distanceData[y+i] = distanceData[didx+i] | |
} | |
distanceData[y+k] = hk | |
visitCount += 1 | |
} | |
} | |
//Increment pointer | |
visitTop += 1 | |
} | |
ndscratch.free(visitDistance) | |
pool.free(visitIndex) | |
return retval | |
} | |
proto.nn = function(point, maxDistance) { | |
var n = this.length | |
if(n < 1) { | |
return -1 | |
} | |
if(typeof maxDistance === "number") { | |
if(maxDistance < 0) { | |
return -1 | |
} | |
} else { | |
maxDistance = Infinity | |
} | |
var d = this.dimension | |
var points = this.points | |
var pointData = points.data | |
var dataVector = pool.mallocFloat64(d) | |
var toVisit = new KDTHeap(n, d+1) | |
var index = toVisit.index | |
var data = toVisit.data | |
index[0] = 0 | |
for(var i=0; i<=d; ++i) { | |
data[i] = 0 | |
} | |
toVisit.count += 1 | |
var nearest = -1 | |
var nearestD = maxDistance | |
while(toVisit.count > 0) { | |
if(data[0] >= nearestD) { | |
break | |
} | |
var idx = index[0] | |
var pidx = points.index(idx, 0) | |
var d2 = 0.0 | |
for(var i=0; i<d; ++i) { | |
d2 += Math.pow(point[i]-pointData[pidx+i], 2) | |
} | |
if(d2 < nearestD) { | |
nearestD = d2 | |
nearest = idx | |
} | |
//Compute distance bounds for children | |
var k = bits.log2(idx+1)%d | |
var ds = 0 | |
for(var i=0; i<d; ++i) { | |
var dd = data[i+1] | |
if(i !== k) { | |
ds += dd | |
} | |
dataVector[i] = dd | |
} | |
var qk = point[k] | |
var pk = pointData[pidx+k] | |
var dk = dataVector[k] | |
var lk = dk | |
var hk = dk | |
if(qk < pk) { | |
hk = Math.max(dk, Math.pow(pk - qk, 2)) | |
} else { | |
lk = Math.max(dk, Math.pow(pk - qk, 2)) | |
} | |
var d2l = lk + ds | |
var d2h = hk + ds | |
toVisit.pop() | |
if(d2l < nearestD) { | |
var left = 2 * idx + 1 | |
if(left < n) { | |
var vcount = toVisit.count | |
index[vcount] = left | |
var vptr = vcount * (d+1) | |
data[vptr] = d2l | |
for(var i=1; i<=d; ++i) { | |
data[vptr+i] = dataVector[i-1] | |
} | |
data[vptr+k+1] = lk | |
toVisit.push() | |
} | |
} | |
if(d2h < nearestD) { | |
var right = 2 * (idx + 1) | |
if(right < n) { | |
var vcount = toVisit.count | |
index[vcount] = right | |
var vptr = vcount * (d+1) | |
data[vptr] = d2h | |
for(var i=1; i<=d; ++i) { | |
data[vptr+i] = dataVector[i-1] | |
} | |
data[vptr+k+1] = hk | |
toVisit.push() | |
} | |
} | |
} | |
pool.freeFloat64(dataVector) | |
toVisit.dispose() | |
if(nearest < 0) { | |
return -1 | |
} | |
return this.ids[nearest] | |
} | |
proto.knn = function(point, maxPoints, maxDistance) { | |
//Check degenerate cases | |
if(typeof maxDistance === "number") { | |
if(maxDistance < 0) { | |
return [] | |
} | |
} else { | |
maxDistance = Infinity | |
} | |
var n = this.length | |
if(n < 1) { | |
return [] | |
} | |
if(typeof maxPoints === "number") { | |
if(maxPoints <= 0) { | |
return [] | |
} | |
maxPoints = Math.min(maxPoints, n)|0 | |
} else { | |
maxPoints = n | |
} | |
var ids = this.ids | |
var d = this.dimension | |
var points = this.points | |
var pointData = points.data | |
var dataVector = pool.mallocFloat64(d) | |
//List of closest points | |
var closestPoints = new KDTHeap(maxPoints, 1) | |
var cl_index = closestPoints.index | |
var cl_data = closestPoints.data | |
var toVisit = new KDTHeap(n, d+1) | |
var index = toVisit.index | |
var data = toVisit.data | |
index[0] = 0 | |
for(var i=0; i<=d; ++i) { | |
data[i] = 0 | |
} | |
toVisit.count += 1 | |
var nearest = -1 | |
var nearestD = maxDistance | |
while(toVisit.count > 0) { | |
if(data[0] >= nearestD) { | |
break | |
} | |
var idx = index[0] | |
var pidx = points.index(idx, 0) | |
var d2 = 0.0 | |
for(var i=0; i<d; ++i) { | |
d2 += Math.pow(point[i]-pointData[pidx+i], 2) | |
} | |
if(d2 < nearestD) { | |
if(closestPoints.count >= maxPoints) { | |
closestPoints.pop() | |
} | |
var pcount = closestPoints.count | |
cl_index[pcount] = idx | |
cl_data[pcount] = -d2 | |
closestPoints.push() | |
if(closestPoints.count >= maxPoints) { | |
nearestD = -cl_data[0] | |
} | |
} | |
//Compute distance bounds for children | |
var k = bits.log2(idx+1)%d | |
var ds = 0 | |
for(var i=0; i<d; ++i) { | |
var dd = data[i+1] | |
if(i !== k) { | |
ds += dd | |
} | |
dataVector[i] = dd | |
} | |
var qk = point[k] | |
var pk = pointData[pidx+k] | |
var dk = dataVector[k] | |
var lk = dk | |
var hk = dk | |
if(qk < pk) { | |
hk = Math.max(dk, Math.pow(pk - qk, 2)) | |
} else { | |
lk = Math.max(dk, Math.pow(pk - qk, 2)) | |
} | |
var d2l = lk + ds | |
var d2h = hk + ds | |
toVisit.pop() | |
if(d2l < nearestD) { | |
var left = 2 * idx + 1 | |
if(left < n) { | |
var vcount = toVisit.count | |
index[vcount] = left | |
var vptr = vcount * (d+1) | |
data[vptr] = d2l | |
for(var i=1; i<=d; ++i) { | |
data[vptr+i] = dataVector[i-1] | |
} | |
data[vptr+k+1] = lk | |
toVisit.push() | |
} | |
} | |
if(d2h < nearestD) { | |
var right = 2 * (idx + 1) | |
if(right < n) { | |
var vcount = toVisit.count | |
index[vcount] = right | |
var vptr = vcount * (d+1) | |
data[vptr] = d2h | |
for(var i=1; i<=d; ++i) { | |
data[vptr+i] = dataVector[i-1] | |
} | |
data[vptr+k+1] = hk | |
toVisit.push() | |
} | |
} | |
} | |
pool.freeFloat64(dataVector) | |
toVisit.dispose() | |
//Sort result | |
var result = new Array(closestPoints.count) | |
var ids = this.ids | |
for(var i=closestPoints.count-1; i>=0; --i) { | |
result[i] = ids[cl_index[0]] | |
closestPoints.pop() | |
} | |
closestPoints.dispose() | |
return result | |
} | |
proto.dispose = function kdtDispose() { | |
pool.free(this.points.data) | |
pool.freeInt32(this.ids) | |
this.points = null | |
this.ids = null | |
this.length = 0 | |
} | |
function createKDTree(points) { | |
var n, d, indexed | |
if(Array.isArray(points)) { | |
n = points.length | |
if(n === 0) { | |
return new KDTree(null, null, 0, 0) | |
} | |
d = points[0].length | |
indexed = ndarray(pool.mallocDouble(n*(d+1)), [n, d+1]) | |
pack(points, indexed.hi(n, d)) | |
} else { | |
n = points.shape[0] | |
d = points.shape[1] | |
//Round up data type size | |
var type = points.dtype | |
if(type === "int8" || | |
type === "int16" || | |
type === "int32" ) { | |
type = "int32" | |
} else if(type === "uint8" || | |
type === "uint8_clamped" || | |
type === "buffer" || | |
type === "uint16" || | |
type === "uint32") { | |
type = "uint32" | |
} else if(type === "float32") { | |
type = "float32" | |
} else { | |
type = "float64" | |
} | |
indexed = ndarray(pool.malloc(n*(d+1)), [n, d+1]) | |
ops.assign(indexed.hi(n,d), points) | |
} | |
for(var i=0; i<n; ++i) { | |
indexed.set(i, d, i) | |
} | |
var pointArray = ndscratch.malloc([n, d], points.dtype) | |
var indexArray = pool.mallocInt32(n) | |
var pointer = 0 | |
var pointData = pointArray.data | |
var arrayData = indexed.data | |
var l2_n = bits.log2(bits.nextPow2(n)) | |
var sel_cmp = ndselect.compile(indexed.order, true, indexed.dtype) | |
//Walk tree in level order | |
var toVisit = [indexed] | |
while(pointer < n) { | |
var head = toVisit.shift() | |
var array = head | |
var nn = array.shape[0]|0 | |
//Find median | |
if(nn > 1) { | |
var k = bits.log2(pointer+1)%d | |
var median | |
var n_2 = inorderTree.root(nn) | |
median = sel_cmp(array, n_2, function(a,b) { | |
return a.get(k) - b.get(k) | |
}) | |
//Copy into new array | |
var pptr = pointArray.index(pointer, 0) | |
var mptr = median.offset | |
for(var i=0; i<d; ++i) { | |
pointData[pptr++] = arrayData[mptr++] | |
} | |
indexArray[pointer] = arrayData[mptr] | |
pointer += 1 | |
//Queue new items | |
toVisit.push(array.hi(n_2)) | |
if(nn > 2) { | |
toVisit.push(array.lo(n_2+1)) | |
} | |
} else { | |
//Copy into new array | |
var mptr = array.offset | |
var pptr = pointArray.index(pointer, 0) | |
for(var i=0; i<d; ++i) { | |
pointData[pptr+i] = arrayData[mptr++] | |
} | |
indexArray[pointer] = arrayData[mptr] | |
pointer += 1 | |
} | |
} | |
//Release indexed | |
pool.free(indexed.data) | |
return new KDTree(pointArray, indexArray, n, d) | |
} | |
function deserializeKDTree(data) { | |
var points = data.p | |
var ids = data.i | |
if(points) { | |
var nd = points.length | |
var pointArray = pool.mallocFloat64(nd) | |
for(var i=0; i<nd; ++i) { | |
pointArray[i] = points[i] | |
} | |
var n = ids.length | |
var idArray = pool.mallocInt32(n) | |
for(var i=0; i<n; ++i) { | |
idArray[i] = ids[i] | |
} | |
var d = (nd/n)|0 | |
return new KDTree( | |
ndarray(pointArray, [n,d]), | |
idArray, | |
n, | |
d) | |
} else { | |
return new KDTree(null, null, 0, data.d) | |
} | |
} | |
},{"./lib/heap.js":5,"bit-twiddle":6,"inorder-tree-layout":7,"ndarray":22,"ndarray-ops":9,"ndarray-pack":14,"ndarray-scratch":20,"ndarray-select":21,"typedarray-pool":26}]},{},[]) | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9pbmRleC5qcyIsIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2J1ZmZlci9ub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCIuLi8uLi8uLi8uLi9ob21lL2FkbWluL2Jyb3dzZXJpZnktY2RuL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9idWZmZXIvbm9kZV9tb2R1bGVzL2llZWU3NTQvaW5kZXguanMiLCIuLi8uLi8uLi8uLi9ob21lL2FkbWluL2Jyb3dzZXJpZnktY2RuL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9idWZmZXIvbm9kZV9tb2R1bGVzL2lzYXJyYXkvaW5kZXguanMiLCJsaWIvaGVhcC5qcyIsIm5vZGVfbW9kdWxlcy9iaXQtdHdpZGRsZS90d2lkZGxlLmpzIiwibm9kZV9tb2R1bGVzL2lub3JkZXItdHJlZS1sYXlvdXQvaW5vcmRlci5qcyIsIm5vZGVfbW9kdWxlcy9uZGFycmF5LW9wcy9uZGFycmF5LW9wcy5qcyIsIm5vZGVfbW9kdWxlcy9uZGFycmF5LW9wcy9ub2RlX21vZHVsZXMvY3dpc2UtY29tcGlsZXIvY29tcGlsZXIuanMiLCJub2RlX21vZHVsZXMvbmRhcnJheS1vcHMvbm9kZV9tb2R1bGVzL2N3aXNlLWNvbXBpbGVyL2xpYi9jb21waWxlLmpzIiwibm9kZV9tb2R1bGVzL25kYXJyYXktb3BzL25vZGVfbW9kdWxlcy9jd2lzZS1jb21waWxlci9saWIvdGh1bmsuanMiLCJub2RlX21vZHVsZXMvbmRhcnJheS1vcHMvbm9kZV9tb2R1bGVzL2N3aXNlLWNvbXBpbGVyL25vZGVfbW9kdWxlcy91bmlxL3VuaXEuanMiLCJub2RlX21vZHVsZXMvbmRhcnJheS1wYWNrL2NvbnZlcnQuanMiLCJub2RlX21vZHVsZXMvbmRhcnJheS1wYWNrL2RvQ29udmVydC5qcyIsIm5vZGVfbW9kdWxlcy9uZGFycmF5LXNjcmF0Y2gvc2NyYXRjaC5qcyIsIm5vZGVfbW9kdWxlcy9uZGFycmF5LXNlbGVjdC9zZWxlY3QuanMiLCJub2RlX21vZHVsZXMvbmRhcnJheS9uZGFycmF5LmpzIiwibm9kZV9tb2R1bGVzL25kYXJyYXkvbm9kZV9tb2R1bGVzL2lvdGEtYXJyYXkvaW90YS5qcyIsIm5vZGVfbW9kdWxlcy9uZGFycmF5L25vZGVfbW9kdWxlcy9pcy1idWZmZXIvaW5kZXguanMiLCJub2RlX21vZHVsZXMvdHlwZWRhcnJheS1wb29sL25vZGVfbW9kdWxlcy9kdXAvZHVwLmpzIiwibm9kZV9tb2R1bGVzL3R5cGVkYXJyYXktcG9vbC9wb29sLmpzIiwia2R0cmVlLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL2dEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNU1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQzFLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN2NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xXQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQkE7QUFDQTs7Ozs7Ozs7OztBQ0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeE5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIoZnVuY3Rpb24gKGdsb2JhbCl7XG4vKiFcbiAqIFRoZSBidWZmZXIgbW9kdWxlIGZyb20gbm9kZS5qcywgZm9yIHRoZSBicm93c2VyLlxuICpcbiAqIEBhdXRob3IgICBGZXJvc3MgQWJvdWtoYWRpamVoIDxmZXJvc3NAZmVyb3NzLm9yZz4gPGh0dHA6Ly9mZXJvc3Mub3JnPlxuICogQGxpY2Vuc2UgIE1JVFxuICovXG4vKiBlc2xpbnQtZGlzYWJsZSBuby1wcm90byAqL1xuXG4ndXNlIHN0cmljdCdcblxudmFyIGJhc2U2NCA9IHJlcXVpcmUoJ2Jhc2U2NC1qcycpXG52YXIgaWVlZTc1NCA9IHJlcXVpcmUoJ2llZWU3NTQnKVxudmFyIGlzQXJyYXkgPSByZXF1aXJlKCdpc2FycmF5JylcblxuZXhwb3J0cy5CdWZmZXIgPSBCdWZmZXJcbmV4cG9ydHMuU2xvd0J1ZmZlciA9IFNsb3dCdWZmZXJcbmV4cG9ydHMuSU5TUEVDVF9NQVhfQllURVMgPSA1MFxuQnVmZmVyLnBvb2xTaXplID0gODE5MiAvLyBub3QgdXNlZCBieSB0aGlzIGltcGxlbWVudGF0aW9uXG5cbnZhciByb290UGFyZW50ID0ge31cblxuLyoqXG4gKiBJZiBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgOlxuICogICA9PT0gdHJ1ZSAgICBVc2UgVWludDhBcnJheSBpbXBsZW1lbnRhdGlvbiAoZmFzdGVzdClcbiAqICAgPT09IGZhbHNlICAgVXNlIE9iamVjdCBpbXBsZW1lbnRhdGlvbiAobW9zdCBjb21wYXRpYmxlLCBldmVuIElFNilcbiAqXG4gKiBCcm93c2VycyB0aGF0IHN1cHBvcnQgdHlwZWQgYXJyYXlzIGFyZSBJRSAxMCssIEZpcmVmb3ggNCssIENocm9tZSA3KywgU2FmYXJpIDUuMSssXG4gKiBPcGVyYSAxMS42KywgaU9TIDQuMisuXG4gKlxuICogRHVlIHRvIHZhcmlvdXMgYnJvd3NlciBidWdzLCBzb21ldGltZXMgdGhlIE9iamVjdCBpbXBsZW1lbnRhdGlvbiB3aWxsIGJlIHVzZWQgZXZlblxuICogd2hlbiB0aGUgYnJvd3NlciBzdXBwb3J0cyB0eXBlZCBhcnJheXMuXG4gKlxuICogTm90ZTpcbiAqXG4gKiAgIC0gRmlyZWZveCA0LTI5IGxhY2tzIHN1cHBvcnQgZm9yIGFkZGluZyBuZXcgcHJvcGVydGllcyB0byBgVWludDhBcnJheWAgaW5zdGFuY2VzLFxuICogICAgIFNlZTogaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9Njk1NDM4LlxuICpcbiAqICAgLSBTYWZhcmkgNS03IGxhY2tzIHN1cHBvcnQgZm9yIGNoYW5naW5nIHRoZSBgT2JqZWN0LnByb3RvdHlwZS5jb25zdHJ1Y3RvcmAgcHJvcGVydHlcbiAqICAgICBvbiBvYmplY3RzLlxuICpcbiAqICAgLSBDaHJvbWUgOS0xMCBpcyBtaXNzaW5nIHRoZSBgVHlwZWRBcnJheS5wcm90b3R5cGUuc3ViYXJyYXlgIGZ1bmN0aW9uLlxuICpcbiAqICAgLSBJRTEwIGhhcyBhIGJyb2tlbiBgVHlwZWRBcnJheS5wcm90b3R5cGUuc3ViYXJyYXlgIGZ1bmN0aW9uIHdoaWNoIHJldHVybnMgYXJyYXlzIG9mXG4gKiAgICAgaW5jb3JyZWN0IGxlbmd0aCBpbiBzb21lIHNpdHVhdGlvbnMuXG5cbiAqIFdlIGRldGVjdCB0aGVzZSBidWdneSBicm93c2VycyBhbmQgc2V0IGBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVGAgdG8gYGZhbHNlYCBzbyB0aGV5XG4gKiBnZXQgdGhlIE9iamVjdCBpbXBsZW1lbnRhdGlvbiwgd2hpY2ggaXMgc2xvd2VyIGJ1dCBiZWhhdmVzIGNvcnJlY3RseS5cbiAqL1xuQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgPSBnbG9iYWwuVFlQRURfQVJSQVlfU1VQUE9SVCAhPT0gdW5kZWZpbmVkXG4gID8gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlRcbiAgOiB0eXBlZEFycmF5U3VwcG9ydCgpXG5cbmZ1bmN0aW9uIHR5cGVkQXJyYXlTdXBwb3J0ICgpIHtcbiAgZnVuY3Rpb24gQmFyICgpIHt9XG4gIHRyeSB7XG4gICAgdmFyIGFyciA9IG5ldyBVaW50OEFycmF5KDEpXG4gICAgYXJyLmZvbyA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIDQyIH1cbiAgICBhcnIuY29uc3RydWN0b3IgPSBCYXJcbiAgICByZXR1cm4gYXJyLmZvbygpID09PSA0MiAmJiAvLyB0eXBlZCBhcnJheSBpbnN0YW5jZXMgY2FuIGJlIGF1Z21lbnRlZFxuICAgICAgICBhcnIuY29uc3RydWN0b3IgPT09IEJhciAmJiAvLyBjb25zdHJ1Y3RvciBjYW4gYmUgc2V0XG4gICAgICAgIHR5cGVvZiBhcnIuc3ViYXJyYXkgPT09ICdmdW5jdGlvbicgJiYgLy8gY2hyb21lIDktMTAgbGFjayBgc3ViYXJyYXlgXG4gICAgICAgIGFyci5zdWJhcnJheSgxLCAxKS5ieXRlTGVuZ3RoID09PSAwIC8vIGllMTAgaGFzIGJyb2tlbiBgc3ViYXJyYXlgXG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5mdW5jdGlvbiBrTWF4TGVuZ3RoICgpIHtcbiAgcmV0dXJuIEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gICAgPyAweDdmZmZmZmZmXG4gICAgOiAweDNmZmZmZmZmXG59XG5cbi8qKlxuICogQ2xhc3M6IEJ1ZmZlclxuICogPT09PT09PT09PT09PVxuICpcbiAqIFRoZSBCdWZmZXIgY29uc3RydWN0b3IgcmV0dXJucyBpbnN0YW5jZXMgb2YgYFVpbnQ4QXJyYXlgIHRoYXQgYXJlIGF1Z21lbnRlZFxuICogd2l0aCBmdW5jdGlvbiBwcm9wZXJ0aWVzIGZvciBhbGwgdGhlIG5vZGUgYEJ1ZmZlcmAgQVBJIGZ1bmN0aW9ucy4gV2UgdXNlXG4gKiBgVWludDhBcnJheWAgc28gdGhhdCBzcXVhcmUgYnJhY2tldCBub3RhdGlvbiB3b3JrcyBhcyBleHBlY3RlZCAtLSBpdCByZXR1cm5zXG4gKiBhIHNpbmdsZSBvY3RldC5cbiAqXG4gKiBCeSBhdWdtZW50aW5nIHRoZSBpbnN0YW5jZXMsIHdlIGNhbiBhdm9pZCBtb2RpZnlpbmcgdGhlIGBVaW50OEFycmF5YFxuICogcHJvdG90eXBlLlxuICovXG5mdW5jdGlvbiBCdWZmZXIgKGFyZykge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgQnVmZmVyKSkge1xuICAgIC8vIEF2b2lkIGdvaW5nIHRocm91Z2ggYW4gQXJndW1lbnRzQWRhcHRvclRyYW1wb2xpbmUgaW4gdGhlIGNvbW1vbiBjYXNlLlxuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMSkgcmV0dXJuIG5ldyBCdWZmZXIoYXJnLCBhcmd1bWVudHNbMV0pXG4gICAgcmV0dXJuIG5ldyBCdWZmZXIoYXJnKVxuICB9XG5cbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXMubGVuZ3RoID0gMFxuICAgIHRoaXMucGFyZW50ID0gdW5kZWZpbmVkXG4gIH1cblxuICAvLyBDb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIGZyb21OdW1iZXIodGhpcywgYXJnKVxuICB9XG5cbiAgLy8gU2xpZ2h0bHkgbGVzcyBjb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGZyb21TdHJpbmcodGhpcywgYXJnLCBhcmd1bWVudHMubGVuZ3RoID4gMSA/IGFyZ3VtZW50c1sxXSA6ICd1dGY4JylcbiAgfVxuXG4gIC8vIFVudXN1YWwuXG4gIHJldHVybiBmcm9tT2JqZWN0KHRoaXMsIGFyZylcbn1cblxuZnVuY3Rpb24gZnJvbU51bWJlciAodGhhdCwgbGVuZ3RoKSB7XG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGggPCAwID8gMCA6IGNoZWNrZWQobGVuZ3RoKSB8IDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICB0aGF0W2ldID0gMFxuICAgIH1cbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tU3RyaW5nICh0aGF0LCBzdHJpbmcsIGVuY29kaW5nKSB7XG4gIGlmICh0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnIHx8IGVuY29kaW5nID09PSAnJykgZW5jb2RpbmcgPSAndXRmOCdcblxuICAvLyBBc3N1bXB0aW9uOiBieXRlTGVuZ3RoKCkgcmV0dXJuIHZhbHVlIGlzIGFsd2F5cyA8IGtNYXhMZW5ndGguXG4gIHZhciBsZW5ndGggPSBieXRlTGVuZ3RoKHN0cmluZywgZW5jb2RpbmcpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuXG4gIHRoYXQud3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbU9iamVjdCAodGhhdCwgb2JqZWN0KSB7XG4gIGlmIChCdWZmZXIuaXNCdWZmZXIob2JqZWN0KSkgcmV0dXJuIGZyb21CdWZmZXIodGhhdCwgb2JqZWN0KVxuXG4gIGlmIChpc0FycmF5KG9iamVjdCkpIHJldHVybiBmcm9tQXJyYXkodGhhdCwgb2JqZWN0KVxuXG4gIGlmIChvYmplY3QgPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ211c3Qgc3RhcnQgd2l0aCBudW1iZXIsIGJ1ZmZlciwgYXJyYXkgb3Igc3RyaW5nJylcbiAgfVxuXG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaWYgKG9iamVjdC5idWZmZXIgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikge1xuICAgICAgcmV0dXJuIGZyb21UeXBlZEFycmF5KHRoYXQsIG9iamVjdClcbiAgICB9XG4gICAgaWYgKG9iamVjdCBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgICByZXR1cm4gZnJvbUFycmF5QnVmZmVyKHRoYXQsIG9iamVjdClcbiAgICB9XG4gIH1cblxuICBpZiAob2JqZWN0Lmxlbmd0aCkgcmV0dXJuIGZyb21BcnJheUxpa2UodGhhdCwgb2JqZWN0KVxuXG4gIHJldHVybiBmcm9tSnNvbk9iamVjdCh0aGF0LCBvYmplY3QpXG59XG5cbmZ1bmN0aW9uIGZyb21CdWZmZXIgKHRoYXQsIGJ1ZmZlcikge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChidWZmZXIubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGFsbG9jYXRlKHRoYXQsIGxlbmd0aClcbiAgYnVmZmVyLmNvcHkodGhhdCwgMCwgMCwgbGVuZ3RoKVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXkgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vLyBEdXBsaWNhdGUgb2YgZnJvbUFycmF5KCkgdG8ga2VlcCBmcm9tQXJyYXkoKSBtb25vbW9ycGhpYy5cbmZ1bmN0aW9uIGZyb21UeXBlZEFycmF5ICh0aGF0LCBhcnJheSkge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICAvLyBUcnVuY2F0aW5nIHRoZSBlbGVtZW50cyBpcyBwcm9iYWJseSBub3Qgd2hhdCBwZW9wbGUgZXhwZWN0IGZyb20gdHlwZWRcbiAgLy8gYXJyYXlzIHdpdGggQllURVNfUEVSX0VMRU1FTlQgPiAxIGJ1dCBpdCdzIGNvbXBhdGlibGUgd2l0aCB0aGUgYmVoYXZpb3JcbiAgLy8gb2YgdGhlIG9sZCBCdWZmZXIgY29uc3RydWN0b3IuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlCdWZmZXIgKHRoYXQsIGFycmF5KSB7XG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIFJldHVybiBhbiBhdWdtZW50ZWQgYFVpbnQ4QXJyYXlgIGluc3RhbmNlLCBmb3IgYmVzdCBwZXJmb3JtYW5jZVxuICAgIGFycmF5LmJ5dGVMZW5ndGhcbiAgICB0aGF0ID0gQnVmZmVyLl9hdWdtZW50KG5ldyBVaW50OEFycmF5KGFycmF5KSlcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgdGhhdCA9IGZyb21UeXBlZEFycmF5KHRoYXQsIG5ldyBVaW50OEFycmF5KGFycmF5KSlcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlMaWtlICh0aGF0LCBhcnJheSkge1xuICB2YXIgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB0aGF0ID0gYWxsb2NhdGUodGhhdCwgbGVuZ3RoKVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuLy8gRGVzZXJpYWxpemUgeyB0eXBlOiAnQnVmZmVyJywgZGF0YTogWzEsMiwzLC4uLl0gfSBpbnRvIGEgQnVmZmVyIG9iamVjdC5cbi8vIFJldHVybnMgYSB6ZXJvLWxlbmd0aCBidWZmZXIgZm9yIGlucHV0cyB0aGF0IGRvbid0IGNvbmZvcm0gdG8gdGhlIHNwZWMuXG5mdW5jdGlvbiBmcm9tSnNvbk9iamVjdCAodGhhdCwgb2JqZWN0KSB7XG4gIHZhciBhcnJheVxuICB2YXIgbGVuZ3RoID0gMFxuXG4gIGlmIChvYmplY3QudHlwZSA9PT0gJ0J1ZmZlcicgJiYgaXNBcnJheShvYmplY3QuZGF0YSkpIHtcbiAgICBhcnJheSA9IG9iamVjdC5kYXRhXG4gICAgbGVuZ3RoID0gY2hlY2tlZChhcnJheS5sZW5ndGgpIHwgMFxuICB9XG4gIHRoYXQgPSBhbGxvY2F0ZSh0aGF0LCBsZW5ndGgpXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSkge1xuICAgIHRoYXRbaV0gPSBhcnJheVtpXSAmIDI1NVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbmlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICBCdWZmZXIucHJvdG90eXBlLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXkucHJvdG90eXBlXG4gIEJ1ZmZlci5fX3Byb3RvX18gPSBVaW50OEFycmF5XG59IGVsc2Uge1xuICAvLyBwcmUtc2V0IGZvciB2YWx1ZXMgdGhhdCBtYXkgZXhpc3QgaW4gdGhlIGZ1dHVyZVxuICBCdWZmZXIucHJvdG90eXBlLmxlbmd0aCA9IHVuZGVmaW5lZFxuICBCdWZmZXIucHJvdG90eXBlLnBhcmVudCA9IHVuZGVmaW5lZFxufVxuXG5mdW5jdGlvbiBhbGxvY2F0ZSAodGhhdCwgbGVuZ3RoKSB7XG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIFJldHVybiBhbiBhdWdtZW50ZWQgYFVpbnQ4QXJyYXlgIGluc3RhbmNlLCBmb3IgYmVzdCBwZXJmb3JtYW5jZVxuICAgIHRoYXQgPSBCdWZmZXIuX2F1Z21lbnQobmV3IFVpbnQ4QXJyYXkobGVuZ3RoKSlcbiAgICB0aGF0Ll9fcHJvdG9fXyA9IEJ1ZmZlci5wcm90b3R5cGVcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgdGhhdC5sZW5ndGggPSBsZW5ndGhcbiAgICB0aGF0Ll9pc0J1ZmZlciA9IHRydWVcbiAgfVxuXG4gIHZhciBmcm9tUG9vbCA9IGxlbmd0aCAhPT0gMCAmJiBsZW5ndGggPD0gQnVmZmVyLnBvb2xTaXplID4+PiAxXG4gIGlmIChmcm9tUG9vbCkgdGhhdC5wYXJlbnQgPSByb290UGFyZW50XG5cbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gY2hlY2tlZCAobGVuZ3RoKSB7XG4gIC8vIE5vdGU6IGNhbm5vdCB1c2UgYGxlbmd0aCA8IGtNYXhMZW5ndGhgIGhlcmUgYmVjYXVzZSB0aGF0IGZhaWxzIHdoZW5cbiAgLy8gbGVuZ3RoIGlzIE5hTiAod2hpY2ggaXMgb3RoZXJ3aXNlIGNvZXJjZWQgdG8gemVyby4pXG4gIGlmIChsZW5ndGggPj0ga01heExlbmd0aCgpKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ0F0dGVtcHQgdG8gYWxsb2NhdGUgQnVmZmVyIGxhcmdlciB0aGFuIG1heGltdW0gJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgJ3NpemU6IDB4JyArIGtNYXhMZW5ndGgoKS50b1N0cmluZygxNikgKyAnIGJ5dGVzJylcbiAgfVxuICByZXR1cm4gbGVuZ3RoIHwgMFxufVxuXG5mdW5jdGlvbiBTbG93QnVmZmVyIChzdWJqZWN0LCBlbmNvZGluZykge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgU2xvd0J1ZmZlcikpIHJldHVybiBuZXcgU2xvd0J1ZmZlcihzdWJqZWN0LCBlbmNvZGluZylcblxuICB2YXIgYnVmID0gbmV3IEJ1ZmZlcihzdWJqZWN0LCBlbmNvZGluZylcbiAgZGVsZXRlIGJ1Zi5wYXJlbnRcbiAgcmV0dXJuIGJ1ZlxufVxuXG5CdWZmZXIuaXNCdWZmZXIgPSBmdW5jdGlvbiBpc0J1ZmZlciAoYikge1xuICByZXR1cm4gISEoYiAhPSBudWxsICYmIGIuX2lzQnVmZmVyKVxufVxuXG5CdWZmZXIuY29tcGFyZSA9IGZ1bmN0aW9uIGNvbXBhcmUgKGEsIGIpIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoYSkgfHwgIUJ1ZmZlci5pc0J1ZmZlcihiKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50cyBtdXN0IGJlIEJ1ZmZlcnMnKVxuICB9XG5cbiAgaWYgKGEgPT09IGIpIHJldHVybiAwXG5cbiAgdmFyIHggPSBhLmxlbmd0aFxuICB2YXIgeSA9IGIubGVuZ3RoXG5cbiAgdmFyIGkgPSAwXG4gIHZhciBsZW4gPSBNYXRoLm1pbih4LCB5KVxuICB3aGlsZSAoaSA8IGxlbikge1xuICAgIGlmIChhW2ldICE9PSBiW2ldKSBicmVha1xuXG4gICAgKytpXG4gIH1cblxuICBpZiAoaSAhPT0gbGVuKSB7XG4gICAgeCA9IGFbaV1cbiAgICB5ID0gYltpXVxuICB9XG5cbiAgaWYgKHggPCB5KSByZXR1cm4gLTFcbiAgaWYgKHkgPCB4KSByZXR1cm4gMVxuICByZXR1cm4gMFxufVxuXG5CdWZmZXIuaXNFbmNvZGluZyA9IGZ1bmN0aW9uIGlzRW5jb2RpbmcgKGVuY29kaW5nKSB7XG4gIHN3aXRjaCAoU3RyaW5nKGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpKSB7XG4gICAgY2FzZSAnaGV4JzpcbiAgICBjYXNlICd1dGY4JzpcbiAgICBjYXNlICd1dGYtOCc6XG4gICAgY2FzZSAnYXNjaWknOlxuICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgY2FzZSAnYmFzZTY0JzpcbiAgICBjYXNlICdyYXcnOlxuICAgIGNhc2UgJ3VjczInOlxuICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICBjYXNlICd1dGYxNmxlJzpcbiAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5CdWZmZXIuY29uY2F0ID0gZnVuY3Rpb24gY29uY2F0IChsaXN0LCBsZW5ndGgpIHtcbiAgaWYgKCFpc0FycmF5KGxpc3QpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdsaXN0IGFyZ3VtZW50IG11c3QgYmUgYW4gQXJyYXkgb2YgQnVmZmVycy4nKVxuXG4gIGlmIChsaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBuZXcgQnVmZmVyKDApXG4gIH1cblxuICB2YXIgaVxuICBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQpIHtcbiAgICBsZW5ndGggPSAwXG4gICAgZm9yIChpID0gMDsgaSA8IGxpc3QubGVuZ3RoOyBpKyspIHtcbiAgICAgIGxlbmd0aCArPSBsaXN0W2ldLmxlbmd0aFxuICAgIH1cbiAgfVxuXG4gIHZhciBidWYgPSBuZXcgQnVmZmVyKGxlbmd0aClcbiAgdmFyIHBvcyA9IDBcbiAgZm9yIChpID0gMDsgaSA8IGxpc3QubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgaXRlbSA9IGxpc3RbaV1cbiAgICBpdGVtLmNvcHkoYnVmLCBwb3MpXG4gICAgcG9zICs9IGl0ZW0ubGVuZ3RoXG4gIH1cbiAgcmV0dXJuIGJ1ZlxufVxuXG5mdW5jdGlvbiBieXRlTGVuZ3RoIChzdHJpbmcsIGVuY29kaW5nKSB7XG4gIGlmICh0eXBlb2Ygc3RyaW5nICE9PSAnc3RyaW5nJykgc3RyaW5nID0gJycgKyBzdHJpbmdcblxuICB2YXIgbGVuID0gc3RyaW5nLmxlbmd0aFxuICBpZiAobGVuID09PSAwKSByZXR1cm4gMFxuXG4gIC8vIFVzZSBhIGZvciBsb29wIHRvIGF2b2lkIHJlY3Vyc2lvblxuICB2YXIgbG93ZXJlZENhc2UgPSBmYWxzZVxuICBmb3IgKDs7KSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgIC8vIERlcHJlY2F0ZWRcbiAgICAgIGNhc2UgJ3Jhdyc6XG4gICAgICBjYXNlICdyYXdzJzpcbiAgICAgICAgcmV0dXJuIGxlblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4VG9CeXRlcyhzdHJpbmcpLmxlbmd0aFxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIGxlbiAqIDJcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBsZW4gPj4+IDFcbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIHJldHVybiBiYXNlNjRUb0J5dGVzKHN0cmluZykubGVuZ3RoXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHJldHVybiB1dGY4VG9CeXRlcyhzdHJpbmcpLmxlbmd0aCAvLyBhc3N1bWUgdXRmOFxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuQnVmZmVyLmJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoXG5cbmZ1bmN0aW9uIHNsb3dUb1N0cmluZyAoZW5jb2RpbmcsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcblxuICBzdGFydCA9IHN0YXJ0IHwgMFxuICBlbmQgPSBlbmQgPT09IHVuZGVmaW5lZCB8fCBlbmQgPT09IEluZmluaXR5ID8gdGhpcy5sZW5ndGggOiBlbmQgfCAwXG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcbiAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKGVuZCA8PSBzdGFydCkgcmV0dXJuICcnXG5cbiAgd2hpbGUgKHRydWUpIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1dGYxNmxlU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKGVuY29kaW5nICsgJycpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbiB0b1N0cmluZyAoKSB7XG4gIHZhciBsZW5ndGggPSB0aGlzLmxlbmd0aCB8IDBcbiAgaWYgKGxlbmd0aCA9PT0gMCkgcmV0dXJuICcnXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIDAsIGxlbmd0aClcbiAgcmV0dXJuIHNsb3dUb1N0cmluZy5hcHBseSh0aGlzLCBhcmd1bWVudHMpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24gZXF1YWxzIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiB0cnVlXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKSA9PT0gMFxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluc3BlY3QgPSBmdW5jdGlvbiBpbnNwZWN0ICgpIHtcbiAgdmFyIHN0ciA9ICcnXG4gIHZhciBtYXggPSBleHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTXG4gIGlmICh0aGlzLmxlbmd0aCA+IDApIHtcbiAgICBzdHIgPSB0aGlzLnRvU3RyaW5nKCdoZXgnLCAwLCBtYXgpLm1hdGNoKC8uezJ9L2cpLmpvaW4oJyAnKVxuICAgIGlmICh0aGlzLmxlbmd0aCA+IG1heCkgc3RyICs9ICcgLi4uICdcbiAgfVxuICByZXR1cm4gJzxCdWZmZXIgJyArIHN0ciArICc+J1xufVxuXG5CdWZmZXIucHJvdG90eXBlLmNvbXBhcmUgPSBmdW5jdGlvbiBjb21wYXJlIChiKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgaWYgKHRoaXMgPT09IGIpIHJldHVybiAwXG4gIHJldHVybiBCdWZmZXIuY29tcGFyZSh0aGlzLCBiKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluZGV4T2YgPSBmdW5jdGlvbiBpbmRleE9mICh2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgaWYgKGJ5dGVPZmZzZXQgPiAweDdmZmZmZmZmKSBieXRlT2Zmc2V0ID0gMHg3ZmZmZmZmZlxuICBlbHNlIGlmIChieXRlT2Zmc2V0IDwgLTB4ODAwMDAwMDApIGJ5dGVPZmZzZXQgPSAtMHg4MDAwMDAwMFxuICBieXRlT2Zmc2V0ID4+PSAwXG5cbiAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gLTFcbiAgaWYgKGJ5dGVPZmZzZXQgPj0gdGhpcy5sZW5ndGgpIHJldHVybiAtMVxuXG4gIC8vIE5lZ2F0aXZlIG9mZnNldHMgc3RhcnQgZnJvbSB0aGUgZW5kIG9mIHRoZSBidWZmZXJcbiAgaWYgKGJ5dGVPZmZzZXQgPCAwKSBieXRlT2Zmc2V0ID0gTWF0aC5tYXgodGhpcy5sZW5ndGggKyBieXRlT2Zmc2V0LCAwKVxuXG4gIGlmICh0eXBlb2YgdmFsID09PSAnc3RyaW5nJykge1xuICAgIGlmICh2YWwubGVuZ3RoID09PSAwKSByZXR1cm4gLTEgLy8gc3BlY2lhbCBjYXNlOiBsb29raW5nIGZvciBlbXB0eSBzdHJpbmcgYWx3YXlzIGZhaWxzXG4gICAgcmV0dXJuIFN0cmluZy5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHZhbCkpIHtcbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgfVxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ251bWJlcicpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgJiYgVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgcmV0dXJuIFVpbnQ4QXJyYXkucHJvdG90eXBlLmluZGV4T2YuY2FsbCh0aGlzLCB2YWwsIGJ5dGVPZmZzZXQpXG4gICAgfVxuICAgIHJldHVybiBhcnJheUluZGV4T2YodGhpcywgWyB2YWwgXSwgYnl0ZU9mZnNldClcbiAgfVxuXG4gIGZ1bmN0aW9uIGFycmF5SW5kZXhPZiAoYXJyLCB2YWwsIGJ5dGVPZmZzZXQpIHtcbiAgICB2YXIgZm91bmRJbmRleCA9IC0xXG4gICAgZm9yICh2YXIgaSA9IDA7IGJ5dGVPZmZzZXQgKyBpIDwgYXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoYXJyW2J5dGVPZmZzZXQgKyBpXSA9PT0gdmFsW2ZvdW5kSW5kZXggPT09IC0xID8gMCA6IGkgLSBmb3VuZEluZGV4XSkge1xuICAgICAgICBpZiAoZm91bmRJbmRleCA9PT0gLTEpIGZvdW5kSW5kZXggPSBpXG4gICAgICAgIGlmIChpIC0gZm91bmRJbmRleCArIDEgPT09IHZhbC5sZW5ndGgpIHJldHVybiBieXRlT2Zmc2V0ICsgZm91bmRJbmRleFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZm91bmRJbmRleCA9IC0xXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAtMVxuICB9XG5cbiAgdGhyb3cgbmV3IFR5cGVFcnJvcigndmFsIG11c3QgYmUgc3RyaW5nLCBudW1iZXIgb3IgQnVmZmVyJylcbn1cblxuLy8gYGdldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5nZXQgPSBmdW5jdGlvbiBnZXQgKG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLmdldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMucmVhZFVJbnQ4KG9mZnNldClcbn1cblxuLy8gYHNldGAgaXMgZGVwcmVjYXRlZFxuQnVmZmVyLnByb3RvdHlwZS5zZXQgPSBmdW5jdGlvbiBzZXQgKHYsIG9mZnNldCkge1xuICBjb25zb2xlLmxvZygnLnNldCgpIGlzIGRlcHJlY2F0ZWQuIEFjY2VzcyB1c2luZyBhcnJheSBpbmRleGVzIGluc3RlYWQuJylcbiAgcmV0dXJuIHRoaXMud3JpdGVVSW50OCh2LCBvZmZzZXQpXG59XG5cbmZ1bmN0aW9uIGhleFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgb2Zmc2V0ID0gTnVtYmVyKG9mZnNldCkgfHwgMFxuICB2YXIgcmVtYWluaW5nID0gYnVmLmxlbmd0aCAtIG9mZnNldFxuICBpZiAoIWxlbmd0aCkge1xuICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICB9IGVsc2Uge1xuICAgIGxlbmd0aCA9IE51bWJlcihsZW5ndGgpXG4gICAgaWYgKGxlbmd0aCA+IHJlbWFpbmluZykge1xuICAgICAgbGVuZ3RoID0gcmVtYWluaW5nXG4gICAgfVxuICB9XG5cbiAgLy8gbXVzdCBiZSBhbiBldmVuIG51bWJlciBvZiBkaWdpdHNcbiAgdmFyIHN0ckxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKHN0ckxlbiAlIDIgIT09IDApIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcblxuICBpZiAobGVuZ3RoID4gc3RyTGVuIC8gMikge1xuICAgIGxlbmd0aCA9IHN0ckxlbiAvIDJcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHBhcnNlZCA9IHBhcnNlSW50KHN0cmluZy5zdWJzdHIoaSAqIDIsIDIpLCAxNilcbiAgICBpZiAoaXNOYU4ocGFyc2VkKSkgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGhleCBzdHJpbmcnKVxuICAgIGJ1ZltvZmZzZXQgKyBpXSA9IHBhcnNlZFxuICB9XG4gIHJldHVybiBpXG59XG5cbmZ1bmN0aW9uIHV0ZjhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjhUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGFzY2lpV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihhc2NpaVRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmluYXJ5V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYXNjaWlXcml0ZShidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGJhc2U2NFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYmFzZTY0VG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiB1Y3MyV3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGYxNmxlVG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlID0gZnVuY3Rpb24gd3JpdGUgKHN0cmluZywgb2Zmc2V0LCBsZW5ndGgsIGVuY29kaW5nKSB7XG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcpXG4gIGlmIChvZmZzZXQgPT09IHVuZGVmaW5lZCkge1xuICAgIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIGVuY29kaW5nKVxuICB9IGVsc2UgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkICYmIHR5cGVvZiBvZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgZW5jb2RpbmcgPSBvZmZzZXRcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgb2Zmc2V0WywgbGVuZ3RoXVssIGVuY29kaW5nXSlcbiAgfSBlbHNlIGlmIChpc0Zpbml0ZShvZmZzZXQpKSB7XG4gICAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICAgIGlmIChpc0Zpbml0ZShsZW5ndGgpKSB7XG4gICAgICBsZW5ndGggPSBsZW5ndGggfCAwXG4gICAgICBpZiAoZW5jb2RpbmcgPT09IHVuZGVmaW5lZCkgZW5jb2RpbmcgPSAndXRmOCdcbiAgICB9IGVsc2Uge1xuICAgICAgZW5jb2RpbmcgPSBsZW5ndGhcbiAgICAgIGxlbmd0aCA9IHVuZGVmaW5lZFxuICAgIH1cbiAgLy8gbGVnYWN5IHdyaXRlKHN0cmluZywgZW5jb2RpbmcsIG9mZnNldCwgbGVuZ3RoKSAtIHJlbW92ZSBpbiB2MC4xM1xuICB9IGVsc2Uge1xuICAgIHZhciBzd2FwID0gZW5jb2RpbmdcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIG9mZnNldCA9IGxlbmd0aCB8IDBcbiAgICBsZW5ndGggPSBzd2FwXG4gIH1cblxuICB2YXIgcmVtYWluaW5nID0gdGhpcy5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkIHx8IGxlbmd0aCA+IHJlbWFpbmluZykgbGVuZ3RoID0gcmVtYWluaW5nXG5cbiAgaWYgKChzdHJpbmcubGVuZ3RoID4gMCAmJiAobGVuZ3RoIDwgMCB8fCBvZmZzZXQgPCAwKSkgfHwgb2Zmc2V0ID4gdGhpcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignYXR0ZW1wdCB0byB3cml0ZSBvdXRzaWRlIGJ1ZmZlciBib3VuZHMnKVxuICB9XG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcblxuICB2YXIgbG93ZXJlZENhc2UgPSBmYWxzZVxuICBmb3IgKDs7KSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGJpbmFyeVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIC8vIFdhcm5pbmc6IG1heExlbmd0aCBub3QgdGFrZW4gaW50byBhY2NvdW50IGluIGJhc2U2NFdyaXRlXG4gICAgICAgIHJldHVybiBiYXNlNjRXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gdWNzMldyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvSlNPTiA9IGZ1bmN0aW9uIHRvSlNPTiAoKSB7XG4gIHJldHVybiB7XG4gICAgdHlwZTogJ0J1ZmZlcicsXG4gICAgZGF0YTogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodGhpcy5fYXJyIHx8IHRoaXMsIDApXG4gIH1cbn1cblxuZnVuY3Rpb24gYmFzZTY0U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICBpZiAoc3RhcnQgPT09IDAgJiYgZW5kID09PSBidWYubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGJhc2U2NC5mcm9tQnl0ZUFycmF5KGJ1ZilcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmLnNsaWNlKHN0YXJ0LCBlbmQpKVxuICB9XG59XG5cbmZ1bmN0aW9uIHV0ZjhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcbiAgdmFyIHJlcyA9IFtdXG5cbiAgdmFyIGkgPSBzdGFydFxuICB3aGlsZSAoaSA8IGVuZCkge1xuICAgIHZhciBmaXJzdEJ5dGUgPSBidWZbaV1cbiAgICB2YXIgY29kZVBvaW50ID0gbnVsbFxuICAgIHZhciBieXRlc1BlclNlcXVlbmNlID0gKGZpcnN0Qnl0ZSA+IDB4RUYpID8gNFxuICAgICAgOiAoZmlyc3RCeXRlID4gMHhERikgPyAzXG4gICAgICA6IChmaXJzdEJ5dGUgPiAweEJGKSA/IDJcbiAgICAgIDogMVxuXG4gICAgaWYgKGkgKyBieXRlc1BlclNlcXVlbmNlIDw9IGVuZCkge1xuICAgICAgdmFyIHNlY29uZEJ5dGUsIHRoaXJkQnl0ZSwgZm91cnRoQnl0ZSwgdGVtcENvZGVQb2ludFxuXG4gICAgICBzd2l0Y2ggKGJ5dGVzUGVyU2VxdWVuY2UpIHtcbiAgICAgICAgY2FzZSAxOlxuICAgICAgICAgIGlmIChmaXJzdEJ5dGUgPCAweDgwKSB7XG4gICAgICAgICAgICBjb2RlUG9pbnQgPSBmaXJzdEJ5dGVcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHgxRikgPDwgMHg2IHwgKHNlY29uZEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweDdGKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGlmICgoc2Vjb25kQnl0ZSAmIDB4QzApID09PSAweDgwICYmICh0aGlyZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4QyB8IChzZWNvbmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKHRoaXJkQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0ZGICYmICh0ZW1wQ29kZVBvaW50IDwgMHhEODAwIHx8IHRlbXBDb2RlUG9pbnQgPiAweERGRkYpKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgIHNlY29uZEJ5dGUgPSBidWZbaSArIDFdXG4gICAgICAgICAgdGhpcmRCeXRlID0gYnVmW2kgKyAyXVxuICAgICAgICAgIGZvdXJ0aEJ5dGUgPSBidWZbaSArIDNdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwICYmIChmb3VydGhCeXRlICYgMHhDMCkgPT09IDB4ODApIHtcbiAgICAgICAgICAgIHRlbXBDb2RlUG9pbnQgPSAoZmlyc3RCeXRlICYgMHhGKSA8PCAweDEyIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweEMgfCAodGhpcmRCeXRlICYgMHgzRikgPDwgMHg2IHwgKGZvdXJ0aEJ5dGUgJiAweDNGKVxuICAgICAgICAgICAgaWYgKHRlbXBDb2RlUG9pbnQgPiAweEZGRkYgJiYgdGVtcENvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICAgICAgICAgIGNvZGVQb2ludCA9IHRlbXBDb2RlUG9pbnRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGNvZGVQb2ludCA9PT0gbnVsbCkge1xuICAgICAgLy8gd2UgZGlkIG5vdCBnZW5lcmF0ZSBhIHZhbGlkIGNvZGVQb2ludCBzbyBpbnNlcnQgYVxuICAgICAgLy8gcmVwbGFjZW1lbnQgY2hhciAoVStGRkZEKSBhbmQgYWR2YW5jZSBvbmx5IDEgYnl0ZVxuICAgICAgY29kZVBvaW50ID0gMHhGRkZEXG4gICAgICBieXRlc1BlclNlcXVlbmNlID0gMVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50ID4gMHhGRkZGKSB7XG4gICAgICAvLyBlbmNvZGUgdG8gdXRmMTYgKHN1cnJvZ2F0ZSBwYWlyIGRhbmNlKVxuICAgICAgY29kZVBvaW50IC09IDB4MTAwMDBcbiAgICAgIHJlcy5wdXNoKGNvZGVQb2ludCA+Pj4gMTAgJiAweDNGRiB8IDB4RDgwMClcbiAgICAgIGNvZGVQb2ludCA9IDB4REMwMCB8IGNvZGVQb2ludCAmIDB4M0ZGXG4gICAgfVxuXG4gICAgcmVzLnB1c2goY29kZVBvaW50KVxuICAgIGkgKz0gYnl0ZXNQZXJTZXF1ZW5jZVxuICB9XG5cbiAgcmV0dXJuIGRlY29kZUNvZGVQb2ludHNBcnJheShyZXMpXG59XG5cbi8vIEJhc2VkIG9uIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzIyNzQ3MjcyLzY4MDc0MiwgdGhlIGJyb3dzZXIgd2l0aFxuLy8gdGhlIGxvd2VzdCBsaW1pdCBpcyBDaHJvbWUsIHdpdGggMHgxMDAwMCBhcmdzLlxuLy8gV2UgZ28gMSBtYWduaXR1ZGUgbGVzcywgZm9yIHNhZmV0eVxudmFyIE1BWF9BUkdVTUVOVFNfTEVOR1RIID0gMHgxMDAwXG5cbmZ1bmN0aW9uIGRlY29kZUNvZGVQb2ludHNBcnJheSAoY29kZVBvaW50cykge1xuICB2YXIgbGVuID0gY29kZVBvaW50cy5sZW5ndGhcbiAgaWYgKGxlbiA8PSBNQVhfQVJHVU1FTlRTX0xFTkdUSCkge1xuICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFN0cmluZywgY29kZVBvaW50cykgLy8gYXZvaWQgZXh0cmEgc2xpY2UoKVxuICB9XG5cbiAgLy8gRGVjb2RlIGluIGNodW5rcyB0byBhdm9pZCBcImNhbGwgc3RhY2sgc2l6ZSBleGNlZWRlZFwiLlxuICB2YXIgcmVzID0gJydcbiAgdmFyIGkgPSAwXG4gIHdoaWxlIChpIDwgbGVuKSB7XG4gICAgcmVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoXG4gICAgICBTdHJpbmcsXG4gICAgICBjb2RlUG9pbnRzLnNsaWNlKGksIGkgKz0gTUFYX0FSR1VNRU5UU19MRU5HVEgpXG4gICAgKVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0gJiAweDdGKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gYmluYXJ5U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgcmV0ID0gJydcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgcmV0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnVmW2ldKVxuICB9XG4gIHJldHVybiByZXRcbn1cblxuZnVuY3Rpb24gaGV4U2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gYnVmLmxlbmd0aFxuXG4gIGlmICghc3RhcnQgfHwgc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgfHwgZW5kIDwgMCB8fCBlbmQgPiBsZW4pIGVuZCA9IGxlblxuXG4gIHZhciBvdXQgPSAnJ1xuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgIG91dCArPSB0b0hleChidWZbaV0pXG4gIH1cbiAgcmV0dXJuIG91dFxufVxuXG5mdW5jdGlvbiB1dGYxNmxlU2xpY2UgKGJ1Ziwgc3RhcnQsIGVuZCkge1xuICB2YXIgYnl0ZXMgPSBidWYuc2xpY2Uoc3RhcnQsIGVuZClcbiAgdmFyIHJlcyA9ICcnXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShieXRlc1tpXSArIGJ5dGVzW2kgKyAxXSAqIDI1NilcbiAgfVxuICByZXR1cm4gcmVzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc2xpY2UgPSBmdW5jdGlvbiBzbGljZSAoc3RhcnQsIGVuZCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgc3RhcnQgPSB+fnN0YXJ0XG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gbGVuIDogfn5lbmRcblxuICBpZiAoc3RhcnQgPCAwKSB7XG4gICAgc3RhcnQgKz0gbGVuXG4gICAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSAwXG4gIH0gZWxzZSBpZiAoc3RhcnQgPiBsZW4pIHtcbiAgICBzdGFydCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IDApIHtcbiAgICBlbmQgKz0gbGVuXG4gICAgaWYgKGVuZCA8IDApIGVuZCA9IDBcbiAgfSBlbHNlIGlmIChlbmQgPiBsZW4pIHtcbiAgICBlbmQgPSBsZW5cbiAgfVxuXG4gIGlmIChlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICB2YXIgbmV3QnVmXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIG5ld0J1ZiA9IEJ1ZmZlci5fYXVnbWVudCh0aGlzLnN1YmFycmF5KHN0YXJ0LCBlbmQpKVxuICB9IGVsc2Uge1xuICAgIHZhciBzbGljZUxlbiA9IGVuZCAtIHN0YXJ0XG4gICAgbmV3QnVmID0gbmV3IEJ1ZmZlcihzbGljZUxlbiwgdW5kZWZpbmVkKVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2xpY2VMZW47IGkrKykge1xuICAgICAgbmV3QnVmW2ldID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9XG5cbiAgaWYgKG5ld0J1Zi5sZW5ndGgpIG5ld0J1Zi5wYXJlbnQgPSB0aGlzLnBhcmVudCB8fCB0aGlzXG5cbiAgcmV0dXJuIG5ld0J1ZlxufVxuXG4vKlxuICogTmVlZCB0byBtYWtlIHN1cmUgdGhhdCBidWZmZXIgaXNuJ3QgdHJ5aW5nIHRvIHdyaXRlIG91dCBvZiBib3VuZHMuXG4gKi9cbmZ1bmN0aW9uIGNoZWNrT2Zmc2V0IChvZmZzZXQsIGV4dCwgbGVuZ3RoKSB7XG4gIGlmICgob2Zmc2V0ICUgMSkgIT09IDAgfHwgb2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ29mZnNldCBpcyBub3QgdWludCcpXG4gIGlmIChvZmZzZXQgKyBleHQgPiBsZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdUcnlpbmcgdG8gYWNjZXNzIGJleW9uZCBidWZmZXIgbGVuZ3RoJylcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludExFID0gZnVuY3Rpb24gcmVhZFVJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludEJFID0gZnVuY3Rpb24gcmVhZFVJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcbiAgfVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldCArIC0tYnl0ZUxlbmd0aF1cbiAgdmFyIG11bCA9IDFcbiAgd2hpbGUgKGJ5dGVMZW5ndGggPiAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50OCA9IGZ1bmN0aW9uIHJlYWRVSW50OCAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDEsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gdGhpc1tvZmZzZXRdXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkxFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MTZCRSA9IGZ1bmN0aW9uIHJlYWRVSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCA4KSB8IHRoaXNbb2Zmc2V0ICsgMV1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyTEUgPSBmdW5jdGlvbiByZWFkVUludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKCh0aGlzW29mZnNldF0pIHxcbiAgICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAgICh0aGlzW29mZnNldCArIDJdIDw8IDE2KSkgK1xuICAgICAgKHRoaXNbb2Zmc2V0ICsgM10gKiAweDEwMDAwMDApXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQzMkJFID0gZnVuY3Rpb24gcmVhZFVJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gKiAweDEwMDAwMDApICtcbiAgICAoKHRoaXNbb2Zmc2V0ICsgMV0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCA4KSB8XG4gICAgdGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50TEUgPSBmdW5jdGlvbiByZWFkSW50TEUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB3aGlsZSAoKytpIDwgYnl0ZUxlbmd0aCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIGldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50QkUgPSBmdW5jdGlvbiByZWFkSW50QkUgKG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCBieXRlTGVuZ3RoLCB0aGlzLmxlbmd0aClcblxuICB2YXIgaSA9IGJ5dGVMZW5ndGhcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1pXVxuICB3aGlsZSAoaSA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWldICogbXVsXG4gIH1cbiAgbXVsICo9IDB4ODBcblxuICBpZiAodmFsID49IG11bCkgdmFsIC09IE1hdGgucG93KDIsIDggKiBieXRlTGVuZ3RoKVxuXG4gIHJldHVybiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50OCA9IGZ1bmN0aW9uIHJlYWRJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIGlmICghKHRoaXNbb2Zmc2V0XSAmIDB4ODApKSByZXR1cm4gKHRoaXNbb2Zmc2V0XSlcbiAgcmV0dXJuICgoMHhmZiAtIHRoaXNbb2Zmc2V0XSArIDEpICogLTEpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2TEUgPSBmdW5jdGlvbiByZWFkSW50MTZMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXRdIHwgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQxNkJFID0gZnVuY3Rpb24gcmVhZEludDE2QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgMV0gfCAodGhpc1tvZmZzZXRdIDw8IDgpXG4gIHJldHVybiAodmFsICYgMHg4MDAwKSA/IHZhbCB8IDB4RkZGRjAwMDAgOiB2YWxcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0pIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSA8PCAyNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MzJCRSA9IGZ1bmN0aW9uIHJlYWRJbnQzMkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG5cbiAgcmV0dXJuICh0aGlzW29mZnNldF0gPDwgMjQpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAzXSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRMRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdExFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRmxvYXRCRSA9IGZ1bmN0aW9uIHJlYWRGbG9hdEJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgNCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCBmYWxzZSwgMjMsIDQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZERvdWJsZUxFID0gZnVuY3Rpb24gcmVhZERvdWJsZUxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgOCwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiBpZWVlNzU0LnJlYWQodGhpcywgb2Zmc2V0LCB0cnVlLCA1MiwgOClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlQkUgPSBmdW5jdGlvbiByZWFkRG91YmxlQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCA1MiwgOClcbn1cblxuZnVuY3Rpb24gY2hlY2tJbnQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihidWYpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdidWZmZXIgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3ZhbHVlIGlzIG91dCBvZiBib3VuZHMnKVxuICBpZiAob2Zmc2V0ICsgZXh0ID4gYnVmLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBtdWwgPSAxXG4gIHZhciBpID0gMFxuICB0aGlzW29mZnNldF0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50QkUgPSBmdW5jdGlvbiB3cml0ZVVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBieXRlTGVuZ3RoID0gYnl0ZUxlbmd0aCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpLCAwKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aCAtIDFcbiAgdmFyIG11bCA9IDFcbiAgdGhpc1tvZmZzZXQgKyBpXSA9IHZhbHVlICYgMHhGRlxuICB3aGlsZSAoLS1pID49IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB0aGlzW29mZnNldCArIGldID0gKHZhbHVlIC8gbXVsKSAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50OCA9IGZ1bmN0aW9uIHdyaXRlVUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHhmZiwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkgdmFsdWUgPSBNYXRoLmZsb29yKHZhbHVlKVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQxNiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmYgKyB2YWx1ZSArIDFcbiAgZm9yICh2YXIgaSA9IDAsIGogPSBNYXRoLm1pbihidWYubGVuZ3RoIC0gb2Zmc2V0LCAyKTsgaSA8IGo7IGkrKykge1xuICAgIGJ1ZltvZmZzZXQgKyBpXSA9ICh2YWx1ZSAmICgweGZmIDw8ICg4ICogKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkpKSkgPj4+XG4gICAgICAobGl0dGxlRW5kaWFuID8gaSA6IDEgLSBpKSAqIDhcbiAgfVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDE2TEUgPSBmdW5jdGlvbiB3cml0ZVVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4ZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgMlxufVxuXG5mdW5jdGlvbiBvYmplY3RXcml0ZVVJbnQzMiAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4pIHtcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgNCk7IGkgPCBqOyBpKyspIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgPj4+IChsaXR0bGVFbmRpYW4gPyBpIDogMyAtIGkpICogOCkgJiAweGZmXG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDMyQkUgPSBmdW5jdGlvbiB3cml0ZVVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4ZmZmZmZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50TEUgPSBmdW5jdGlvbiB3cml0ZUludExFICh2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbGltaXQgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCAtIDEpXG5cbiAgICBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBieXRlTGVuZ3RoLCBsaW1pdCAtIDEsIC1saW1pdClcbiAgfVxuXG4gIHZhciBpID0gMFxuICB2YXIgbXVsID0gMVxuICB2YXIgc3ViID0gdmFsdWUgPCAwID8gMSA6IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSB2YWx1ZSA8IDAgPyAxIDogMFxuICB0aGlzW29mZnNldCArIGldID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgtLWkgPj0gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHRoaXNbb2Zmc2V0ICsgaV0gPSAoKHZhbHVlIC8gbXVsKSA+PiAwKSAtIHN1YiAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBvZmZzZXQgKyBieXRlTGVuZ3RoXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQ4ID0gZnVuY3Rpb24gd3JpdGVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4N2YsIC0weDgwKVxuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB2YWx1ZSA9IE1hdGguZmxvb3IodmFsdWUpXG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZiArIHZhbHVlICsgMVxuICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICByZXR1cm4gb2Zmc2V0ICsgMVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MTZMRSA9IGZ1bmN0aW9uIHdyaXRlSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweDdmZmYsIC0weDgwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkJFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkxFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlSW50MzJCRSA9IGZ1bmN0aW9uIHdyaXRlSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweDdmZmZmZmZmLCAtMHg4MDAwMDAwMClcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmZmZmZmZmICsgdmFsdWUgKyAxXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlICYgMHhmZilcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSlcbiAgfVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5mdW5jdGlvbiBjaGVja0lFRUU3NTQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgZXh0LCBtYXgsIG1pbikge1xuICBpZiAodmFsdWUgPiBtYXggfHwgdmFsdWUgPCBtaW4pIHRocm93IG5ldyBSYW5nZUVycm9yKCd2YWx1ZSBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbmRleCBvdXQgb2YgcmFuZ2UnKVxuICBpZiAob2Zmc2V0IDwgMCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luZGV4IG91dCBvZiByYW5nZScpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRmxvYXQgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgNCwgMy40MDI4MjM0NjYzODUyODg2ZSszOCwgLTMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgMjMsIDQpXG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdExFID0gZnVuY3Rpb24gd3JpdGVGbG9hdExFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUZsb2F0QkUgPSBmdW5jdGlvbiB3cml0ZUZsb2F0QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZUZsb2F0KHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuZnVuY3Rpb24gd3JpdGVEb3VibGUgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgY2hlY2tJRUVFNzU0KGJ1ZiwgdmFsdWUsIG9mZnNldCwgOCwgMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgsIC0xLjc5NzY5MzEzNDg2MjMxNTdFKzMwOClcbiAgfVxuICBpZWVlNzU0LndyaXRlKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuLCA1MiwgOClcbiAgcmV0dXJuIG9mZnNldCArIDhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUxFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUsIG5vQXNzZXJ0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRG91YmxlQkUgPSBmdW5jdGlvbiB3cml0ZURvdWJsZUJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVEb3VibGUodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UsIG5vQXNzZXJ0KVxufVxuXG4vLyBjb3B5KHRhcmdldEJ1ZmZlciwgdGFyZ2V0U3RhcnQ9MCwgc291cmNlU3RhcnQ9MCwgc291cmNlRW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmNvcHkgPSBmdW5jdGlvbiBjb3B5ICh0YXJnZXQsIHRhcmdldFN0YXJ0LCBzdGFydCwgZW5kKSB7XG4gIGlmICghc3RhcnQpIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCAmJiBlbmQgIT09IDApIGVuZCA9IHRoaXMubGVuZ3RoXG4gIGlmICh0YXJnZXRTdGFydCA+PSB0YXJnZXQubGVuZ3RoKSB0YXJnZXRTdGFydCA9IHRhcmdldC5sZW5ndGhcbiAgaWYgKCF0YXJnZXRTdGFydCkgdGFyZ2V0U3RhcnQgPSAwXG4gIGlmIChlbmQgPiAwICYmIGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIC8vIENvcHkgMCBieXRlczsgd2UncmUgZG9uZVxuICBpZiAoZW5kID09PSBzdGFydCkgcmV0dXJuIDBcbiAgaWYgKHRhcmdldC5sZW5ndGggPT09IDAgfHwgdGhpcy5sZW5ndGggPT09IDApIHJldHVybiAwXG5cbiAgLy8gRmF0YWwgZXJyb3IgY29uZGl0aW9uc1xuICBpZiAodGFyZ2V0U3RhcnQgPCAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3RhcmdldFN0YXJ0IG91dCBvZiBib3VuZHMnKVxuICB9XG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdzb3VyY2VFbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgLy8gQXJlIHdlIG9vYj9cbiAgaWYgKGVuZCA+IHRoaXMubGVuZ3RoKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0IDwgZW5kIC0gc3RhcnQpIHtcbiAgICBlbmQgPSB0YXJnZXQubGVuZ3RoIC0gdGFyZ2V0U3RhcnQgKyBzdGFydFxuICB9XG5cbiAgdmFyIGxlbiA9IGVuZCAtIHN0YXJ0XG4gIHZhciBpXG5cbiAgaWYgKHRoaXMgPT09IHRhcmdldCAmJiBzdGFydCA8IHRhcmdldFN0YXJ0ICYmIHRhcmdldFN0YXJ0IDwgZW5kKSB7XG4gICAgLy8gZGVzY2VuZGluZyBjb3B5IGZyb20gZW5kXG4gICAgZm9yIChpID0gbGVuIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2UgaWYgKGxlbiA8IDEwMDAgfHwgIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gYXNjZW5kaW5nIGNvcHkgZnJvbSBzdGFydFxuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgdGFyZ2V0W2kgKyB0YXJnZXRTdGFydF0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGFyZ2V0Ll9zZXQodGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLCB0YXJnZXRTdGFydClcbiAgfVxuXG4gIHJldHVybiBsZW5cbn1cblxuLy8gZmlsbCh2YWx1ZSwgc3RhcnQ9MCwgZW5kPWJ1ZmZlci5sZW5ndGgpXG5CdWZmZXIucHJvdG90eXBlLmZpbGwgPSBmdW5jdGlvbiBmaWxsICh2YWx1ZSwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXZhbHVlKSB2YWx1ZSA9IDBcbiAgaWYgKCFzdGFydCkgc3RhcnQgPSAwXG4gIGlmICghZW5kKSBlbmQgPSB0aGlzLmxlbmd0aFxuXG4gIGlmIChlbmQgPCBzdGFydCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2VuZCA8IHN0YXJ0JylcblxuICAvLyBGaWxsIDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVyblxuICBpZiAodGhpcy5sZW5ndGggPT09IDApIHJldHVyblxuXG4gIGlmIChzdGFydCA8IDAgfHwgc3RhcnQgPj0gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdzdGFydCBvdXQgb2YgYm91bmRzJylcbiAgaWYgKGVuZCA8IDAgfHwgZW5kID4gdGhpcy5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdlbmQgb3V0IG9mIGJvdW5kcycpXG5cbiAgdmFyIGlcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICBmb3IgKGkgPSBzdGFydDsgaSA8IGVuZDsgaSsrKSB7XG4gICAgICB0aGlzW2ldID0gdmFsdWVcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gdXRmOFRvQnl0ZXModmFsdWUudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gc3RhcnQ7IGkgPCBlbmQ7IGkrKykge1xuICAgICAgdGhpc1tpXSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IGBBcnJheUJ1ZmZlcmAgd2l0aCB0aGUgKmNvcGllZCogbWVtb3J5IG9mIHRoZSBidWZmZXIgaW5zdGFuY2UuXG4gKiBBZGRlZCBpbiBOb2RlIDAuMTIuIE9ubHkgYXZhaWxhYmxlIGluIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCBBcnJheUJ1ZmZlci5cbiAqL1xuQnVmZmVyLnByb3RvdHlwZS50b0FycmF5QnVmZmVyID0gZnVuY3Rpb24gdG9BcnJheUJ1ZmZlciAoKSB7XG4gIGlmICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAgIHJldHVybiAobmV3IEJ1ZmZlcih0aGlzKSkuYnVmZmVyXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBidWYgPSBuZXcgVWludDhBcnJheSh0aGlzLmxlbmd0aClcbiAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBidWYubGVuZ3RoOyBpIDwgbGVuOyBpICs9IDEpIHtcbiAgICAgICAgYnVmW2ldID0gdGhpc1tpXVxuICAgICAgfVxuICAgICAgcmV0dXJuIGJ1Zi5idWZmZXJcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQnVmZmVyLnRvQXJyYXlCdWZmZXIgbm90IHN1cHBvcnRlZCBpbiB0aGlzIGJyb3dzZXInKVxuICB9XG59XG5cbi8vIEhFTFBFUiBGVU5DVElPTlNcbi8vID09PT09PT09PT09PT09PT1cblxudmFyIEJQID0gQnVmZmVyLnByb3RvdHlwZVxuXG4vKipcbiAqIEF1Z21lbnQgYSBVaW50OEFycmF5ICppbnN0YW5jZSogKG5vdCB0aGUgVWludDhBcnJheSBjbGFzcyEpIHdpdGggQnVmZmVyIG1ldGhvZHNcbiAqL1xuQnVmZmVyLl9hdWdtZW50ID0gZnVuY3Rpb24gX2F1Z21lbnQgKGFycikge1xuICBhcnIuY29uc3RydWN0b3IgPSBCdWZmZXJcbiAgYXJyLl9pc0J1ZmZlciA9IHRydWVcblxuICAvLyBzYXZlIHJlZmVyZW5jZSB0byBvcmlnaW5hbCBVaW50OEFycmF5IHNldCBtZXRob2QgYmVmb3JlIG92ZXJ3cml0aW5nXG4gIGFyci5fc2V0ID0gYXJyLnNldFxuXG4gIC8vIGRlcHJlY2F0ZWRcbiAgYXJyLmdldCA9IEJQLmdldFxuICBhcnIuc2V0ID0gQlAuc2V0XG5cbiAgYXJyLndyaXRlID0gQlAud3JpdGVcbiAgYXJyLnRvU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvTG9jYWxlU3RyaW5nID0gQlAudG9TdHJpbmdcbiAgYXJyLnRvSlNPTiA9IEJQLnRvSlNPTlxuICBhcnIuZXF1YWxzID0gQlAuZXF1YWxzXG4gIGFyci5jb21wYXJlID0gQlAuY29tcGFyZVxuICBhcnIuaW5kZXhPZiA9IEJQLmluZGV4T2ZcbiAgYXJyLmNvcHkgPSBCUC5jb3B5XG4gIGFyci5zbGljZSA9IEJQLnNsaWNlXG4gIGFyci5yZWFkVUludExFID0gQlAucmVhZFVJbnRMRVxuICBhcnIucmVhZFVJbnRCRSA9IEJQLnJlYWRVSW50QkVcbiAgYXJyLnJlYWRVSW50OCA9IEJQLnJlYWRVSW50OFxuICBhcnIucmVhZFVJbnQxNkxFID0gQlAucmVhZFVJbnQxNkxFXG4gIGFyci5yZWFkVUludDE2QkUgPSBCUC5yZWFkVUludDE2QkVcbiAgYXJyLnJlYWRVSW50MzJMRSA9IEJQLnJlYWRVSW50MzJMRVxuICBhcnIucmVhZFVJbnQzMkJFID0gQlAucmVhZFVJbnQzMkJFXG4gIGFyci5yZWFkSW50TEUgPSBCUC5yZWFkSW50TEVcbiAgYXJyLnJlYWRJbnRCRSA9IEJQLnJlYWRJbnRCRVxuICBhcnIucmVhZEludDggPSBCUC5yZWFkSW50OFxuICBhcnIucmVhZEludDE2TEUgPSBCUC5yZWFkSW50MTZMRVxuICBhcnIucmVhZEludDE2QkUgPSBCUC5yZWFkSW50MTZCRVxuICBhcnIucmVhZEludDMyTEUgPSBCUC5yZWFkSW50MzJMRVxuICBhcnIucmVhZEludDMyQkUgPSBCUC5yZWFkSW50MzJCRVxuICBhcnIucmVhZEZsb2F0TEUgPSBCUC5yZWFkRmxvYXRMRVxuICBhcnIucmVhZEZsb2F0QkUgPSBCUC5yZWFkRmxvYXRCRVxuICBhcnIucmVhZERvdWJsZUxFID0gQlAucmVhZERvdWJsZUxFXG4gIGFyci5yZWFkRG91YmxlQkUgPSBCUC5yZWFkRG91YmxlQkVcbiAgYXJyLndyaXRlVUludDggPSBCUC53cml0ZVVJbnQ4XG4gIGFyci53cml0ZVVJbnRMRSA9IEJQLndyaXRlVUludExFXG4gIGFyci53cml0ZVVJbnRCRSA9IEJQLndyaXRlVUludEJFXG4gIGFyci53cml0ZVVJbnQxNkxFID0gQlAud3JpdGVVSW50MTZMRVxuICBhcnIud3JpdGVVSW50MTZCRSA9IEJQLndyaXRlVUludDE2QkVcbiAgYXJyLndyaXRlVUludDMyTEUgPSBCUC53cml0ZVVJbnQzMkxFXG4gIGFyci53cml0ZVVJbnQzMkJFID0gQlAud3JpdGVVSW50MzJCRVxuICBhcnIud3JpdGVJbnRMRSA9IEJQLndyaXRlSW50TEVcbiAgYXJyLndyaXRlSW50QkUgPSBCUC53cml0ZUludEJFXG4gIGFyci53cml0ZUludDggPSBCUC53cml0ZUludDhcbiAgYXJyLndyaXRlSW50MTZMRSA9IEJQLndyaXRlSW50MTZMRVxuICBhcnIud3JpdGVJbnQxNkJFID0gQlAud3JpdGVJbnQxNkJFXG4gIGFyci53cml0ZUludDMyTEUgPSBCUC53cml0ZUludDMyTEVcbiAgYXJyLndyaXRlSW50MzJCRSA9IEJQLndyaXRlSW50MzJCRVxuICBhcnIud3JpdGVGbG9hdExFID0gQlAud3JpdGVGbG9hdExFXG4gIGFyci53cml0ZUZsb2F0QkUgPSBCUC53cml0ZUZsb2F0QkVcbiAgYXJyLndyaXRlRG91YmxlTEUgPSBCUC53cml0ZURvdWJsZUxFXG4gIGFyci53cml0ZURvdWJsZUJFID0gQlAud3JpdGVEb3VibGVCRVxuICBhcnIuZmlsbCA9IEJQLmZpbGxcbiAgYXJyLmluc3BlY3QgPSBCUC5pbnNwZWN0XG4gIGFyci50b0FycmF5QnVmZmVyID0gQlAudG9BcnJheUJ1ZmZlclxuXG4gIHJldHVybiBhcnJcbn1cblxudmFyIElOVkFMSURfQkFTRTY0X1JFID0gL1teK1xcLzAtOUEtWmEtei1fXS9nXG5cbmZ1bmN0aW9uIGJhc2U2NGNsZWFuIChzdHIpIHtcbiAgLy8gTm9kZSBzdHJpcHMgb3V0IGludmFsaWQgY2hhcmFjdGVycyBsaWtlIFxcbiBhbmQgXFx0IGZyb20gdGhlIHN0cmluZywgYmFzZTY0LWpzIGRvZXMgbm90XG4gIHN0ciA9IHN0cmluZ3RyaW0oc3RyKS5yZXBsYWNlKElOVkFMSURfQkFTRTY0X1JFLCAnJylcbiAgLy8gTm9kZSBjb252ZXJ0cyBzdHJpbmdzIHdpdGggbGVuZ3RoIDwgMiB0byAnJ1xuICBpZiAoc3RyLmxlbmd0aCA8IDIpIHJldHVybiAnJ1xuICAvLyBOb2RlIGFsbG93cyBmb3Igbm9uLXBhZGRlZCBiYXNlNjQgc3RyaW5ncyAobWlzc2luZyB0cmFpbGluZyA9PT0pLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgd2hpbGUgKHN0ci5sZW5ndGggJSA0ICE9PSAwKSB7XG4gICAgc3RyID0gc3RyICsgJz0nXG4gIH1cbiAgcmV0dXJuIHN0clxufVxuXG5mdW5jdGlvbiBzdHJpbmd0cmltIChzdHIpIHtcbiAgaWYgKHN0ci50cmltKSByZXR1cm4gc3RyLnRyaW0oKVxuICByZXR1cm4gc3RyLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKVxufVxuXG5mdW5jdGlvbiB0b0hleCAobikge1xuICBpZiAobiA8IDE2KSByZXR1cm4gJzAnICsgbi50b1N0cmluZygxNilcbiAgcmV0dXJuIG4udG9TdHJpbmcoMTYpXG59XG5cbmZ1bmN0aW9uIHV0ZjhUb0J5dGVzIChzdHJpbmcsIHVuaXRzKSB7XG4gIHVuaXRzID0gdW5pdHMgfHwgSW5maW5pdHlcbiAgdmFyIGNvZGVQb2ludFxuICB2YXIgbGVuZ3RoID0gc3RyaW5nLmxlbmd0aFxuICB2YXIgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcbiAgdmFyIGJ5dGVzID0gW11cblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgY29kZVBvaW50ID0gc3RyaW5nLmNoYXJDb2RlQXQoaSlcblxuICAgIC8vIGlzIHN1cnJvZ2F0ZSBjb21wb25lbnRcbiAgICBpZiAoY29kZVBvaW50ID4gMHhEN0ZGICYmIGNvZGVQb2ludCA8IDB4RTAwMCkge1xuICAgICAgLy8gbGFzdCBjaGFyIHdhcyBhIGxlYWRcbiAgICAgIGlmICghbGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgICAvLyBubyBsZWFkIHlldFxuICAgICAgICBpZiAoY29kZVBvaW50ID4gMHhEQkZGKSB7XG4gICAgICAgICAgLy8gdW5leHBlY3RlZCB0cmFpbFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH0gZWxzZSBpZiAoaSArIDEgPT09IGxlbmd0aCkge1xuICAgICAgICAgIC8vIHVucGFpcmVkIGxlYWRcbiAgICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gdmFsaWQgbGVhZFxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG5cbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gMiBsZWFkcyBpbiBhIHJvd1xuICAgICAgaWYgKGNvZGVQb2ludCA8IDB4REMwMCkge1xuICAgICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICAgICAgbGVhZFN1cnJvZ2F0ZSA9IGNvZGVQb2ludFxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyB2YWxpZCBzdXJyb2dhdGUgcGFpclxuICAgICAgY29kZVBvaW50ID0gKGxlYWRTdXJyb2dhdGUgLSAweEQ4MDAgPDwgMTAgfCBjb2RlUG9pbnQgLSAweERDMDApICsgMHgxMDAwMFxuICAgIH0gZWxzZSBpZiAobGVhZFN1cnJvZ2F0ZSkge1xuICAgICAgLy8gdmFsaWQgYm1wIGNoYXIsIGJ1dCBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgfVxuXG4gICAgbGVhZFN1cnJvZ2F0ZSA9IG51bGxcblxuICAgIC8vIGVuY29kZSB1dGY4XG4gICAgaWYgKGNvZGVQb2ludCA8IDB4ODApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMSkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChjb2RlUG9pbnQpXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPCAweDgwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAyKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2IHwgMHhDMCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gMykgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyB8IDB4RTAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4MTEwMDAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDQpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDEyIHwgMHhGMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4QyAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHg2ICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCAmIDB4M0YgfCAweDgwXG4gICAgICApXG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjb2RlIHBvaW50JylcbiAgICB9XG4gIH1cblxuICByZXR1cm4gYnl0ZXNcbn1cblxuZnVuY3Rpb24gYXNjaWlUb0J5dGVzIChzdHIpIHtcbiAgdmFyIGJ5dGVBcnJheSA9IFtdXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgLy8gTm9kZSdzIGNvZGUgc2VlbXMgdG8gYmUgZG9pbmcgdGhpcyBhbmQgbm90ICYgMHg3Ri4uXG4gICAgYnl0ZUFycmF5LnB1c2goc3RyLmNoYXJDb2RlQXQoaSkgJiAweEZGKVxuICB9XG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gdXRmMTZsZVRvQnl0ZXMgKHN0ciwgdW5pdHMpIHtcbiAgdmFyIGMsIGhpLCBsb1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcblxuICAgIGMgPSBzdHIuY2hhckNvZGVBdChpKVxuICAgIGhpID0gYyA+PiA4XG4gICAgbG8gPSBjICUgMjU2XG4gICAgYnl0ZUFycmF5LnB1c2gobG8pXG4gICAgYnl0ZUFycmF5LnB1c2goaGkpXG4gIH1cblxuICByZXR1cm4gYnl0ZUFycmF5XG59XG5cbmZ1bmN0aW9uIGJhc2U2NFRvQnl0ZXMgKHN0cikge1xuICByZXR1cm4gYmFzZTY0LnRvQnl0ZUFycmF5KGJhc2U2NGNsZWFuKHN0cikpXG59XG5cbmZ1bmN0aW9uIGJsaXRCdWZmZXIgKHNyYywgZHN0LCBvZmZzZXQsIGxlbmd0aCkge1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKChpICsgb2Zmc2V0ID49IGRzdC5sZW5ndGgpIHx8IChpID49IHNyYy5sZW5ndGgpKSBicmVha1xuICAgIGRzdFtpICsgb2Zmc2V0XSA9IHNyY1tpXVxuICB9XG4gIHJldHVybiBpXG59XG5cbn0pLmNhbGwodGhpcyx0eXBlb2YgZ2xvYmFsICE9PSBcInVuZGVmaW5lZFwiID8gZ2xvYmFsIDogdHlwZW9mIHNlbGYgIT09IFwidW5kZWZpbmVkXCIgPyBzZWxmIDogdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiA/IHdpbmRvdyA6IHt9KVxuLy8jIHNvdXJjZU1hcHBpbmdVUkw9ZGF0YTphcHBsaWNhdGlvbi9qc29uO2NoYXJzZXQ6dXRmLTg7YmFzZTY0LGV5SjJaWEp6YVc5dUlqb3pMQ0p6YjNWeVkyVnpJanBiSWk0dUx5NHVMeTR1THk0dUwyaHZiV1V2WVdSdGFXNHZZbkp2ZDNObGNtbG1lUzFqWkc0dmJtOWtaVjl0YjJSMWJHVnpMMkp5YjNkelpYSnBabmt2Ym05a1pWOXRiMlIxYkdWekwySjFabVpsY2k5cGJtUmxlQzVxY3lKZExDSnVZVzFsY3lJNlcxMHNJbTFoY0hCcGJtZHpJam9pTzBGQlFVRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRWlMQ0ptYVd4bElqb2laMlZ1WlhKaGRHVmtMbXB6SWl3aWMyOTFjbU5sVW05dmRDSTZJaUlzSW5OdmRYSmpaWE5EYjI1MFpXNTBJanBiSWk4cUlWeHVJQ29nVkdobElHSjFabVpsY2lCdGIyUjFiR1VnWm5KdmJTQnViMlJsTG1wekxDQm1iM0lnZEdobElHSnliM2R6WlhJdVhHNGdLbHh1SUNvZ1FHRjFkR2h2Y2lBZ0lFWmxjbTl6Y3lCQlltOTFhMmhoWkdscVpXZ2dQR1psY205emMwQm1aWEp2YzNNdWIzSm5QaUE4YUhSMGNEb3ZMMlpsY205emN5NXZjbWMrWEc0Z0tpQkFiR2xqWlc1elpTQWdUVWxVWEc0Z0tpOWNiaThxSUdWemJHbHVkQzFrYVhOaFlteGxJRzV2TFhCeWIzUnZJQ292WEc1Y2JpZDFjMlVnYzNSeWFXTjBKMXh1WEc1MllYSWdZbUZ6WlRZMElEMGdjbVZ4ZFdseVpTZ25ZbUZ6WlRZMExXcHpKeWxjYm5aaGNpQnBaV1ZsTnpVMElEMGdjbVZ4ZFdseVpTZ25hV1ZsWlRjMU5DY3BYRzUyWVhJZ2FYTkJjbkpoZVNBOUlISmxjWFZwY21Vb0oybHpZWEp5WVhrbktWeHVYRzVsZUhCdmNuUnpMa0oxWm1abGNpQTlJRUoxWm1abGNseHVaWGh3YjNKMGN5NVRiRzkzUW5WbVptVnlJRDBnVTJ4dmQwSjFabVpsY2x4dVpYaHdiM0owY3k1SlRsTlFSVU5VWDAxQldGOUNXVlJGVXlBOUlEVXdYRzVDZFdabVpYSXVjRzl2YkZOcGVtVWdQU0E0TVRreUlDOHZJRzV2ZENCMWMyVmtJR0o1SUhSb2FYTWdhVzF3YkdWdFpXNTBZWFJwYjI1Y2JseHVkbUZ5SUhKdmIzUlFZWEpsYm5RZ1BTQjdmVnh1WEc0dktpcGNiaUFxSUVsbUlHQkNkV1ptWlhJdVZGbFFSVVJmUVZKU1FWbGZVMVZRVUU5U1ZHQTZYRzRnS2lBZ0lEMDlQU0IwY25WbElDQWdJRlZ6WlNCVmFXNTBPRUZ5Y21GNUlHbHRjR3hsYldWdWRHRjBhVzl1SUNobVlYTjBaWE4wS1Z4dUlDb2dJQ0E5UFQwZ1ptRnNjMlVnSUNCVmMyVWdUMkpxWldOMElHbHRjR3hsYldWdWRHRjBhVzl1SUNodGIzTjBJR052YlhCaGRHbGliR1VzSUdWMlpXNGdTVVUyS1Z4dUlDcGNiaUFxSUVKeWIzZHpaWEp6SUhSb1lYUWdjM1Z3Y0c5eWRDQjBlWEJsWkNCaGNuSmhlWE1nWVhKbElFbEZJREV3S3l3Z1JtbHlaV1p2ZUNBMEt5d2dRMmh5YjIxbElEY3JMQ0JUWVdaaGNta2dOUzR4S3l4Y2JpQXFJRTl3WlhKaElERXhMallyTENCcFQxTWdOQzR5S3k1Y2JpQXFYRzRnS2lCRWRXVWdkRzhnZG1GeWFXOTFjeUJpY205M2MyVnlJR0oxWjNNc0lITnZiV1YwYVcxbGN5QjBhR1VnVDJKcVpXTjBJR2x0Y0d4bGJXVnVkR0YwYVc5dUlIZHBiR3dnWW1VZ2RYTmxaQ0JsZG1WdVhHNGdLaUIzYUdWdUlIUm9aU0JpY205M2MyVnlJSE4xY0hCdmNuUnpJSFI1Y0dWa0lHRnljbUY1Y3k1Y2JpQXFYRzRnS2lCT2IzUmxPbHh1SUNwY2JpQXFJQ0FnTFNCR2FYSmxabTk0SURRdE1qa2diR0ZqYTNNZ2MzVndjRzl5ZENCbWIzSWdZV1JrYVc1bklHNWxkeUJ3Y205d1pYSjBhV1Z6SUhSdklHQlZhVzUwT0VGeWNtRjVZQ0JwYm5OMFlXNWpaWE1zWEc0Z0tpQWdJQ0FnVTJWbE9pQm9kSFJ3Y3pvdkwySjFaM3BwYkd4aExtMXZlbWxzYkdFdWIzSm5MM05vYjNkZlluVm5MbU5uYVQ5cFpEMDJPVFUwTXpndVhHNGdLbHh1SUNvZ0lDQXRJRk5oWm1GeWFTQTFMVGNnYkdGamEzTWdjM1Z3Y0c5eWRDQm1iM0lnWTJoaGJtZHBibWNnZEdobElHQlBZbXBsWTNRdWNISnZkRzkwZVhCbExtTnZibk4wY25WamRHOXlZQ0J3Y205d1pYSjBlVnh1SUNvZ0lDQWdJRzl1SUc5aWFtVmpkSE11WEc0Z0tseHVJQ29nSUNBdElFTm9jbTl0WlNBNUxURXdJR2x6SUcxcGMzTnBibWNnZEdobElHQlVlWEJsWkVGeWNtRjVMbkJ5YjNSdmRIbHdaUzV6ZFdKaGNuSmhlV0FnWm5WdVkzUnBiMjR1WEc0Z0tseHVJQ29nSUNBdElFbEZNVEFnYUdGeklHRWdZbkp2YTJWdUlHQlVlWEJsWkVGeWNtRjVMbkJ5YjNSdmRIbHdaUzV6ZFdKaGNuSmhlV0FnWm5WdVkzUnBiMjRnZDJocFkyZ2djbVYwZFhKdWN5QmhjbkpoZVhNZ2IyWmNiaUFxSUNBZ0lDQnBibU52Y25KbFkzUWdiR1Z1WjNSb0lHbHVJSE52YldVZ2MybDBkV0YwYVc5dWN5NWNibHh1SUNvZ1YyVWdaR1YwWldOMElIUm9aWE5sSUdKMVoyZDVJR0p5YjNkelpYSnpJR0Z1WkNCelpYUWdZRUoxWm1abGNpNVVXVkJGUkY5QlVsSkJXVjlUVlZCUVQxSlVZQ0IwYnlCZ1ptRnNjMlZnSUhOdklIUm9aWGxjYmlBcUlHZGxkQ0IwYUdVZ1QySnFaV04wSUdsdGNHeGxiV1Z1ZEdGMGFXOXVMQ0IzYUdsamFDQnBjeUJ6Ykc5M1pYSWdZblYwSUdKbGFHRjJaWE1nWTI5eWNtVmpkR3g1TGx4dUlDb3ZYRzVDZFdabVpYSXVWRmxRUlVSZlFWSlNRVmxmVTFWUVVFOVNWQ0E5SUdkc2IySmhiQzVVV1ZCRlJGOUJVbEpCV1Y5VFZWQlFUMUpVSUNFOVBTQjFibVJsWm1sdVpXUmNiaUFnUHlCbmJHOWlZV3d1VkZsUVJVUmZRVkpTUVZsZlUxVlFVRTlTVkZ4dUlDQTZJSFI1Y0dWa1FYSnlZWGxUZFhCd2IzSjBLQ2xjYmx4dVpuVnVZM1JwYjI0Z2RIbHdaV1JCY25KaGVWTjFjSEJ2Y25RZ0tDa2dlMXh1SUNCbWRXNWpkR2x2YmlCQ1lYSWdLQ2tnZTMxY2JpQWdkSEo1SUh0Y2JpQWdJQ0IyWVhJZ1lYSnlJRDBnYm1WM0lGVnBiblE0UVhKeVlYa29NU2xjYmlBZ0lDQmhjbkl1Wm05dklEMGdablZ1WTNScGIyNGdLQ2tnZXlCeVpYUjFjbTRnTkRJZ2ZWeHVJQ0FnSUdGeWNpNWpiMjV6ZEhKMVkzUnZjaUE5SUVKaGNseHVJQ0FnSUhKbGRIVnliaUJoY25JdVptOXZLQ2tnUFQwOUlEUXlJQ1ltSUM4dklIUjVjR1ZrSUdGeWNtRjVJR2x1YzNSaGJtTmxjeUJqWVc0Z1ltVWdZWFZuYldWdWRHVmtYRzRnSUNBZ0lDQWdJR0Z5Y2k1amIyNXpkSEoxWTNSdmNpQTlQVDBnUW1GeUlDWW1JQzh2SUdOdmJuTjBjblZqZEc5eUlHTmhiaUJpWlNCelpYUmNiaUFnSUNBZ0lDQWdkSGx3Wlc5bUlHRnljaTV6ZFdKaGNuSmhlU0E5UFQwZ0oyWjFibU4wYVc5dUp5QW1KaUF2THlCamFISnZiV1VnT1MweE1DQnNZV05ySUdCemRXSmhjbkpoZVdCY2JpQWdJQ0FnSUNBZ1lYSnlMbk4xWW1GeWNtRjVLREVzSURFcExtSjVkR1ZNWlc1bmRHZ2dQVDA5SURBZ0x5OGdhV1V4TUNCb1lYTWdZbkp2YTJWdUlHQnpkV0poY25KaGVXQmNiaUFnZlNCallYUmphQ0FvWlNrZ2UxeHVJQ0FnSUhKbGRIVnliaUJtWVd4elpWeHVJQ0I5WEc1OVhHNWNibVoxYm1OMGFXOXVJR3ROWVhoTVpXNW5kR2dnS0NrZ2UxeHVJQ0J5WlhSMWNtNGdRblZtWm1WeUxsUlpVRVZFWDBGU1VrRlpYMU5WVUZCUFVsUmNiaUFnSUNBL0lEQjROMlptWm1abVptWmNiaUFnSUNBNklEQjRNMlptWm1abVptWmNibjFjYmx4dUx5b3FYRzRnS2lCRGJHRnpjem9nUW5WbVptVnlYRzRnS2lBOVBUMDlQVDA5UFQwOVBUMDlYRzRnS2x4dUlDb2dWR2hsSUVKMVptWmxjaUJqYjI1emRISjFZM1J2Y2lCeVpYUjFjbTV6SUdsdWMzUmhibU5sY3lCdlppQmdWV2x1ZERoQmNuSmhlV0FnZEdoaGRDQmhjbVVnWVhWbmJXVnVkR1ZrWEc0Z0tpQjNhWFJvSUdaMWJtTjBhVzl1SUhCeWIzQmxjblJwWlhNZ1ptOXlJR0ZzYkNCMGFHVWdibTlrWlNCZ1FuVm1abVZ5WUNCQlVFa2dablZ1WTNScGIyNXpMaUJYWlNCMWMyVmNiaUFxSUdCVmFXNTBPRUZ5Y21GNVlDQnpieUIwYUdGMElITnhkV0Z5WlNCaWNtRmphMlYwSUc1dmRHRjBhVzl1SUhkdmNtdHpJR0Z6SUdWNGNHVmpkR1ZrSUMwdElHbDBJSEpsZEhWeWJuTmNiaUFxSUdFZ2MybHVaMnhsSUc5amRHVjBMbHh1SUNwY2JpQXFJRUo1SUdGMVoyMWxiblJwYm1jZ2RHaGxJR2x1YzNSaGJtTmxjeXdnZDJVZ1kyRnVJR0YyYjJsa0lHMXZaR2xtZVdsdVp5QjBhR1VnWUZWcGJuUTRRWEp5WVhsZ1hHNGdLaUJ3Y205MGIzUjVjR1V1WEc0Z0tpOWNibVoxYm1OMGFXOXVJRUoxWm1abGNpQW9ZWEpuS1NCN1hHNGdJR2xtSUNnaEtIUm9hWE1nYVc1emRHRnVZMlZ2WmlCQ2RXWm1aWElwS1NCN1hHNGdJQ0FnTHk4Z1FYWnZhV1FnWjI5cGJtY2dkR2h5YjNWbmFDQmhiaUJCY21kMWJXVnVkSE5CWkdGd2RHOXlWSEpoYlhCdmJHbHVaU0JwYmlCMGFHVWdZMjl0Ylc5dUlHTmhjMlV1WEc0Z0lDQWdhV1lnS0dGeVozVnRaVzUwY3k1c1pXNW5kR2dnUGlBeEtTQnlaWFIxY200Z2JtVjNJRUoxWm1abGNpaGhjbWNzSUdGeVozVnRaVzUwYzFzeFhTbGNiaUFnSUNCeVpYUjFjbTRnYm1WM0lFSjFabVpsY2loaGNtY3BYRzRnSUgxY2JseHVJQ0JwWmlBb0lVSjFabVpsY2k1VVdWQkZSRjlCVWxKQldWOVRWVkJRVDFKVUtTQjdYRzRnSUNBZ2RHaHBjeTVzWlc1bmRHZ2dQU0F3WEc0Z0lDQWdkR2hwY3k1d1lYSmxiblFnUFNCMWJtUmxabWx1WldSY2JpQWdmVnh1WEc0Z0lDOHZJRU52YlcxdmJpQmpZWE5sTGx4dUlDQnBaaUFvZEhsd1pXOW1JR0Z5WnlBOVBUMGdKMjUxYldKbGNpY3BJSHRjYmlBZ0lDQnlaWFIxY200Z1puSnZiVTUxYldKbGNpaDBhR2x6TENCaGNtY3BYRzRnSUgxY2JseHVJQ0F2THlCVGJHbG5hSFJzZVNCc1pYTnpJR052YlcxdmJpQmpZWE5sTGx4dUlDQnBaaUFvZEhsd1pXOW1JR0Z5WnlBOVBUMGdKM04wY21sdVp5Y3BJSHRjYmlBZ0lDQnlaWFIxY200Z1puSnZiVk4wY21sdVp5aDBhR2x6TENCaGNtY3NJR0Z5WjNWdFpXNTBjeTVzWlc1bmRHZ2dQaUF4SUQ4Z1lYSm5kVzFsYm5Seld6RmRJRG9nSjNWMFpqZ25LVnh1SUNCOVhHNWNiaUFnTHk4Z1ZXNTFjM1ZoYkM1Y2JpQWdjbVYwZFhKdUlHWnliMjFQWW1wbFkzUW9kR2hwY3l3Z1lYSm5LVnh1ZlZ4dVhHNW1kVzVqZEdsdmJpQm1jbTl0VG5WdFltVnlJQ2gwYUdGMExDQnNaVzVuZEdncElIdGNiaUFnZEdoaGRDQTlJR0ZzYkc5allYUmxLSFJvWVhRc0lHeGxibWQwYUNBOElEQWdQeUF3SURvZ1kyaGxZMnRsWkNoc1pXNW5kR2dwSUh3Z01DbGNiaUFnYVdZZ0tDRkNkV1ptWlhJdVZGbFFSVVJmUVZKU1FWbGZVMVZRVUU5U1ZDa2dlMXh1SUNBZ0lHWnZjaUFvZG1GeUlHa2dQU0F3T3lCcElEd2diR1Z1WjNSb095QnBLeXNwSUh0Y2JpQWdJQ0FnSUhSb1lYUmJhVjBnUFNBd1hHNGdJQ0FnZlZ4dUlDQjlYRzRnSUhKbGRIVnliaUIwYUdGMFhHNTlYRzVjYm1aMWJtTjBhVzl1SUdaeWIyMVRkSEpwYm1jZ0tIUm9ZWFFzSUhOMGNtbHVaeXdnWlc1amIyUnBibWNwSUh0Y2JpQWdhV1lnS0hSNWNHVnZaaUJsYm1OdlpHbHVaeUFoUFQwZ0ozTjBjbWx1WnljZ2ZId2daVzVqYjJScGJtY2dQVDA5SUNjbktTQmxibU52WkdsdVp5QTlJQ2QxZEdZNEoxeHVYRzRnSUM4dklFRnpjM1Z0Y0hScGIyNDZJR0o1ZEdWTVpXNW5kR2dvS1NCeVpYUjFjbTRnZG1Gc2RXVWdhWE1nWVd4M1lYbHpJRHdnYTAxaGVFeGxibWQwYUM1Y2JpQWdkbUZ5SUd4bGJtZDBhQ0E5SUdKNWRHVk1aVzVuZEdnb2MzUnlhVzVuTENCbGJtTnZaR2x1WnlrZ2ZDQXdYRzRnSUhSb1lYUWdQU0JoYkd4dlkyRjBaU2gwYUdGMExDQnNaVzVuZEdncFhHNWNiaUFnZEdoaGRDNTNjbWwwWlNoemRISnBibWNzSUdWdVkyOWthVzVuS1Z4dUlDQnlaWFIxY200Z2RHaGhkRnh1ZlZ4dVhHNW1kVzVqZEdsdmJpQm1jbTl0VDJKcVpXTjBJQ2gwYUdGMExDQnZZbXBsWTNRcElIdGNiaUFnYVdZZ0tFSjFabVpsY2k1cGMwSjFabVpsY2lodlltcGxZM1FwS1NCeVpYUjFjbTRnWm5KdmJVSjFabVpsY2loMGFHRjBMQ0J2WW1wbFkzUXBYRzVjYmlBZ2FXWWdLR2x6UVhKeVlYa29iMkpxWldOMEtTa2djbVYwZFhKdUlHWnliMjFCY25KaGVTaDBhR0YwTENCdlltcGxZM1FwWEc1Y2JpQWdhV1lnS0c5aWFtVmpkQ0E5UFNCdWRXeHNLU0I3WEc0Z0lDQWdkR2h5YjNjZ2JtVjNJRlI1Y0dWRmNuSnZjaWduYlhWemRDQnpkR0Z5ZENCM2FYUm9JRzUxYldKbGNpd2dZblZtWm1WeUxDQmhjbkpoZVNCdmNpQnpkSEpwYm1jbktWeHVJQ0I5WEc1Y2JpQWdhV1lnS0hSNWNHVnZaaUJCY25KaGVVSjFabVpsY2lBaFBUMGdKM1Z1WkdWbWFXNWxaQ2NwSUh0Y2JpQWdJQ0JwWmlBb2IySnFaV04wTG1KMVptWmxjaUJwYm5OMFlXNWpaVzltSUVGeWNtRjVRblZtWm1WeUtTQjdYRzRnSUNBZ0lDQnlaWFIxY200Z1puSnZiVlI1Y0dWa1FYSnlZWGtvZEdoaGRDd2diMkpxWldOMEtWeHVJQ0FnSUgxY2JpQWdJQ0JwWmlBb2IySnFaV04wSUdsdWMzUmhibU5sYjJZZ1FYSnlZWGxDZFdabVpYSXBJSHRjYmlBZ0lDQWdJSEpsZEhWeWJpQm1jbTl0UVhKeVlYbENkV1ptWlhJb2RHaGhkQ3dnYjJKcVpXTjBLVnh1SUNBZ0lIMWNiaUFnZlZ4dVhHNGdJR2xtSUNodlltcGxZM1F1YkdWdVozUm9LU0J5WlhSMWNtNGdabkp2YlVGeWNtRjVUR2xyWlNoMGFHRjBMQ0J2WW1wbFkzUXBYRzVjYmlBZ2NtVjBkWEp1SUdaeWIyMUtjMjl1VDJKcVpXTjBLSFJvWVhRc0lHOWlhbVZqZENsY2JuMWNibHh1Wm5WdVkzUnBiMjRnWm5KdmJVSjFabVpsY2lBb2RHaGhkQ3dnWW5WbVptVnlLU0I3WEc0Z0lIWmhjaUJzWlc1bmRHZ2dQU0JqYUdWamEyVmtLR0oxWm1abGNpNXNaVzVuZEdncElId2dNRnh1SUNCMGFHRjBJRDBnWVd4c2IyTmhkR1VvZEdoaGRDd2diR1Z1WjNSb0tWeHVJQ0JpZFdabVpYSXVZMjl3ZVNoMGFHRjBMQ0F3TENBd0xDQnNaVzVuZEdncFhHNGdJSEpsZEhWeWJpQjBhR0YwWEc1OVhHNWNibVoxYm1OMGFXOXVJR1p5YjIxQmNuSmhlU0FvZEdoaGRDd2dZWEp5WVhrcElIdGNiaUFnZG1GeUlHeGxibWQwYUNBOUlHTm9aV05yWldRb1lYSnlZWGt1YkdWdVozUm9LU0I4SURCY2JpQWdkR2hoZENBOUlHRnNiRzlqWVhSbEtIUm9ZWFFzSUd4bGJtZDBhQ2xjYmlBZ1ptOXlJQ2gyWVhJZ2FTQTlJREE3SUdrZ1BDQnNaVzVuZEdnN0lHa2dLejBnTVNrZ2UxeHVJQ0FnSUhSb1lYUmJhVjBnUFNCaGNuSmhlVnRwWFNBbUlESTFOVnh1SUNCOVhHNGdJSEpsZEhWeWJpQjBhR0YwWEc1OVhHNWNiaTh2SUVSMWNHeHBZMkYwWlNCdlppQm1jbTl0UVhKeVlYa29LU0IwYnlCclpXVndJR1p5YjIxQmNuSmhlU2dwSUcxdmJtOXRiM0p3YUdsakxseHVablZ1WTNScGIyNGdabkp2YlZSNWNHVmtRWEp5WVhrZ0tIUm9ZWFFzSUdGeWNtRjVLU0I3WEc0Z0lIWmhjaUJzWlc1bmRHZ2dQU0JqYUdWamEyVmtLR0Z5Y21GNUxteGxibWQwYUNrZ2ZDQXdYRzRnSUhSb1lYUWdQU0JoYkd4dlkyRjBaU2gwYUdGMExDQnNaVzVuZEdncFhHNGdJQzh2SUZSeWRXNWpZWFJwYm1jZ2RHaGxJR1ZzWlcxbGJuUnpJR2x6SUhCeWIySmhZbXg1SUc1dmRDQjNhR0YwSUhCbGIzQnNaU0JsZUhCbFkzUWdabkp2YlNCMGVYQmxaRnh1SUNBdkx5QmhjbkpoZVhNZ2QybDBhQ0JDV1ZSRlUxOVFSVkpmUlV4RlRVVk9WQ0ErSURFZ1luVjBJR2wwSjNNZ1kyOXRjR0YwYVdKc1pTQjNhWFJvSUhSb1pTQmlaV2hoZG1sdmNseHVJQ0F2THlCdlppQjBhR1VnYjJ4a0lFSjFabVpsY2lCamIyNXpkSEoxWTNSdmNpNWNiaUFnWm05eUlDaDJZWElnYVNBOUlEQTdJR2tnUENCc1pXNW5kR2c3SUdrZ0t6MGdNU2tnZTF4dUlDQWdJSFJvWVhSYmFWMGdQU0JoY25KaGVWdHBYU0FtSURJMU5WeHVJQ0I5WEc0Z0lISmxkSFZ5YmlCMGFHRjBYRzU5WEc1Y2JtWjFibU4wYVc5dUlHWnliMjFCY25KaGVVSjFabVpsY2lBb2RHaGhkQ3dnWVhKeVlYa3BJSHRjYmlBZ2FXWWdLRUoxWm1abGNpNVVXVkJGUkY5QlVsSkJXVjlUVlZCUVQxSlVLU0I3WEc0Z0lDQWdMeThnVW1WMGRYSnVJR0Z1SUdGMVoyMWxiblJsWkNCZ1ZXbHVkRGhCY25KaGVXQWdhVzV6ZEdGdVkyVXNJR1p2Y2lCaVpYTjBJSEJsY21admNtMWhibU5sWEc0Z0lDQWdZWEp5WVhrdVlubDBaVXhsYm1kMGFGeHVJQ0FnSUhSb1lYUWdQU0JDZFdabVpYSXVYMkYxWjIxbGJuUW9ibVYzSUZWcGJuUTRRWEp5WVhrb1lYSnlZWGtwS1Z4dUlDQjlJR1ZzYzJVZ2UxeHVJQ0FnSUM4dklFWmhiR3hpWVdOck9pQlNaWFIxY200Z1lXNGdiMkpxWldOMElHbHVjM1JoYm1ObElHOW1JSFJvWlNCQ2RXWm1aWElnWTJ4aGMzTmNiaUFnSUNCMGFHRjBJRDBnWm5KdmJWUjVjR1ZrUVhKeVlYa29kR2hoZEN3Z2JtVjNJRlZwYm5RNFFYSnlZWGtvWVhKeVlYa3BLVnh1SUNCOVhHNGdJSEpsZEhWeWJpQjBhR0YwWEc1OVhHNWNibVoxYm1OMGFXOXVJR1p5YjIxQmNuSmhlVXhwYTJVZ0tIUm9ZWFFzSUdGeWNtRjVLU0I3WEc0Z0lIWmhjaUJzWlc1bmRHZ2dQU0JqYUdWamEyVmtLR0Z5Y21GNUxteGxibWQwYUNrZ2ZDQXdYRzRnSUhSb1lYUWdQU0JoYkd4dlkyRjBaU2gwYUdGMExDQnNaVzVuZEdncFhHNGdJR1p2Y2lBb2RtRnlJR2tnUFNBd095QnBJRHdnYkdWdVozUm9PeUJwSUNzOUlERXBJSHRjYmlBZ0lDQjBhR0YwVzJsZElEMGdZWEp5WVhsYmFWMGdKaUF5TlRWY2JpQWdmVnh1SUNCeVpYUjFjbTRnZEdoaGRGeHVmVnh1WEc0dkx5QkVaWE5sY21saGJHbDZaU0I3SUhSNWNHVTZJQ2RDZFdabVpYSW5MQ0JrWVhSaE9pQmJNU3d5TERNc0xpNHVYU0I5SUdsdWRHOGdZU0JDZFdabVpYSWdiMkpxWldOMExseHVMeThnVW1WMGRYSnVjeUJoSUhwbGNtOHRiR1Z1WjNSb0lHSjFabVpsY2lCbWIzSWdhVzV3ZFhSeklIUm9ZWFFnWkc5dUozUWdZMjl1Wm05eWJTQjBieUIwYUdVZ2MzQmxZeTVjYm1aMWJtTjBhVzl1SUdaeWIyMUtjMjl1VDJKcVpXTjBJQ2gwYUdGMExDQnZZbXBsWTNRcElIdGNiaUFnZG1GeUlHRnljbUY1WEc0Z0lIWmhjaUJzWlc1bmRHZ2dQU0F3WEc1Y2JpQWdhV1lnS0c5aWFtVmpkQzUwZVhCbElEMDlQU0FuUW5WbVptVnlKeUFtSmlCcGMwRnljbUY1S0c5aWFtVmpkQzVrWVhSaEtTa2dlMXh1SUNBZ0lHRnljbUY1SUQwZ2IySnFaV04wTG1SaGRHRmNiaUFnSUNCc1pXNW5kR2dnUFNCamFHVmphMlZrS0dGeWNtRjVMbXhsYm1kMGFDa2dmQ0F3WEc0Z0lIMWNiaUFnZEdoaGRDQTlJR0ZzYkc5allYUmxLSFJvWVhRc0lHeGxibWQwYUNsY2JseHVJQ0JtYjNJZ0tIWmhjaUJwSUQwZ01Ec2dhU0E4SUd4bGJtZDBhRHNnYVNBclBTQXhLU0I3WEc0Z0lDQWdkR2hoZEZ0cFhTQTlJR0Z5Y21GNVcybGRJQ1lnTWpVMVhHNGdJSDFjYmlBZ2NtVjBkWEp1SUhSb1lYUmNibjFjYmx4dWFXWWdLRUoxWm1abGNpNVVXVkJGUkY5QlVsSkJXVjlUVlZCUVQxSlVLU0I3WEc0Z0lFSjFabVpsY2k1d2NtOTBiM1I1Y0dVdVgxOXdjbTkwYjE5ZklEMGdWV2x1ZERoQmNuSmhlUzV3Y205MGIzUjVjR1ZjYmlBZ1FuVm1abVZ5TGw5ZmNISnZkRzlmWHlBOUlGVnBiblE0UVhKeVlYbGNibjBnWld4elpTQjdYRzRnSUM4dklIQnlaUzF6WlhRZ1ptOXlJSFpoYkhWbGN5QjBhR0YwSUcxaGVTQmxlR2x6ZENCcGJpQjBhR1VnWm5WMGRYSmxYRzRnSUVKMVptWmxjaTV3Y205MGIzUjVjR1V1YkdWdVozUm9JRDBnZFc1a1pXWnBibVZrWEc0Z0lFSjFabVpsY2k1d2NtOTBiM1I1Y0dVdWNHRnlaVzUwSUQwZ2RXNWtaV1pwYm1Wa1hHNTlYRzVjYm1aMWJtTjBhVzl1SUdGc2JHOWpZWFJsSUNoMGFHRjBMQ0JzWlc1bmRHZ3BJSHRjYmlBZ2FXWWdLRUoxWm1abGNpNVVXVkJGUkY5QlVsSkJXVjlUVlZCUVQxSlVLU0I3WEc0Z0lDQWdMeThnVW1WMGRYSnVJR0Z1SUdGMVoyMWxiblJsWkNCZ1ZXbHVkRGhCY25KaGVXQWdhVzV6ZEdGdVkyVXNJR1p2Y2lCaVpYTjBJSEJsY21admNtMWhibU5sWEc0Z0lDQWdkR2hoZENBOUlFSjFabVpsY2k1ZllYVm5iV1Z1ZENodVpYY2dWV2x1ZERoQmNuSmhlU2hzWlc1bmRHZ3BLVnh1SUNBZ0lIUm9ZWFF1WDE5d2NtOTBiMTlmSUQwZ1FuVm1abVZ5TG5CeWIzUnZkSGx3WlZ4dUlDQjlJR1ZzYzJVZ2UxeHVJQ0FnSUM4dklFWmhiR3hpWVdOck9pQlNaWFIxY200Z1lXNGdiMkpxWldOMElHbHVjM1JoYm1ObElHOW1JSFJvWlNCQ2RXWm1aWElnWTJ4aGMzTmNiaUFnSUNCMGFHRjBMbXhsYm1kMGFDQTlJR3hsYm1kMGFGeHVJQ0FnSUhSb1lYUXVYMmx6UW5WbVptVnlJRDBnZEhKMVpWeHVJQ0I5WEc1Y2JpQWdkbUZ5SUdaeWIyMVFiMjlzSUQwZ2JHVnVaM1JvSUNFOVBTQXdJQ1ltSUd4bGJtZDBhQ0E4UFNCQ2RXWm1aWEl1Y0c5dmJGTnBlbVVnUGo0K0lERmNiaUFnYVdZZ0tHWnliMjFRYjI5c0tTQjBhR0YwTG5CaGNtVnVkQ0E5SUhKdmIzUlFZWEpsYm5SY2JseHVJQ0J5WlhSMWNtNGdkR2hoZEZ4dWZWeHVYRzVtZFc1amRHbHZiaUJqYUdWamEyVmtJQ2hzWlc1bmRHZ3BJSHRjYmlBZ0x5OGdUbTkwWlRvZ1kyRnVibTkwSUhWelpTQmdiR1Z1WjNSb0lEd2dhMDFoZUV4bGJtZDBhR0FnYUdWeVpTQmlaV05oZFhObElIUm9ZWFFnWm1GcGJITWdkMmhsYmx4dUlDQXZMeUJzWlc1bmRHZ2dhWE1nVG1GT0lDaDNhR2xqYUNCcGN5QnZkR2hsY25kcGMyVWdZMjlsY21ObFpDQjBieUI2WlhKdkxpbGNiaUFnYVdZZ0tHeGxibWQwYUNBK1BTQnJUV0Y0VEdWdVozUm9LQ2twSUh0Y2JpQWdJQ0IwYUhKdmR5QnVaWGNnVW1GdVoyVkZjbkp2Y2lnblFYUjBaVzF3ZENCMGJ5QmhiR3h2WTJGMFpTQkNkV1ptWlhJZ2JHRnlaMlZ5SUhSb1lXNGdiV0Y0YVcxMWJTQW5JQ3RjYmlBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FnSUNBZ0lDQWdJQ0FuYzJsNlpUb2dNSGduSUNzZ2EwMWhlRXhsYm1kMGFDZ3BMblJ2VTNSeWFXNW5LREUyS1NBcklDY2dZbmwwWlhNbktWeHVJQ0I5WEc0Z0lISmxkSFZ5YmlCc1pXNW5kR2dnZkNBd1hHNTlYRzVjYm1aMWJtTjBhVzl1SUZOc2IzZENkV1ptWlhJZ0tITjFZbXBsWTNRc0lHVnVZMjlrYVc1bktTQjdYRzRnSUdsbUlDZ2hLSFJvYVhNZ2FXNXpkR0Z1WTJWdlppQlRiRzkzUW5WbVptVnlLU2tnY21WMGRYSnVJRzVsZHlCVGJHOTNRblZtWm1WeUtITjFZbXBsWTNRc0lHVnVZMjlrYVc1bktWeHVYRzRnSUhaaGNpQmlkV1lnUFNCdVpYY2dRblZtWm1WeUtITjFZbXBsWTNRc0lHVnVZMjlrYVc1bktWeHVJQ0JrWld4bGRHVWdZblZtTG5CaGNtVnVkRnh1SUNCeVpYUjFjbTRnWW5WbVhHNTlYRzVjYmtKMVptWmxjaTVwYzBKMVptWmxjaUE5SUdaMWJtTjBhVzl1SUdselFuVm1abVZ5SUNoaUtTQjdYRzRnSUhKbGRIVnliaUFoSVNoaUlDRTlJRzUxYkd3Z0ppWWdZaTVmYVhOQ2RXWm1aWElwWEc1OVhHNWNia0oxWm1abGNpNWpiMjF3WVhKbElEMGdablZ1WTNScGIyNGdZMjl0Y0dGeVpTQW9ZU3dnWWlrZ2UxeHVJQ0JwWmlBb0lVSjFabVpsY2k1cGMwSjFabVpsY2loaEtTQjhmQ0FoUW5WbVptVnlMbWx6UW5WbVptVnlLR0lwS1NCN1hHNGdJQ0FnZEdoeWIzY2dibVYzSUZSNWNHVkZjbkp2Y2lnblFYSm5kVzFsYm5SeklHMTFjM1FnWW1VZ1FuVm1abVZ5Y3ljcFhHNGdJSDFjYmx4dUlDQnBaaUFvWVNBOVBUMGdZaWtnY21WMGRYSnVJREJjYmx4dUlDQjJZWElnZUNBOUlHRXViR1Z1WjNSb1hHNGdJSFpoY2lCNUlEMGdZaTVzWlc1bmRHaGNibHh1SUNCMllYSWdhU0E5SURCY2JpQWdkbUZ5SUd4bGJpQTlJRTFoZEdndWJXbHVLSGdzSUhrcFhHNGdJSGRvYVd4bElDaHBJRHdnYkdWdUtTQjdYRzRnSUNBZ2FXWWdLR0ZiYVYwZ0lUMDlJR0piYVYwcElHSnlaV0ZyWEc1Y2JpQWdJQ0FySzJsY2JpQWdmVnh1WEc0Z0lHbG1JQ2hwSUNFOVBTQnNaVzRwSUh0Y2JpQWdJQ0I0SUQwZ1lWdHBYVnh1SUNBZ0lIa2dQU0JpVzJsZFhHNGdJSDFjYmx4dUlDQnBaaUFvZUNBOElIa3BJSEpsZEhWeWJpQXRNVnh1SUNCcFppQW9lU0E4SUhncElISmxkSFZ5YmlBeFhHNGdJSEpsZEhWeWJpQXdYRzU5WEc1Y2JrSjFabVpsY2k1cGMwVnVZMjlrYVc1bklEMGdablZ1WTNScGIyNGdhWE5GYm1OdlpHbHVaeUFvWlc1amIyUnBibWNwSUh0Y2JpQWdjM2RwZEdOb0lDaFRkSEpwYm1jb1pXNWpiMlJwYm1jcExuUnZURzkzWlhKRFlYTmxLQ2twSUh0Y2JpQWdJQ0JqWVhObElDZG9aWGduT2x4dUlDQWdJR05oYzJVZ0ozVjBaamduT2x4dUlDQWdJR05oYzJVZ0ozVjBaaTA0SnpwY2JpQWdJQ0JqWVhObElDZGhjMk5wYVNjNlhHNGdJQ0FnWTJGelpTQW5ZbWx1WVhKNUp6cGNiaUFnSUNCallYTmxJQ2RpWVhObE5qUW5PbHh1SUNBZ0lHTmhjMlVnSjNKaGR5YzZYRzRnSUNBZ1kyRnpaU0FuZFdOek1pYzZYRzRnSUNBZ1kyRnpaU0FuZFdOekxUSW5PbHh1SUNBZ0lHTmhjMlVnSjNWMFpqRTJiR1VuT2x4dUlDQWdJR05oYzJVZ0ozVjBaaTB4Tm14bEp6cGNiaUFnSUNBZ0lISmxkSFZ5YmlCMGNuVmxYRzRnSUNBZ1pHVm1ZWFZzZERwY2JpQWdJQ0FnSUhKbGRIVnliaUJtWVd4elpWeHVJQ0I5WEc1OVhHNWNia0oxWm1abGNpNWpiMjVqWVhRZ1BTQm1kVzVqZEdsdmJpQmpiMjVqWVhRZ0tHeHBjM1FzSUd4bGJtZDBhQ2tnZTF4dUlDQnBaaUFvSVdselFYSnlZWGtvYkdsemRDa3BJSFJvY205M0lHNWxkeUJVZVhCbFJYSnliM0lvSjJ4cGMzUWdZWEpuZFcxbGJuUWdiWFZ6ZENCaVpTQmhiaUJCY25KaGVTQnZaaUJDZFdabVpYSnpMaWNwWEc1Y2JpQWdhV1lnS0d4cGMzUXViR1Z1WjNSb0lEMDlQU0F3S1NCN1hHNGdJQ0FnY21WMGRYSnVJRzVsZHlCQ2RXWm1aWElvTUNsY2JpQWdmVnh1WEc0Z0lIWmhjaUJwWEc0Z0lHbG1JQ2hzWlc1bmRHZ2dQVDA5SUhWdVpHVm1hVzVsWkNrZ2UxeHVJQ0FnSUd4bGJtZDBhQ0E5SURCY2JpQWdJQ0JtYjNJZ0tHa2dQU0F3T3lCcElEd2diR2x6ZEM1c1pXNW5kR2c3SUdrckt5a2dlMXh1SUNBZ0lDQWdiR1Z1WjNSb0lDczlJR3hwYzNSYmFWMHViR1Z1WjNSb1hHNGdJQ0FnZlZ4dUlDQjlYRzVjYmlBZ2RtRnlJR0oxWmlBOUlHNWxkeUJDZFdabVpYSW9iR1Z1WjNSb0tWeHVJQ0IyWVhJZ2NHOXpJRDBnTUZ4dUlDQm1iM0lnS0drZ1BTQXdPeUJwSUR3Z2JHbHpkQzVzWlc1bmRHZzdJR2tyS3lrZ2UxeHVJQ0FnSUhaaGNpQnBkR1Z0SUQwZ2JHbHpkRnRwWFZ4dUlDQWdJR2wwWlcwdVkyOXdlU2hpZFdZc0lIQnZjeWxjYmlBZ0lDQndiM01nS3owZ2FYUmxiUzVzWlc1bmRHaGNiaUFnZlZ4dUlDQnlaWFIxY200Z1luVm1YRzU5WEc1Y2JtWjFibU4wYVc5dUlHSjVkR1ZNWlc1bmRHZ2dLSE4wY21sdVp5d2daVzVqYjJScGJtY3BJSHRjYmlBZ2FXWWdLSFI1Y0dWdlppQnpkSEpwYm1jZ0lUMDlJQ2R6ZEhKcGJtY25LU0J6ZEhKcGJtY2dQU0FuSnlBcklITjBjbWx1WjF4dVhHNGdJSFpoY2lCc1pXNGdQU0J6ZEhKcGJtY3ViR1Z1WjNSb1hHNGdJR2xtSUNoc1pXNGdQVDA5SURBcElISmxkSFZ5YmlBd1hHNWNiaUFnTHk4Z1ZYTmxJR0VnWm05eUlHeHZiM0FnZEc4Z1lYWnZhV1FnY21WamRYSnphVzl1WEc0Z0lIWmhjaUJzYjNkbGNtVmtRMkZ6WlNBOUlHWmhiSE5sWEc0Z0lHWnZjaUFvT3pzcElIdGNiaUFnSUNCemQybDBZMmdnS0dWdVkyOWthVzVuS1NCN1hHNGdJQ0FnSUNCallYTmxJQ2RoYzJOcGFTYzZYRzRnSUNBZ0lDQmpZWE5sSUNkaWFXNWhjbmtuT2x4dUlDQWdJQ0FnTHk4Z1JHVndjbVZqWVhSbFpGeHVJQ0FnSUNBZ1kyRnpaU0FuY21GM0p6cGNiaUFnSUNBZ0lHTmhjMlVnSjNKaGQzTW5PbHh1SUNBZ0lDQWdJQ0J5WlhSMWNtNGdiR1Z1WEc0Z0lDQWdJQ0JqWVhObElDZDFkR1k0SnpwY2JpQWdJQ0FnSUdOaGMyVWdKM1YwWmkwNEp6cGNiaUFnSUNBZ0lDQWdjbVYwZFhKdUlIVjBaamhVYjBKNWRHVnpLSE4wY21sdVp5a3ViR1Z1WjNSb1hHNGdJQ0FnSUNCallYTmxJQ2QxWTNNeUp6cGNiaUFnSUNBZ0lHTmhjMlVnSjNWamN5MHlKenBjYmlBZ0lDQWdJR05oYzJVZ0ozVjBaakUyYkdVbk9seHVJQ0FnSUNBZ1kyRnpaU0FuZFhSbUxURTJiR1VuT2x4dUlDQWdJQ0FnSUNCeVpYUjFjbTRnYkdWdUlDb2dNbHh1SUNBZ0lDQWdZMkZ6WlNBbmFHVjRKenBjYmlBZ0lDQWdJQ0FnY21WMGRYSnVJR3hsYmlBK1BqNGdNVnh1SUNBZ0lDQWdZMkZ6WlNBblltRnpaVFkwSnpwY2JpQWdJQ0FnSUNBZ2NtVjBkWEp1SUdKaGMyVTJORlJ2UW5sMFpYTW9jM1J5YVc1bktTNXNaVzVuZEdoY2JpQWdJQ0FnSUdSbFptRjFiSFE2WEc0Z0lDQWdJQ0FnSUdsbUlDaHNiM2RsY21Wa1EyRnpaU2tnY21WMGRYSnVJSFYwWmpoVWIwSjVkR1Z6S0hOMGNtbHVaeWt1YkdWdVozUm9JQzh2SUdGemMzVnRaU0IxZEdZNFhHNGdJQ0FnSUNBZ0lHVnVZMjlrYVc1bklEMGdLQ2NuSUNzZ1pXNWpiMlJwYm1jcExuUnZURzkzWlhKRFlYTmxLQ2xjYmlBZ0lDQWdJQ0FnYkc5M1pYSmxaRU5oYzJVZ1BTQjBjblZsWEc0Z0lDQWdmVnh1SUNCOVhHNTlYRzVDZFdabVpYSXVZbmwwWlV4bGJtZDBhQ0E5SUdKNWRHVk1aVzVuZEdoY2JseHVablZ1WTNScGIyNGdjMnh2ZDFSdlUzUnlhVzVuSUNobGJtTnZaR2x1Wnl3Z2MzUmhjblFzSUdWdVpDa2dlMXh1SUNCMllYSWdiRzkzWlhKbFpFTmhjMlVnUFNCbVlXeHpaVnh1WEc0Z0lITjBZWEowSUQwZ2MzUmhjblFnZkNBd1hHNGdJR1Z1WkNBOUlHVnVaQ0E5UFQwZ2RXNWtaV1pwYm1Wa0lIeDhJR1Z1WkNBOVBUMGdTVzVtYVc1cGRIa2dQeUIwYUdsekxteGxibWQwYUNBNklHVnVaQ0I4SURCY2JseHVJQ0JwWmlBb0lXVnVZMjlrYVc1bktTQmxibU52WkdsdVp5QTlJQ2QxZEdZNEoxeHVJQ0JwWmlBb2MzUmhjblFnUENBd0tTQnpkR0Z5ZENBOUlEQmNiaUFnYVdZZ0tHVnVaQ0ErSUhSb2FYTXViR1Z1WjNSb0tTQmxibVFnUFNCMGFHbHpMbXhsYm1kMGFGeHVJQ0JwWmlBb1pXNWtJRHc5SUhOMFlYSjBLU0J5WlhSMWNtNGdKeWRjYmx4dUlDQjNhR2xzWlNBb2RISjFaU2tnZTF4dUlDQWdJSE4zYVhSamFDQW9aVzVqYjJScGJtY3BJSHRjYmlBZ0lDQWdJR05oYzJVZ0oyaGxlQ2M2WEc0Z0lDQWdJQ0FnSUhKbGRIVnliaUJvWlhoVGJHbGpaU2gwYUdsekxDQnpkR0Z5ZEN3Z1pXNWtLVnh1WEc0Z0lDQWdJQ0JqWVhObElDZDFkR1k0SnpwY2JpQWdJQ0FnSUdOaGMyVWdKM1YwWmkwNEp6cGNiaUFnSUNBZ0lDQWdjbVYwZFhKdUlIVjBaamhUYkdsalpTaDBhR2x6TENCemRHRnlkQ3dnWlc1a0tWeHVYRzRnSUNBZ0lDQmpZWE5sSUNkaGMyTnBhU2M2WEc0Z0lDQWdJQ0FnSUhKbGRIVnliaUJoYzJOcGFWTnNhV05sS0hSb2FYTXNJSE4wWVhKMExDQmxibVFwWEc1Y2JpQWdJQ0FnSUdOaGMyVWdKMkpwYm1GeWVTYzZYRzRnSUNBZ0lDQWdJSEpsZEhWeWJpQmlhVzVoY25sVGJHbGpaU2gwYUdsekxDQnpkR0Z5ZEN3Z1pXNWtLVnh1WEc0Z0lDQWdJQ0JqWVhObElDZGlZWE5sTmpRbk9seHVJQ0FnSUNBZ0lDQnlaWFIxY200Z1ltRnpaVFkwVTJ4cFkyVW9kR2hwY3l3Z2MzUmhjblFzSUdWdVpDbGNibHh1SUNBZ0lDQWdZMkZ6WlNBbmRXTnpNaWM2WEc0Z0lDQWdJQ0JqWVhObElDZDFZM010TWljNlhHNGdJQ0FnSUNCallYTmxJQ2QxZEdZeE5teGxKenBjYmlBZ0lDQWdJR05oYzJVZ0ozVjBaaTB4Tm14bEp6cGNiaUFnSUNBZ0lDQWdjbVYwZFhKdUlIVjBaakUyYkdWVGJHbGpaU2gwYUdsekxDQnpkR0Z5ZEN3Z1pXNWtLVnh1WEc0Z0lDQWdJQ0JrWldaaGRXeDBPbHh1SUNBZ0lDQWdJQ0JwWmlBb2JHOTNaWEpsWkVOaGMyVXBJSFJvY205M0lHNWxkeUJVZVhCbFJYSnliM0lvSjFWdWEyNXZkMjRnWlc1amIyUnBibWM2SUNjZ0t5QmxibU52WkdsdVp5bGNiaUFnSUNBZ0lDQWdaVzVqYjJScGJtY2dQU0FvWlc1amIyUnBibWNnS3lBbkp5a3VkRzlNYjNkbGNrTmhjMlVvS1Z4dUlDQWdJQ0FnSUNCc2IzZGxjbVZrUTJGelpTQTlJSFJ5ZFdWY2JpQWdJQ0I5WEc0Z0lIMWNibjFjYmx4dVFuVm1abVZ5TG5CeWIzUnZkSGx3WlM1MGIxTjBjbWx1WnlBOUlHWjFibU4wYVc5dUlIUnZVM1J5YVc1bklDZ3BJSHRjYmlBZ2RtRnlJR3hsYm1kMGFDQTlJSFJvYVhNdWJHVnVaM1JvSUh3Z01GeHVJQ0JwWmlBb2JHVnVaM1JvSUQwOVBTQXdLU0J5WlhSMWNtNGdKeWRjYmlBZ2FXWWdLR0Z5WjNWdFpXNTBjeTVzWlc1bmRHZ2dQVDA5SURBcElISmxkSFZ5YmlCMWRHWTRVMnhwWTJVb2RHaHBjeXdnTUN3Z2JHVnVaM1JvS1Z4dUlDQnlaWFIxY200Z2MyeHZkMVJ2VTNSeWFXNW5MbUZ3Y0d4NUtIUm9hWE1zSUdGeVozVnRaVzUwY3lsY2JuMWNibHh1UW5WbVptVnlMbkJ5YjNSdmRIbHdaUzVsY1hWaGJITWdQU0JtZFc1amRHbHZiaUJsY1hWaGJITWdLR0lwSUh0Y2JpQWdhV1lnS0NGQ2RXWm1aWEl1YVhOQ2RXWm1aWElvWWlrcElIUm9jbTkzSUc1bGR5QlVlWEJsUlhKeWIzSW9KMEZ5WjNWdFpXNTBJRzExYzNRZ1ltVWdZU0JDZFdabVpYSW5LVnh1SUNCcFppQW9kR2hwY3lBOVBUMGdZaWtnY21WMGRYSnVJSFJ5ZFdWY2JpQWdjbVYwZFhKdUlFSjFabVpsY2k1amIyMXdZWEpsS0hSb2FYTXNJR0lwSUQwOVBTQXdYRzU5WEc1Y2JrSjFabVpsY2k1d2NtOTBiM1I1Y0dVdWFXNXpjR1ZqZENBOUlHWjFibU4wYVc5dUlHbHVjM0JsWTNRZ0tDa2dlMXh1SUNCMllYSWdjM1J5SUQwZ0p5ZGNiaUFnZG1GeUlHMWhlQ0E5SUdWNGNHOXlkSE11U1U1VFVFVkRWRjlOUVZoZlFsbFVSVk5jYmlBZ2FXWWdLSFJvYVhNdWJHVnVaM1JvSUQ0Z01Da2dlMXh1SUNBZ0lITjBjaUE5SUhSb2FYTXVkRzlUZEhKcGJtY29KMmhsZUNjc0lEQXNJRzFoZUNrdWJXRjBZMmdvTHk1N01uMHZaeWt1YW05cGJpZ25JQ2NwWEc0Z0lDQWdhV1lnS0hSb2FYTXViR1Z1WjNSb0lENGdiV0Y0S1NCemRISWdLejBnSnlBdUxpNGdKMXh1SUNCOVhHNGdJSEpsZEhWeWJpQW5QRUoxWm1abGNpQW5JQ3NnYzNSeUlDc2dKejRuWEc1OVhHNWNia0oxWm1abGNpNXdjbTkwYjNSNWNHVXVZMjl0Y0dGeVpTQTlJR1oxYm1OMGFXOXVJR052YlhCaGNtVWdLR0lwSUh0Y2JpQWdhV1lnS0NGQ2RXWm1aWEl1YVhOQ2RXWm1aWElvWWlrcElIUm9jbTkzSUc1bGR5QlVlWEJsUlhKeWIzSW9KMEZ5WjNWdFpXNTBJRzExYzNRZ1ltVWdZU0JDZFdabVpYSW5LVnh1SUNCcFppQW9kR2hwY3lBOVBUMGdZaWtnY21WMGRYSnVJREJjYmlBZ2NtVjBkWEp1SUVKMVptWmxjaTVqYjIxd1lYSmxLSFJvYVhNc0lHSXBYRzU5WEc1Y2JrSjFabVpsY2k1d2NtOTBiM1I1Y0dVdWFXNWtaWGhQWmlBOUlHWjFibU4wYVc5dUlHbHVaR1Y0VDJZZ0tIWmhiQ3dnWW5sMFpVOW1abk5sZENrZ2UxeHVJQ0JwWmlBb1lubDBaVTltWm5ObGRDQStJREI0TjJabVptWm1abVlwSUdKNWRHVlBabVp6WlhRZ1BTQXdlRGRtWm1abVptWm1YRzRnSUdWc2MyVWdhV1lnS0dKNWRHVlBabVp6WlhRZ1BDQXRNSGc0TURBd01EQXdNQ2tnWW5sMFpVOW1abk5sZENBOUlDMHdlRGd3TURBd01EQXdYRzRnSUdKNWRHVlBabVp6WlhRZ1BqNDlJREJjYmx4dUlDQnBaaUFvZEdocGN5NXNaVzVuZEdnZ1BUMDlJREFwSUhKbGRIVnliaUF0TVZ4dUlDQnBaaUFvWW5sMFpVOW1abk5sZENBK1BTQjBhR2x6TG14bGJtZDBhQ2tnY21WMGRYSnVJQzB4WEc1Y2JpQWdMeThnVG1WbllYUnBkbVVnYjJabWMyVjBjeUJ6ZEdGeWRDQm1jbTl0SUhSb1pTQmxibVFnYjJZZ2RHaGxJR0oxWm1abGNseHVJQ0JwWmlBb1lubDBaVTltWm5ObGRDQThJREFwSUdKNWRHVlBabVp6WlhRZ1BTQk5ZWFJvTG0xaGVDaDBhR2x6TG14bGJtZDBhQ0FySUdKNWRHVlBabVp6WlhRc0lEQXBYRzVjYmlBZ2FXWWdLSFI1Y0dWdlppQjJZV3dnUFQwOUlDZHpkSEpwYm1jbktTQjdYRzRnSUNBZ2FXWWdLSFpoYkM1c1pXNW5kR2dnUFQwOUlEQXBJSEpsZEhWeWJpQXRNU0F2THlCemNHVmphV0ZzSUdOaGMyVTZJR3h2YjJ0cGJtY2dabTl5SUdWdGNIUjVJSE4wY21sdVp5QmhiSGRoZVhNZ1ptRnBiSE5jYmlBZ0lDQnlaWFIxY200Z1UzUnlhVzVuTG5CeWIzUnZkSGx3WlM1cGJtUmxlRTltTG1OaGJHd29kR2hwY3l3Z2RtRnNMQ0JpZVhSbFQyWm1jMlYwS1Z4dUlDQjlYRzRnSUdsbUlDaENkV1ptWlhJdWFYTkNkV1ptWlhJb2RtRnNLU2tnZTF4dUlDQWdJSEpsZEhWeWJpQmhjbkpoZVVsdVpHVjRUMllvZEdocGN5d2dkbUZzTENCaWVYUmxUMlptYzJWMEtWeHVJQ0I5WEc0Z0lHbG1JQ2gwZVhCbGIyWWdkbUZzSUQwOVBTQW5iblZ0WW1WeUp5a2dlMXh1SUNBZ0lHbG1JQ2hDZFdabVpYSXVWRmxRUlVSZlFWSlNRVmxmVTFWUVVFOVNWQ0FtSmlCVmFXNTBPRUZ5Y21GNUxuQnliM1J2ZEhsd1pTNXBibVJsZUU5bUlEMDlQU0FuWm5WdVkzUnBiMjRuS1NCN1hHNGdJQ0FnSUNCeVpYUjFjbTRnVldsdWREaEJjbkpoZVM1d2NtOTBiM1I1Y0dVdWFXNWtaWGhQWmk1allXeHNLSFJvYVhNc0lIWmhiQ3dnWW5sMFpVOW1abk5sZENsY2JpQWdJQ0I5WEc0Z0lDQWdjbVYwZFhKdUlHRnljbUY1U1c1a1pYaFBaaWgwYUdsekxDQmJJSFpoYkNCZExDQmllWFJsVDJabWMyVjBLVnh1SUNCOVhHNWNiaUFnWm5WdVkzUnBiMjRnWVhKeVlYbEpibVJsZUU5bUlDaGhjbklzSUhaaGJDd2dZbmwwWlU5bVpuTmxkQ2tnZTF4dUlDQWdJSFpoY2lCbWIzVnVaRWx1WkdWNElEMGdMVEZjYmlBZ0lDQm1iM0lnS0haaGNpQnBJRDBnTURzZ1lubDBaVTltWm5ObGRDQXJJR2tnUENCaGNuSXViR1Z1WjNSb095QnBLeXNwSUh0Y2JpQWdJQ0FnSUdsbUlDaGhjbkpiWW5sMFpVOW1abk5sZENBcklHbGRJRDA5UFNCMllXeGJabTkxYm1SSmJtUmxlQ0E5UFQwZ0xURWdQeUF3SURvZ2FTQXRJR1p2ZFc1a1NXNWtaWGhkS1NCN1hHNGdJQ0FnSUNBZ0lHbG1JQ2htYjNWdVpFbHVaR1Y0SUQwOVBTQXRNU2tnWm05MWJtUkpibVJsZUNBOUlHbGNiaUFnSUNBZ0lDQWdhV1lnS0drZ0xTQm1iM1Z1WkVsdVpHVjRJQ3NnTVNBOVBUMGdkbUZzTG14bGJtZDBhQ2tnY21WMGRYSnVJR0o1ZEdWUFptWnpaWFFnS3lCbWIzVnVaRWx1WkdWNFhHNGdJQ0FnSUNCOUlHVnNjMlVnZTF4dUlDQWdJQ0FnSUNCbWIzVnVaRWx1WkdWNElEMGdMVEZjYmlBZ0lDQWdJSDFjYmlBZ0lDQjlYRzRnSUNBZ2NtVjBkWEp1SUMweFhHNGdJSDFjYmx4dUlDQjBhSEp2ZHlCdVpYY2dWSGx3WlVWeWNtOXlLQ2QyWVd3Z2JYVnpkQ0JpWlNCemRISnBibWNzSUc1MWJXSmxjaUJ2Y2lCQ2RXWm1aWEluS1Z4dWZWeHVYRzR2THlCZ1oyVjBZQ0JwY3lCa1pYQnlaV05oZEdWa1hHNUNkV1ptWlhJdWNISnZkRzkwZVhCbExtZGxkQ0E5SUdaMWJtTjBhVzl1SUdkbGRDQW9iMlptYzJWMEtTQjdYRzRnSUdOdmJuTnZiR1V1Ykc5bktDY3VaMlYwS0NrZ2FYTWdaR1Z3Y21WallYUmxaQzRnUVdOalpYTnpJSFZ6YVc1bklHRnljbUY1SUdsdVpHVjRaWE1nYVc1emRHVmhaQzRuS1Z4dUlDQnlaWFIxY200Z2RHaHBjeTV5WldGa1ZVbHVkRGdvYjJabWMyVjBLVnh1ZlZ4dVhHNHZMeUJnYzJWMFlDQnBjeUJrWlhCeVpXTmhkR1ZrWEc1Q2RXWm1aWEl1Y0hKdmRHOTBlWEJsTG5ObGRDQTlJR1oxYm1OMGFXOXVJSE5sZENBb2Rpd2diMlptYzJWMEtTQjdYRzRnSUdOdmJuTnZiR1V1Ykc5bktDY3VjMlYwS0NrZ2FYTWdaR1Z3Y21WallYUmxaQzRnUVdOalpYTnpJSFZ6YVc1bklHRnljbUY1SUdsdVpHVjRaWE1nYVc1emRHVmhaQzRuS1Z4dUlDQnlaWFIxY200Z2RHaHBjeTUzY21sMFpWVkpiblE0S0hZc0lHOW1abk5sZENsY2JuMWNibHh1Wm5WdVkzUnBiMjRnYUdWNFYzSnBkR1VnS0dKMVppd2djM1J5YVc1bkxDQnZabVp6WlhRc0lHeGxibWQwYUNrZ2UxeHVJQ0J2Wm1aelpYUWdQU0JPZFcxaVpYSW9iMlptYzJWMEtTQjhmQ0F3WEc0Z0lIWmhjaUJ5WlcxaGFXNXBibWNnUFNCaWRXWXViR1Z1WjNSb0lDMGdiMlptYzJWMFhHNGdJR2xtSUNnaGJHVnVaM1JvS1NCN1hHNGdJQ0FnYkdWdVozUm9JRDBnY21WdFlXbHVhVzVuWEc0Z0lIMGdaV3h6WlNCN1hHNGdJQ0FnYkdWdVozUm9JRDBnVG5WdFltVnlLR3hsYm1kMGFDbGNiaUFnSUNCcFppQW9iR1Z1WjNSb0lENGdjbVZ0WVdsdWFXNW5LU0I3WEc0Z0lDQWdJQ0JzWlc1bmRHZ2dQU0J5WlcxaGFXNXBibWRjYmlBZ0lDQjlYRzRnSUgxY2JseHVJQ0F2THlCdGRYTjBJR0psSUdGdUlHVjJaVzRnYm5WdFltVnlJRzltSUdScFoybDBjMXh1SUNCMllYSWdjM1J5VEdWdUlEMGdjM1J5YVc1bkxteGxibWQwYUZ4dUlDQnBaaUFvYzNSeVRHVnVJQ1VnTWlBaFBUMGdNQ2tnZEdoeWIzY2dibVYzSUVWeWNtOXlLQ2RKYm5aaGJHbGtJR2hsZUNCemRISnBibWNuS1Z4dVhHNGdJR2xtSUNoc1pXNW5kR2dnUGlCemRISk1aVzRnTHlBeUtTQjdYRzRnSUNBZ2JHVnVaM1JvSUQwZ2MzUnlUR1Z1SUM4Z01seHVJQ0I5WEc0Z0lHWnZjaUFvZG1GeUlHa2dQU0F3T3lCcElEd2diR1Z1WjNSb095QnBLeXNwSUh0Y2JpQWdJQ0IyWVhJZ2NHRnljMlZrSUQwZ2NHRnljMlZKYm5Rb2MzUnlhVzVuTG5OMVluTjBjaWhwSUNvZ01pd2dNaWtzSURFMktWeHVJQ0FnSUdsbUlDaHBjMDVoVGlod1lYSnpaV1FwS1NCMGFISnZkeUJ1WlhjZ1JYSnliM0lvSjBsdWRtRnNhV1FnYUdWNElITjBjbWx1WnljcFhHNGdJQ0FnWW5WbVcyOW1abk5sZENBcklHbGRJRDBnY0dGeWMyVmtYRzRnSUgxY2JpQWdjbVYwZFhKdUlHbGNibjFjYmx4dVpuVnVZM1JwYjI0Z2RYUm1PRmR5YVhSbElDaGlkV1lzSUhOMGNtbHVaeXdnYjJabWMyVjBMQ0JzWlc1bmRHZ3BJSHRjYmlBZ2NtVjBkWEp1SUdKc2FYUkNkV1ptWlhJb2RYUm1PRlJ2UW5sMFpYTW9jM1J5YVc1bkxDQmlkV1l1YkdWdVozUm9JQzBnYjJabWMyVjBLU3dnWW5WbUxDQnZabVp6WlhRc0lHeGxibWQwYUNsY2JuMWNibHh1Wm5WdVkzUnBiMjRnWVhOamFXbFhjbWwwWlNBb1luVm1MQ0J6ZEhKcGJtY3NJRzltWm5ObGRDd2diR1Z1WjNSb0tTQjdYRzRnSUhKbGRIVnliaUJpYkdsMFFuVm1abVZ5S0dGelkybHBWRzlDZVhSbGN5aHpkSEpwYm1jcExDQmlkV1lzSUc5bVpuTmxkQ3dnYkdWdVozUm9LVnh1ZlZ4dVhHNW1kVzVqZEdsdmJpQmlhVzVoY25sWGNtbDBaU0FvWW5WbUxDQnpkSEpwYm1jc0lHOW1abk5sZEN3Z2JHVnVaM1JvS1NCN1hHNGdJSEpsZEhWeWJpQmhjMk5wYVZkeWFYUmxLR0oxWml3Z2MzUnlhVzVuTENCdlptWnpaWFFzSUd4bGJtZDBhQ2xjYm4xY2JseHVablZ1WTNScGIyNGdZbUZ6WlRZMFYzSnBkR1VnS0dKMVppd2djM1J5YVc1bkxDQnZabVp6WlhRc0lHeGxibWQwYUNrZ2UxeHVJQ0J5WlhSMWNtNGdZbXhwZEVKMVptWmxjaWhpWVhObE5qUlViMEo1ZEdWektITjBjbWx1Wnlrc0lHSjFaaXdnYjJabWMyVjBMQ0JzWlc1bmRHZ3BYRzU5WEc1Y2JtWjFibU4wYVc5dUlIVmpjekpYY21sMFpTQW9ZblZtTENCemRISnBibWNzSUc5bVpuTmxkQ3dnYkdWdVozUm9LU0I3WEc0Z0lISmxkSFZ5YmlCaWJHbDBRblZtWm1WeUtIVjBaakUyYkdWVWIwSjVkR1Z6S0hOMGNtbHVaeXdnWW5WbUxteGxibWQwYUNBdElHOW1abk5sZENrc0lHSjFaaXdnYjJabWMyVjBMQ0JzWlc1bmRHZ3BYRzU5WEc1Y2JrSjFabVpsY2k1d2NtOTBiM1I1Y0dVdWQzSnBkR1VnUFNCbWRXNWpkR2x2YmlCM2NtbDBaU0FvYzNSeWFXNW5MQ0J2Wm1aelpYUXNJR3hsYm1kMGFDd2daVzVqYjJScGJtY3BJSHRjYmlBZ0x5OGdRblZtWm1WeUkzZHlhWFJsS0hOMGNtbHVaeWxjYmlBZ2FXWWdLRzltWm5ObGRDQTlQVDBnZFc1a1pXWnBibVZrS1NCN1hHNGdJQ0FnWlc1amIyUnBibWNnUFNBbmRYUm1PQ2RjYmlBZ0lDQnNaVzVuZEdnZ1BTQjBhR2x6TG14bGJtZDBhRnh1SUNBZ0lHOW1abk5sZENBOUlEQmNiaUFnTHk4Z1FuVm1abVZ5STNkeWFYUmxLSE4wY21sdVp5d2daVzVqYjJScGJtY3BYRzRnSUgwZ1pXeHpaU0JwWmlBb2JHVnVaM1JvSUQwOVBTQjFibVJsWm1sdVpXUWdKaVlnZEhsd1pXOW1JRzltWm5ObGRDQTlQVDBnSjNOMGNtbHVaeWNwSUh0Y2JpQWdJQ0JsYm1OdlpHbHVaeUE5SUc5bVpuTmxkRnh1SUNBZ0lHeGxibWQwYUNBOUlIUm9hWE11YkdWdVozUm9YRzRnSUNBZ2IyWm1jMlYwSUQwZ01GeHVJQ0F2THlCQ2RXWm1aWElqZDNKcGRHVW9jM1J5YVc1bkxDQnZabVp6WlhSYkxDQnNaVzVuZEdoZFd5d2daVzVqYjJScGJtZGRLVnh1SUNCOUlHVnNjMlVnYVdZZ0tHbHpSbWx1YVhSbEtHOW1abk5sZENrcElIdGNiaUFnSUNCdlptWnpaWFFnUFNCdlptWnpaWFFnZkNBd1hHNGdJQ0FnYVdZZ0tHbHpSbWx1YVhSbEtHeGxibWQwYUNrcElIdGNiaUFnSUNBZ0lHeGxibWQwYUNBOUlHeGxibWQwYUNCOElEQmNiaUFnSUNBZ0lHbG1JQ2hsYm1OdlpHbHVaeUE5UFQwZ2RXNWtaV1pwYm1Wa0tTQmxibU52WkdsdVp5QTlJQ2QxZEdZNEoxeHVJQ0FnSUgwZ1pXeHpaU0I3WEc0Z0lDQWdJQ0JsYm1OdlpHbHVaeUE5SUd4bGJtZDBhRnh1SUNBZ0lDQWdiR1Z1WjNSb0lEMGdkVzVrWldacGJtVmtYRzRnSUNBZ2ZWeHVJQ0F2THlCc1pXZGhZM2tnZDNKcGRHVW9jM1J5YVc1bkxDQmxibU52WkdsdVp5d2diMlptYzJWMExDQnNaVzVuZEdncElDMGdjbVZ0YjNabElHbHVJSFl3TGpFelhHNGdJSDBnWld4elpTQjdYRzRnSUNBZ2RtRnlJSE4zWVhBZ1BTQmxibU52WkdsdVoxeHVJQ0FnSUdWdVkyOWthVzVuSUQwZ2IyWm1jMlYwWEc0Z0lDQWdiMlptYzJWMElEMGdiR1Z1WjNSb0lId2dNRnh1SUNBZ0lHeGxibWQwYUNBOUlITjNZWEJjYmlBZ2ZWeHVYRzRnSUhaaGNpQnlaVzFoYVc1cGJtY2dQU0IwYUdsekxteGxibWQwYUNBdElHOW1abk5sZEZ4dUlDQnBaaUFvYkdWdVozUm9JRDA5UFNCMWJtUmxabWx1WldRZ2ZId2diR1Z1WjNSb0lENGdjbVZ0WVdsdWFXNW5LU0JzWlc1bmRHZ2dQU0J5WlcxaGFXNXBibWRjYmx4dUlDQnBaaUFvS0hOMGNtbHVaeTVzWlc1bmRHZ2dQaUF3SUNZbUlDaHNaVzVuZEdnZ1BDQXdJSHg4SUc5bVpuTmxkQ0E4SURBcEtTQjhmQ0J2Wm1aelpYUWdQaUIwYUdsekxteGxibWQwYUNrZ2UxeHVJQ0FnSUhSb2NtOTNJRzVsZHlCU1lXNW5aVVZ5Y205eUtDZGhkSFJsYlhCMElIUnZJSGR5YVhSbElHOTFkSE5wWkdVZ1luVm1abVZ5SUdKdmRXNWtjeWNwWEc0Z0lIMWNibHh1SUNCcFppQW9JV1Z1WTI5a2FXNW5LU0JsYm1OdlpHbHVaeUE5SUNkMWRHWTRKMXh1WEc0Z0lIWmhjaUJzYjNkbGNtVmtRMkZ6WlNBOUlHWmhiSE5sWEc0Z0lHWnZjaUFvT3pzcElIdGNiaUFnSUNCemQybDBZMmdnS0dWdVkyOWthVzVuS1NCN1hHNGdJQ0FnSUNCallYTmxJQ2RvWlhnbk9seHVJQ0FnSUNBZ0lDQnlaWFIxY200Z2FHVjRWM0pwZEdVb2RHaHBjeXdnYzNSeWFXNW5MQ0J2Wm1aelpYUXNJR3hsYm1kMGFDbGNibHh1SUNBZ0lDQWdZMkZ6WlNBbmRYUm1PQ2M2WEc0Z0lDQWdJQ0JqWVhObElDZDFkR1l0T0NjNlhHNGdJQ0FnSUNBZ0lISmxkSFZ5YmlCMWRHWTRWM0pwZEdVb2RHaHBjeXdnYzNSeWFXNW5MQ0J2Wm1aelpYUXNJR3hsYm1kMGFDbGNibHh1SUNBZ0lDQWdZMkZ6WlNBbllYTmphV2tuT2x4dUlDQWdJQ0FnSUNCeVpYUjFjbTRnWVhOamFXbFhjbWwwWlNoMGFHbHpMQ0J6ZEhKcGJtY3NJRzltWm5ObGRDd2diR1Z1WjNSb0tWeHVYRzRnSUNBZ0lDQmpZWE5sSUNkaWFXNWhjbmtuT2x4dUlDQWdJQ0FnSUNCeVpYUjFjbTRnWW1sdVlYSjVWM0pwZEdVb2RHaHBjeXdnYzNSeWFXNW5MQ0J2Wm1aelpYUXNJR3hsYm1kMGFDbGNibHh1SUNBZ0lDQWdZMkZ6WlNBblltRnpaVFkwSnpwY2JpQWdJQ0FnSUNBZ0x5OGdWMkZ5Ym1sdVp6b2diV0Y0VEdWdVozUm9JRzV2ZENCMFlXdGxiaUJwYm5SdklHRmpZMjkxYm5RZ2FXNGdZbUZ6WlRZMFYzSnBkR1ZjYmlBZ0lDQWdJQ0FnY21WMGRYSnVJR0poYzJVMk5GZHlhWFJsS0hSb2FYTXNJSE4wY21sdVp5d2diMlptYzJWMExDQnNaVzVuZEdncFhHNWNiaUFnSUNBZ0lHTmhjMlVnSjNWamN6SW5PbHh1SUNBZ0lDQWdZMkZ6WlNBbmRXTnpMVEluT2x4dUlDQWdJQ0FnWTJGelpTQW5kWFJtTVRac1pTYzZYRzRnSUNBZ0lDQmpZWE5sSUNkMWRHWXRNVFpzWlNjNlhHNGdJQ0FnSUNBZ0lISmxkSFZ5YmlCMVkzTXlWM0pwZEdVb2RHaHBjeXdnYzNSeWFXNW5MQ0J2Wm1aelpYUXNJR3hsYm1kMGFDbGNibHh1SUNBZ0lDQWdaR1ZtWVhWc2REcGNiaUFnSUNBZ0lDQWdhV1lnS0d4dmQyVnlaV1JEWVhObEtTQjBhSEp2ZHlCdVpYY2dWSGx3WlVWeWNtOXlLQ2RWYm10dWIzZHVJR1Z1WTI5a2FXNW5PaUFuSUNzZ1pXNWpiMlJwYm1jcFhHNGdJQ0FnSUNBZ0lHVnVZMjlrYVc1bklEMGdLQ2NuSUNzZ1pXNWpiMlJwYm1jcExuUnZURzkzWlhKRFlYTmxLQ2xjYmlBZ0lDQWdJQ0FnYkc5M1pYSmxaRU5oYzJVZ1BTQjBjblZsWEc0Z0lDQWdmVnh1SUNCOVhHNTlYRzVjYmtKMVptWmxjaTV3Y205MGIzUjVjR1V1ZEc5S1UwOU9JRDBnWm5WdVkzUnBiMjRnZEc5S1UwOU9JQ2dwSUh0Y2JpQWdjbVYwZFhKdUlIdGNiaUFnSUNCMGVYQmxPaUFuUW5WbVptVnlKeXhjYmlBZ0lDQmtZWFJoT2lCQmNuSmhlUzV3Y205MGIzUjVjR1V1YzJ4cFkyVXVZMkZzYkNoMGFHbHpMbDloY25JZ2ZId2dkR2hwY3l3Z01DbGNiaUFnZlZ4dWZWeHVYRzVtZFc1amRHbHZiaUJpWVhObE5qUlRiR2xqWlNBb1luVm1MQ0J6ZEdGeWRDd2daVzVrS1NCN1hHNGdJR2xtSUNoemRHRnlkQ0E5UFQwZ01DQW1KaUJsYm1RZ1BUMDlJR0oxWmk1c1pXNW5kR2dwSUh0Y2JpQWdJQ0J5WlhSMWNtNGdZbUZ6WlRZMExtWnliMjFDZVhSbFFYSnlZWGtvWW5WbUtWeHVJQ0I5SUdWc2MyVWdlMXh1SUNBZ0lISmxkSFZ5YmlCaVlYTmxOalF1Wm5KdmJVSjVkR1ZCY25KaGVTaGlkV1l1YzJ4cFkyVW9jM1JoY25Rc0lHVnVaQ2twWEc0Z0lIMWNibjFjYmx4dVpuVnVZM1JwYjI0Z2RYUm1PRk5zYVdObElDaGlkV1lzSUhOMFlYSjBMQ0JsYm1RcElIdGNiaUFnWlc1a0lEMGdUV0YwYUM1dGFXNG9ZblZtTG14bGJtZDBhQ3dnWlc1a0tWeHVJQ0IyWVhJZ2NtVnpJRDBnVzExY2JseHVJQ0IyWVhJZ2FTQTlJSE4wWVhKMFhHNGdJSGRvYVd4bElDaHBJRHdnWlc1a0tTQjdYRzRnSUNBZ2RtRnlJR1pwY25OMFFubDBaU0E5SUdKMVpsdHBYVnh1SUNBZ0lIWmhjaUJqYjJSbFVHOXBiblFnUFNCdWRXeHNYRzRnSUNBZ2RtRnlJR0o1ZEdWelVHVnlVMlZ4ZFdWdVkyVWdQU0FvWm1seWMzUkNlWFJsSUQ0Z01IaEZSaWtnUHlBMFhHNGdJQ0FnSUNBNklDaG1hWEp6ZEVKNWRHVWdQaUF3ZUVSR0tTQS9JRE5jYmlBZ0lDQWdJRG9nS0dacGNuTjBRbmwwWlNBK0lEQjRRa1lwSUQ4Z01seHVJQ0FnSUNBZ09pQXhYRzVjYmlBZ0lDQnBaaUFvYVNBcklHSjVkR1Z6VUdWeVUyVnhkV1Z1WTJVZ1BEMGdaVzVrS1NCN1hHNGdJQ0FnSUNCMllYSWdjMlZqYjI1a1FubDBaU3dnZEdocGNtUkNlWFJsTENCbWIzVnlkR2hDZVhSbExDQjBaVzF3UTI5a1pWQnZhVzUwWEc1Y2JpQWdJQ0FnSUhOM2FYUmphQ0FvWW5sMFpYTlFaWEpUWlhGMVpXNWpaU2tnZTF4dUlDQWdJQ0FnSUNCallYTmxJREU2WEc0Z0lDQWdJQ0FnSUNBZ2FXWWdLR1pwY25OMFFubDBaU0E4SURCNE9EQXBJSHRjYmlBZ0lDQWdJQ0FnSUNBZ0lHTnZaR1ZRYjJsdWRDQTlJR1pwY25OMFFubDBaVnh1SUNBZ0lDQWdJQ0FnSUgxY2JpQWdJQ0FnSUNBZ0lDQmljbVZoYTF4dUlDQWdJQ0FnSUNCallYTmxJREk2WEc0Z0lDQWdJQ0FnSUNBZ2MyVmpiMjVrUW5sMFpTQTlJR0oxWmx0cElDc2dNVjFjYmlBZ0lDQWdJQ0FnSUNCcFppQW9LSE5sWTI5dVpFSjVkR1VnSmlBd2VFTXdLU0E5UFQwZ01IZzRNQ2tnZTF4dUlDQWdJQ0FnSUNBZ0lDQWdkR1Z0Y0VOdlpHVlFiMmx1ZENBOUlDaG1hWEp6ZEVKNWRHVWdKaUF3ZURGR0tTQThQQ0F3ZURZZ2ZDQW9jMlZqYjI1a1FubDBaU0FtSURCNE0wWXBYRzRnSUNBZ0lDQWdJQ0FnSUNCcFppQW9kR1Z0Y0VOdlpHVlFiMmx1ZENBK0lEQjROMFlwSUh0Y2JpQWdJQ0FnSUNBZ0lDQWdJQ0FnWTI5a1pWQnZhVzUwSUQwZ2RHVnRjRU52WkdWUWIybHVkRnh1SUNBZ0lDQWdJQ0FnSUNBZ2ZWeHVJQ0FnSUNBZ0lDQWdJSDFjYmlBZ0lDQWdJQ0FnSUNCaWNtVmhhMXh1SUNBZ0lDQWdJQ0JqWVhObElETTZYRzRnSUNBZ0lDQWdJQ0FnYzJWamIyNWtRbmwwWlNBOUlHSjFabHRwSUNzZ01WMWNiaUFnSUNBZ0lDQWdJQ0IwYUdseVpFSjVkR1VnUFNCaWRXWmJhU0FySURKZFhHNGdJQ0FnSUNBZ0lDQWdhV1lnS0NoelpXTnZibVJDZVhSbElDWWdNSGhETUNrZ1BUMDlJREI0T0RBZ0ppWWdLSFJvYVhKa1FubDBaU0FtSURCNFF6QXBJRDA5UFNBd2VEZ3dLU0I3WEc0Z0lDQWdJQ0FnSUNBZ0lDQjBaVzF3UTI5a1pWQnZhVzUwSUQwZ0tHWnBjbk4wUW5sMFpTQW1JREI0UmlrZ1BEd2dNSGhESUh3Z0tITmxZMjl1WkVKNWRHVWdKaUF3ZUROR0tTQThQQ0F3ZURZZ2ZDQW9kR2hwY21SQ2VYUmxJQ1lnTUhnelJpbGNiaUFnSUNBZ0lDQWdJQ0FnSUdsbUlDaDBaVzF3UTI5a1pWQnZhVzUwSUQ0Z01IZzNSa1lnSmlZZ0tIUmxiWEJEYjJSbFVHOXBiblFnUENBd2VFUTRNREFnZkh3Z2RHVnRjRU52WkdWUWIybHVkQ0ErSURCNFJFWkdSaWtwSUh0Y2JpQWdJQ0FnSUNBZ0lDQWdJQ0FnWTI5a1pWQnZhVzUwSUQwZ2RHVnRjRU52WkdWUWIybHVkRnh1SUNBZ0lDQWdJQ0FnSUNBZ2ZWeHVJQ0FnSUNBZ0lDQWdJSDFjYmlBZ0lDQWdJQ0FnSUNCaWNtVmhhMXh1SUNBZ0lDQWdJQ0JqWVhObElEUTZYRzRnSUNBZ0lDQWdJQ0FnYzJWamIyNWtRbmwwWlNBOUlHSjFabHRwSUNzZ01WMWNiaUFnSUNBZ0lDQWdJQ0IwYUdseVpFSjVkR1VnUFNCaWRXWmJhU0FySURKZFhHNGdJQ0FnSUNBZ0lDQWdabTkxY25Sb1FubDBaU0E5SUdKMVpsdHBJQ3NnTTExY2JpQWdJQ0FnSUNBZ0lDQnBaaUFvS0hObFkyOXVaRUo1ZEdVZ0ppQXdlRU13S1NBOVBUMGdNSGc0TUNBbUppQW9kR2hwY21SQ2VYUmxJQ1lnTUhoRE1Da2dQVDA5SURCNE9EQWdKaVlnS0dadmRYSjBhRUo1ZEdVZ0ppQXdlRU13S1NBOVBUMGdNSGc0TUNrZ2UxeHVJQ0FnSUNBZ0lDQWdJQ0FnZEdWdGNFTnZaR1ZRYjJsdWRDQTlJQ2htYVhKemRFSjVkR1VnSmlBd2VFWXBJRHc4SURCNE1USWdmQ0FvYzJWamIyNWtRbmwwWlNBbUlEQjRNMFlwSUR3OElEQjRReUI4SUNoMGFHbHlaRUo1ZEdVZ0ppQXdlRE5HS1NBOFBDQXdlRFlnZkNBb1ptOTFjblJvUW5sMFpTQW1JREI0TTBZcFhHNGdJQ0FnSUNBZ0lDQWdJQ0JwWmlBb2RHVnRjRU52WkdWUWIybHVkQ0ErSURCNFJrWkdSaUFtSmlCMFpXMXdRMjlrWlZCdmFXNTBJRHdnTUhneE1UQXdNREFwSUh0Y2JpQWdJQ0FnSUNBZ0lDQWdJQ0FnWTI5a1pWQnZhVzUwSUQwZ2RHVnRjRU52WkdWUWIybHVkRnh1SUNBZ0lDQWdJQ0FnSUNBZ2ZWeHVJQ0FnSUNBZ0lDQWdJSDFjYmlBZ0lDQWdJSDFjYmlBZ0lDQjlYRzVjYmlBZ0lDQnBaaUFvWTI5a1pWQnZhVzUwSUQwOVBTQnVkV3hzS1NCN1hHNGdJQ0FnSUNBdkx5QjNaU0JrYVdRZ2JtOTBJR2RsYm1WeVlYUmxJR0VnZG1Gc2FXUWdZMjlrWlZCdmFXNTBJSE52SUdsdWMyVnlkQ0JoWEc0Z0lDQWdJQ0F2THlCeVpYQnNZV05sYldWdWRDQmphR0Z5SUNoVkswWkdSa1FwSUdGdVpDQmhaSFpoYm1ObElHOXViSGtnTVNCaWVYUmxYRzRnSUNBZ0lDQmpiMlJsVUc5cGJuUWdQU0F3ZUVaR1JrUmNiaUFnSUNBZ0lHSjVkR1Z6VUdWeVUyVnhkV1Z1WTJVZ1BTQXhYRzRnSUNBZ2ZTQmxiSE5sSUdsbUlDaGpiMlJsVUc5cGJuUWdQaUF3ZUVaR1JrWXBJSHRjYmlBZ0lDQWdJQzh2SUdWdVkyOWtaU0IwYnlCMWRHWXhOaUFvYzNWeWNtOW5ZWFJsSUhCaGFYSWdaR0Z1WTJVcFhHNGdJQ0FnSUNCamIyUmxVRzlwYm5RZ0xUMGdNSGd4TURBd01GeHVJQ0FnSUNBZ2NtVnpMbkIxYzJnb1kyOWtaVkJ2YVc1MElENCtQaUF4TUNBbUlEQjRNMFpHSUh3Z01IaEVPREF3S1Z4dUlDQWdJQ0FnWTI5a1pWQnZhVzUwSUQwZ01IaEVRekF3SUh3Z1kyOWtaVkJ2YVc1MElDWWdNSGd6UmtaY2JpQWdJQ0I5WEc1Y2JpQWdJQ0J5WlhNdWNIVnphQ2hqYjJSbFVHOXBiblFwWEc0Z0lDQWdhU0FyUFNCaWVYUmxjMUJsY2xObGNYVmxibU5sWEc0Z0lIMWNibHh1SUNCeVpYUjFjbTRnWkdWamIyUmxRMjlrWlZCdmFXNTBjMEZ5Y21GNUtISmxjeWxjYm4xY2JseHVMeThnUW1GelpXUWdiMjRnYUhSMGNEb3ZMM04wWVdOcmIzWmxjbVpzYjNjdVkyOXRMMkV2TWpJM05EY3lOekl2Tmpnd056UXlMQ0IwYUdVZ1luSnZkM05sY2lCM2FYUm9YRzR2THlCMGFHVWdiRzkzWlhOMElHeHBiV2wwSUdseklFTm9jbTl0WlN3Z2QybDBhQ0F3ZURFd01EQXdJR0Z5WjNNdVhHNHZMeUJYWlNCbmJ5QXhJRzFoWjI1cGRIVmtaU0JzWlhOekxDQm1iM0lnYzJGbVpYUjVYRzUyWVhJZ1RVRllYMEZTUjFWTlJVNVVVMTlNUlU1SFZFZ2dQU0F3ZURFd01EQmNibHh1Wm5WdVkzUnBiMjRnWkdWamIyUmxRMjlrWlZCdmFXNTBjMEZ5Y21GNUlDaGpiMlJsVUc5cGJuUnpLU0I3WEc0Z0lIWmhjaUJzWlc0Z1BTQmpiMlJsVUc5cGJuUnpMbXhsYm1kMGFGeHVJQ0JwWmlBb2JHVnVJRHc5SUUxQldGOUJVa2RWVFVWT1ZGTmZURVZPUjFSSUtTQjdYRzRnSUNBZ2NtVjBkWEp1SUZOMGNtbHVaeTVtY205dFEyaGhja052WkdVdVlYQndiSGtvVTNSeWFXNW5MQ0JqYjJSbFVHOXBiblJ6S1NBdkx5QmhkbTlwWkNCbGVIUnlZU0J6YkdsalpTZ3BYRzRnSUgxY2JseHVJQ0F2THlCRVpXTnZaR1VnYVc0Z1kyaDFibXR6SUhSdklHRjJiMmxrSUZ3aVkyRnNiQ0J6ZEdGamF5QnphWHBsSUdWNFkyVmxaR1ZrWENJdVhHNGdJSFpoY2lCeVpYTWdQU0FuSjF4dUlDQjJZWElnYVNBOUlEQmNiaUFnZDJocGJHVWdLR2tnUENCc1pXNHBJSHRjYmlBZ0lDQnlaWE1nS3owZ1UzUnlhVzVuTG1aeWIyMURhR0Z5UTI5a1pTNWhjSEJzZVNoY2JpQWdJQ0FnSUZOMGNtbHVaeXhjYmlBZ0lDQWdJR052WkdWUWIybHVkSE11YzJ4cFkyVW9hU3dnYVNBclBTQk5RVmhmUVZKSFZVMUZUbFJUWDB4RlRrZFVTQ2xjYmlBZ0lDQXBYRzRnSUgxY2JpQWdjbVYwZFhKdUlISmxjMXh1ZlZ4dVhHNW1kVzVqZEdsdmJpQmhjMk5wYVZOc2FXTmxJQ2hpZFdZc0lITjBZWEowTENCbGJtUXBJSHRjYmlBZ2RtRnlJSEpsZENBOUlDY25YRzRnSUdWdVpDQTlJRTFoZEdndWJXbHVLR0oxWmk1c1pXNW5kR2dzSUdWdVpDbGNibHh1SUNCbWIzSWdLSFpoY2lCcElEMGdjM1JoY25RN0lHa2dQQ0JsYm1RN0lHa3JLeWtnZTF4dUlDQWdJSEpsZENBclBTQlRkSEpwYm1jdVpuSnZiVU5vWVhKRGIyUmxLR0oxWmx0cFhTQW1JREI0TjBZcFhHNGdJSDFjYmlBZ2NtVjBkWEp1SUhKbGRGeHVmVnh1WEc1bWRXNWpkR2x2YmlCaWFXNWhjbmxUYkdsalpTQW9ZblZtTENCemRHRnlkQ3dnWlc1a0tTQjdYRzRnSUhaaGNpQnlaWFFnUFNBbkoxeHVJQ0JsYm1RZ1BTQk5ZWFJvTG0xcGJpaGlkV1l1YkdWdVozUm9MQ0JsYm1RcFhHNWNiaUFnWm05eUlDaDJZWElnYVNBOUlITjBZWEowT3lCcElEd2daVzVrT3lCcEt5c3BJSHRjYmlBZ0lDQnlaWFFnS3owZ1UzUnlhVzVuTG1aeWIyMURhR0Z5UTI5a1pTaGlkV1piYVYwcFhHNGdJSDFjYmlBZ2NtVjBkWEp1SUhKbGRGeHVmVnh1WEc1bWRXNWpkR2x2YmlCb1pYaFRiR2xqWlNBb1luVm1MQ0J6ZEdGeWRDd2daVzVrS1NCN1hHNGdJSFpoY2lCc1pXNGdQU0JpZFdZdWJHVnVaM1JvWEc1Y2JpQWdhV1lnS0NGemRHRnlkQ0I4ZkNCemRHRnlkQ0E4SURBcElITjBZWEowSUQwZ01GeHVJQ0JwWmlBb0lXVnVaQ0I4ZkNCbGJtUWdQQ0F3SUh4OElHVnVaQ0ErSUd4bGJpa2daVzVrSUQwZ2JHVnVYRzVjYmlBZ2RtRnlJRzkxZENBOUlDY25YRzRnSUdadmNpQW9kbUZ5SUdrZ1BTQnpkR0Z5ZERzZ2FTQThJR1Z1WkRzZ2FTc3JLU0I3WEc0Z0lDQWdiM1YwSUNzOUlIUnZTR1Y0S0dKMVpsdHBYU2xjYmlBZ2ZWeHVJQ0J5WlhSMWNtNGdiM1YwWEc1OVhHNWNibVoxYm1OMGFXOXVJSFYwWmpFMmJHVlRiR2xqWlNBb1luVm1MQ0J6ZEdGeWRDd2daVzVrS1NCN1hHNGdJSFpoY2lCaWVYUmxjeUE5SUdKMVppNXpiR2xqWlNoemRHRnlkQ3dnWlc1a0tWeHVJQ0IyWVhJZ2NtVnpJRDBnSnlkY2JpQWdabTl5SUNoMllYSWdhU0E5SURBN0lHa2dQQ0JpZVhSbGN5NXNaVzVuZEdnN0lHa2dLejBnTWlrZ2UxeHVJQ0FnSUhKbGN5QXJQU0JUZEhKcGJtY3Vabkp2YlVOb1lYSkRiMlJsS0dKNWRHVnpXMmxkSUNzZ1lubDBaWE5iYVNBcklERmRJQ29nTWpVMktWeHVJQ0I5WEc0Z0lISmxkSFZ5YmlCeVpYTmNibjFjYmx4dVFuVm1abVZ5TG5CeWIzUnZkSGx3WlM1emJHbGpaU0E5SUdaMWJtTjBhVzl1SUhOc2FXTmxJQ2h6ZEdGeWRDd2daVzVrS1NCN1hHNGdJSFpoY2lCc1pXNGdQU0IwYUdsekxteGxibWQwYUZ4dUlDQnpkR0Z5ZENBOUlINStjM1JoY25SY2JpQWdaVzVrSUQwZ1pXNWtJRDA5UFNCMWJtUmxabWx1WldRZ1B5QnNaVzRnT2lCK2ZtVnVaRnh1WEc0Z0lHbG1JQ2h6ZEdGeWRDQThJREFwSUh0Y2JpQWdJQ0J6ZEdGeWRDQXJQU0JzWlc1Y2JpQWdJQ0JwWmlBb2MzUmhjblFnUENBd0tTQnpkR0Z5ZENBOUlEQmNiaUFnZlNCbGJITmxJR2xtSUNoemRHRnlkQ0ErSUd4bGJpa2dlMXh1SUNBZ0lITjBZWEowSUQwZ2JHVnVYRzRnSUgxY2JseHVJQ0JwWmlBb1pXNWtJRHdnTUNrZ2UxeHVJQ0FnSUdWdVpDQXJQU0JzWlc1Y2JpQWdJQ0JwWmlBb1pXNWtJRHdnTUNrZ1pXNWtJRDBnTUZ4dUlDQjlJR1ZzYzJVZ2FXWWdLR1Z1WkNBK0lHeGxiaWtnZTF4dUlDQWdJR1Z1WkNBOUlHeGxibHh1SUNCOVhHNWNiaUFnYVdZZ0tHVnVaQ0E4SUhOMFlYSjBLU0JsYm1RZ1BTQnpkR0Z5ZEZ4dVhHNGdJSFpoY2lCdVpYZENkV1pjYmlBZ2FXWWdLRUoxWm1abGNpNVVXVkJGUkY5QlVsSkJXVjlUVlZCUVQxSlVLU0I3WEc0Z0lDQWdibVYzUW5WbUlEMGdRblZtWm1WeUxsOWhkV2R0Wlc1MEtIUm9hWE11YzNWaVlYSnlZWGtvYzNSaGNuUXNJR1Z1WkNrcFhHNGdJSDBnWld4elpTQjdYRzRnSUNBZ2RtRnlJSE5zYVdObFRHVnVJRDBnWlc1a0lDMGdjM1JoY25SY2JpQWdJQ0J1WlhkQ2RXWWdQU0J1WlhjZ1FuVm1abVZ5S0hOc2FXTmxUR1Z1TENCMWJtUmxabWx1WldRcFhHNGdJQ0FnWm05eUlDaDJZWElnYVNBOUlEQTdJR2tnUENCemJHbGpaVXhsYmpzZ2FTc3JLU0I3WEc0Z0lDQWdJQ0J1WlhkQ2RXWmJhVjBnUFNCMGFHbHpXMmtnS3lCemRHRnlkRjFjYmlBZ0lDQjlYRzRnSUgxY2JseHVJQ0JwWmlBb2JtVjNRblZtTG14bGJtZDBhQ2tnYm1WM1FuVm1MbkJoY21WdWRDQTlJSFJvYVhNdWNHRnlaVzUwSUh4OElIUm9hWE5jYmx4dUlDQnlaWFIxY200Z2JtVjNRblZtWEc1OVhHNWNiaThxWEc0Z0tpQk9aV1ZrSUhSdklHMWhhMlVnYzNWeVpTQjBhR0YwSUdKMVptWmxjaUJwYzI0bmRDQjBjbmxwYm1jZ2RHOGdkM0pwZEdVZ2IzVjBJRzltSUdKdmRXNWtjeTVjYmlBcUwxeHVablZ1WTNScGIyNGdZMmhsWTJ0UFptWnpaWFFnS0c5bVpuTmxkQ3dnWlhoMExDQnNaVzVuZEdncElIdGNiaUFnYVdZZ0tDaHZabVp6WlhRZ0pTQXhLU0FoUFQwZ01DQjhmQ0J2Wm1aelpYUWdQQ0F3S1NCMGFISnZkeUJ1WlhjZ1VtRnVaMlZGY25KdmNpZ25iMlptYzJWMElHbHpJRzV2ZENCMWFXNTBKeWxjYmlBZ2FXWWdLRzltWm5ObGRDQXJJR1Y0ZENBK0lHeGxibWQwYUNrZ2RHaHliM2NnYm1WM0lGSmhibWRsUlhKeWIzSW9KMVJ5ZVdsdVp5QjBieUJoWTJObGMzTWdZbVY1YjI1a0lHSjFabVpsY2lCc1pXNW5kR2duS1Z4dWZWeHVYRzVDZFdabVpYSXVjSEp2ZEc5MGVYQmxMbkpsWVdSVlNXNTBURVVnUFNCbWRXNWpkR2x2YmlCeVpXRmtWVWx1ZEV4RklDaHZabVp6WlhRc0lHSjVkR1ZNWlc1bmRHZ3NJRzV2UVhOelpYSjBLU0I3WEc0Z0lHOW1abk5sZENBOUlHOW1abk5sZENCOElEQmNiaUFnWW5sMFpVeGxibWQwYUNBOUlHSjVkR1ZNWlc1bmRHZ2dmQ0F3WEc0Z0lHbG1JQ2doYm05QmMzTmxjblFwSUdOb1pXTnJUMlptYzJWMEtHOW1abk5sZEN3Z1lubDBaVXhsYm1kMGFDd2dkR2hwY3k1c1pXNW5kR2dwWEc1Y2JpQWdkbUZ5SUhaaGJDQTlJSFJvYVhOYmIyWm1jMlYwWFZ4dUlDQjJZWElnYlhWc0lEMGdNVnh1SUNCMllYSWdhU0E5SURCY2JpQWdkMmhwYkdVZ0tDc3JhU0E4SUdKNWRHVk1aVzVuZEdnZ0ppWWdLRzExYkNBcVBTQXdlREV3TUNrcElIdGNiaUFnSUNCMllXd2dLejBnZEdocGMxdHZabVp6WlhRZ0t5QnBYU0FxSUcxMWJGeHVJQ0I5WEc1Y2JpQWdjbVYwZFhKdUlIWmhiRnh1ZlZ4dVhHNUNkV1ptWlhJdWNISnZkRzkwZVhCbExuSmxZV1JWU1c1MFFrVWdQU0JtZFc1amRHbHZiaUJ5WldGa1ZVbHVkRUpGSUNodlptWnpaWFFzSUdKNWRHVk1aVzVuZEdnc0lHNXZRWE56WlhKMEtTQjdYRzRnSUc5bVpuTmxkQ0E5SUc5bVpuTmxkQ0I4SURCY2JpQWdZbmwwWlV4bGJtZDBhQ0E5SUdKNWRHVk1aVzVuZEdnZ2ZDQXdYRzRnSUdsbUlDZ2hibTlCYzNObGNuUXBJSHRjYmlBZ0lDQmphR1ZqYTA5bVpuTmxkQ2h2Wm1aelpYUXNJR0o1ZEdWTVpXNW5kR2dzSUhSb2FYTXViR1Z1WjNSb0tWeHVJQ0I5WEc1Y2JpQWdkbUZ5SUhaaGJDQTlJSFJvYVhOYmIyWm1jMlYwSUNzZ0xTMWllWFJsVEdWdVozUm9YVnh1SUNCMllYSWdiWFZzSUQwZ01WeHVJQ0IzYUdsc1pTQW9ZbmwwWlV4bGJtZDBhQ0ErSURBZ0ppWWdLRzExYkNBcVBTQXdlREV3TUNrcElIdGNiaUFnSUNCMllXd2dLejBnZEdocGMxdHZabVp6WlhRZ0t5QXRMV0o1ZEdWTVpXNW5kR2hkSUNvZ2JYVnNYRzRnSUgxY2JseHVJQ0J5WlhSMWNtNGdkbUZzWEc1OVhHNWNia0oxWm1abGNpNXdjbTkwYjNSNWNHVXVjbVZoWkZWSmJuUTRJRDBnWm5WdVkzUnBiMjRnY21WaFpGVkpiblE0SUNodlptWnpaWFFzSUc1dlFYTnpaWEowS1NCN1hHNGdJR2xtSUNnaGJtOUJjM05sY25RcElHTm9aV05yVDJabWMyVjBLRzltWm5ObGRDd2dNU3dnZEdocGN5NXNaVzVuZEdncFhHNGdJSEpsZEhWeWJpQjBhR2x6VzI5bVpuTmxkRjFjYm4xY2JseHVRblZtWm1WeUxuQnliM1J2ZEhsd1pTNXlaV0ZrVlVsdWRERTJURVVnUFNCbWRXNWpkR2x2YmlCeVpXRmtWVWx1ZERFMlRFVWdLRzltWm5ObGRDd2dibTlCYzNObGNuUXBJSHRjYmlBZ2FXWWdLQ0Z1YjBGemMyVnlkQ2tnWTJobFkydFBabVp6WlhRb2IyWm1jMlYwTENBeUxDQjBhR2x6TG14bGJtZDBhQ2xjYmlBZ2NtVjBkWEp1SUhSb2FYTmJiMlptYzJWMFhTQjhJQ2gwYUdselcyOW1abk5sZENBcklERmRJRHc4SURncFhHNTlYRzVjYmtKMVptWmxjaTV3Y205MGIzUjVjR1V1Y21WaFpGVkpiblF4TmtKRklEMGdablZ1WTNScGIyNGdjbVZoWkZWSmJuUXhOa0pGSUNodlptWnpaWFFzSUc1dlFYTnpaWEowS1NCN1hHNGdJR2xtSUNnaGJtOUJjM05sY25RcElHTm9aV05yVDJabWMyVjBLRzltWm5ObGRDd2dNaXdnZEdocGN5NXNaVzVuZEdncFhHNGdJSEpsZEhWeWJpQW9kR2hwYzF0dlptWnpaWFJkSUR3OElEZ3BJSHdnZEdocGMxdHZabVp6WlhRZ0t5QXhYVnh1ZlZ4dVhHNUNkV1ptWlhJdWNISnZkRzkwZVhCbExuSmxZV1JWU1c1ME16Sk1SU0E5SUdaMWJtTjBhVzl1SUhKbFlXUlZTVzUwTXpKTVJTQW9iMlptYzJWMExDQnViMEZ6YzJWeWRDa2dlMXh1SUNCcFppQW9JVzV2UVhOelpYSjBLU0JqYUdWamEwOW1abk5sZENodlptWnpaWFFzSURRc0lIUm9hWE11YkdWdVozUm9LVnh1WEc0Z0lISmxkSFZ5YmlBb0tIUm9hWE5iYjJabWMyVjBYU2tnZkZ4dUlDQWdJQ0FnS0hSb2FYTmJiMlptYzJWMElDc2dNVjBnUER3Z09Da2dmRnh1SUNBZ0lDQWdLSFJvYVhOYmIyWm1jMlYwSUNzZ01sMGdQRHdnTVRZcEtTQXJYRzRnSUNBZ0lDQW9kR2hwYzF0dlptWnpaWFFnS3lBelhTQXFJREI0TVRBd01EQXdNQ2xjYm4xY2JseHVRblZtWm1WeUxuQnliM1J2ZEhsd1pTNXlaV0ZrVlVsdWRETXlRa1VnUFNCbWRXNWpkR2x2YmlCeVpXRmtWVWx1ZERNeVFrVWdLRzltWm5ObGRDd2dibTlCYzNObGNuUXBJSHRjYmlBZ2FXWWdLQ0Z1YjBGemMyVnlkQ2tnWTJobFkydFBabVp6WlhRb2IyWm1jMlYwTENBMExDQjBhR2x6TG14bGJtZDBhQ2xjYmx4dUlDQnlaWFIxY200Z0tIUm9hWE5iYjJabWMyVjBYU0FxSURCNE1UQXdNREF3TUNrZ0sxeHVJQ0FnSUNnb2RHaHBjMXR2Wm1aelpYUWdLeUF4WFNBOFBDQXhOaWtnZkZ4dUlDQWdJQ2gwYUdselcyOW1abk5sZENBcklESmRJRHc4SURncElIeGNiaUFnSUNCMGFHbHpXMjltWm5ObGRDQXJJRE5kS1Z4dWZWeHVYRzVDZFdabVpYSXVjSEp2ZEc5MGVYQmxMbkpsWVdSSmJuUk1SU0E5SUdaMWJtTjBhVzl1SUhKbFlXUkpiblJNUlNBb2IyWm1jMlYwTENCaWVYUmxUR1Z1WjNSb0xDQnViMEZ6YzJWeWRDa2dlMXh1SUNCdlptWnpaWFFnUFNCdlptWnpaWFFnZkNBd1hHNGdJR0o1ZEdWTVpXNW5kR2dnUFNCaWVYUmxUR1Z1WjNSb0lId2dNRnh1SUNCcFppQW9JVzV2UVhOelpYSjBLU0JqYUdWamEwOW1abk5sZENodlptWnpaWFFzSUdKNWRHVk1aVzVuZEdnc0lIUm9hWE11YkdWdVozUm9LVnh1WEc0Z0lIWmhjaUIyWVd3Z1BTQjBhR2x6VzI5bVpuTmxkRjFjYmlBZ2RtRnlJRzExYkNBOUlERmNiaUFnZG1GeUlHa2dQU0F3WEc0Z0lIZG9hV3hsSUNncksya2dQQ0JpZVhSbFRHVnVaM1JvSUNZbUlDaHRkV3dnS2owZ01IZ3hNREFwS1NCN1hHNGdJQ0FnZG1Gc0lDczlJSFJvYVhOYmIyWm1jMlYwSUNzZ2FWMGdLaUJ0ZFd4Y2JpQWdmVnh1SUNCdGRXd2dLajBnTUhnNE1GeHVYRzRnSUdsbUlDaDJZV3dnUGowZ2JYVnNLU0IyWVd3Z0xUMGdUV0YwYUM1d2IzY29NaXdnT0NBcUlHSjVkR1ZNWlc1bmRHZ3BYRzVjYmlBZ2NtVjBkWEp1SUhaaGJGeHVmVnh1WEc1Q2RXWm1aWEl1Y0hKdmRHOTBlWEJsTG5KbFlXUkpiblJDUlNBOUlHWjFibU4wYVc5dUlISmxZV1JKYm5SQ1JTQW9iMlptYzJWMExDQmllWFJsVEdWdVozUm9MQ0J1YjBGemMyVnlkQ2tnZTF4dUlDQnZabVp6WlhRZ1BTQnZabVp6WlhRZ2ZDQXdYRzRnSUdKNWRHVk1aVzVuZEdnZ1BTQmllWFJsVEdWdVozUm9JSHdnTUZ4dUlDQnBaaUFvSVc1dlFYTnpaWEowS1NCamFHVmphMDltWm5ObGRDaHZabVp6WlhRc0lHSjVkR1ZNWlc1bmRHZ3NJSFJvYVhNdWJHVnVaM1JvS1Z4dVhHNGdJSFpoY2lCcElEMGdZbmwwWlV4bGJtZDBhRnh1SUNCMllYSWdiWFZzSUQwZ01WeHVJQ0IyWVhJZ2RtRnNJRDBnZEdocGMxdHZabVp6WlhRZ0t5QXRMV2xkWEc0Z0lIZG9hV3hsSUNocElENGdNQ0FtSmlBb2JYVnNJQ285SURCNE1UQXdLU2tnZTF4dUlDQWdJSFpoYkNBclBTQjBhR2x6VzI5bVpuTmxkQ0FySUMwdGFWMGdLaUJ0ZFd4Y2JpQWdmVnh1SUNCdGRXd2dLajBnTUhnNE1GeHVYRzRnSUdsbUlDaDJZV3dnUGowZ2JYVnNLU0IyWVd3Z0xUMGdUV0YwYUM1d2IzY29NaXdnT0NBcUlHSjVkR1ZNWlc1bmRHZ3BYRzVjYmlBZ2NtVjBkWEp1SUhaaGJGeHVmVnh1WEc1Q2RXWm1aWEl1Y0hKdmRHOTBlWEJsTG5KbFlXUkpiblE0SUQwZ1puVnVZM1JwYjI0Z2NtVmhaRWx1ZERnZ0tHOW1abk5sZEN3Z2JtOUJjM05sY25RcElIdGNiaUFnYVdZZ0tDRnViMEZ6YzJWeWRDa2dZMmhsWTJ0UFptWnpaWFFvYjJabWMyVjBMQ0F4TENCMGFHbHpMbXhsYm1kMGFDbGNiaUFnYVdZZ0tDRW9kR2hwYzF0dlptWnpaWFJkSUNZZ01IZzRNQ2twSUhKbGRIVnliaUFvZEdocGMxdHZabVp6WlhSZEtWeHVJQ0J5WlhSMWNtNGdLQ2d3ZUdabUlDMGdkR2hwYzF0dlptWnpaWFJkSUNzZ01Ta2dLaUF0TVNsY2JuMWNibHh1UW5WbVptVnlMbkJ5YjNSdmRIbHdaUzV5WldGa1NXNTBNVFpNUlNBOUlHWjFibU4wYVc5dUlISmxZV1JKYm5ReE5reEZJQ2h2Wm1aelpYUXNJRzV2UVhOelpYSjBLU0I3WEc0Z0lHbG1JQ2doYm05QmMzTmxjblFwSUdOb1pXTnJUMlptYzJWMEtHOW1abk5sZEN3Z01pd2dkR2hwY3k1c1pXNW5kR2dwWEc0Z0lIWmhjaUIyWVd3Z1BTQjBhR2x6VzI5bVpuTmxkRjBnZkNBb2RHaHBjMXR2Wm1aelpYUWdLeUF4WFNBOFBDQTRLVnh1SUNCeVpYUjFjbTRnS0haaGJDQW1JREI0T0RBd01Da2dQeUIyWVd3Z2ZDQXdlRVpHUmtZd01EQXdJRG9nZG1Gc1hHNTlYRzVjYmtKMVptWmxjaTV3Y205MGIzUjVjR1V1Y21WaFpFbHVkREUyUWtVZ1BTQm1kVzVqZEdsdmJpQnlaV0ZrU1c1ME1UWkNSU0FvYjJabWMyVjBMQ0J1YjBGemMyVnlkQ2tnZTF4dUlDQnBaaUFvSVc1dlFYTnpaWEowS1NCamFHVmphMDltWm5ObGRDaHZabVp6WlhRc0lESXNJSFJvYVhNdWJHVnVaM1JvS1Z4dUlDQjJZWElnZG1Gc0lEMGdkR2hwYzF0dlptWnpaWFFnS3lBeFhTQjhJQ2gwYUdselcyOW1abk5sZEYwZ1BEd2dPQ2xjYmlBZ2NtVjBkWEp1SUNoMllXd2dKaUF3ZURnd01EQXBJRDhnZG1Gc0lId2dNSGhHUmtaR01EQXdNQ0E2SUhaaGJGeHVmVnh1WEc1Q2RXWm1aWEl1Y0hKdmRHOTBlWEJsTG5KbFlXUkpiblF6TWt4RklEMGdablZ1WTNScGIyNGdjbVZoWkVsdWRETXlURVVnS0c5bVpuTmxkQ3dnYm05QmMzTmxjblFwSUh0Y2JpQWdhV1lnS0NGdWIwRnpjMlZ5ZENrZ1kyaGxZMnRQWm1aelpYUW9iMlptYzJWMExDQTBMQ0IwYUdsekxteGxibWQwYUNsY2JseHVJQ0J5WlhSMWNtNGdLSFJvYVhOYmIyWm1jMlYwWFNrZ2ZGeHVJQ0FnSUNoMGFHbHpXMjltWm5ObGRDQXJJREZkSUR3OElEZ3BJSHhjYmlBZ0lDQW9kR2hwYzF0dlptWnpaWFFnS3lBeVhTQThQQ0F4TmlrZ2ZGeHVJQ0FnSUNoMGFHbHpXMjltWm5ObGRDQXJJRE5kSUR3OElESTBLVnh1ZlZ4dVhHNUNkV1ptWlhJdWNISnZkRzkwZVhCbExuSmxZV1JKYm5Rek1rSkZJRDBnWm5WdVkzUnBiMjRnY21WaFpFbHVkRE15UWtVZ0tHOW1abk5sZEN3Z2JtOUJjM05sY25RcElIdGNiaUFnYVdZZ0tDRnViMEZ6YzJWeWRDa2dZMmhsWTJ0UFptWnpaWFFvYjJabWMyVjBMQ0EwTENCMGFHbHpMbXhsYm1kMGFDbGNibHh1SUNCeVpYUjFjbTRnS0hSb2FYTmJiMlptYzJWMFhTQThQQ0F5TkNrZ2ZGeHVJQ0FnSUNoMGFHbHpXMjltWm5ObGRDQXJJREZkSUR3OElERTJLU0I4WEc0Z0lDQWdLSFJvYVhOYmIyWm1jMlYwSUNzZ01sMGdQRHdnT0NrZ2ZGeHVJQ0FnSUNoMGFHbHpXMjltWm5ObGRDQXJJRE5kS1Z4dWZWeHVYRzVDZFdabVpYSXVjSEp2ZEc5MGVYQmxMbkpsWVdSR2JHOWhkRXhGSUQwZ1puVnVZM1JwYjI0Z2NtVmhaRVpzYjJGMFRFVWdLRzltWm5ObGRDd2dibTlCYzNObGNuUXBJSHRjYmlBZ2FXWWdLQ0Z1YjBGemMyVnlkQ2tnWTJobFkydFBabVp6WlhRb2IyWm1jMlYwTENBMExDQjBhR2x6TG14bGJtZDBhQ2xjYmlBZ2NtVjBkWEp1SUdsbFpXVTNOVFF1Y21WaFpDaDBhR2x6TENCdlptWnpaWFFzSUhSeWRXVXNJREl6TENBMEtWeHVmVnh1WEc1Q2RXWm1aWEl1Y0hKdmRHOTBlWEJsTG5KbFlXUkdiRzloZEVKRklEMGdablZ1WTNScGIyNGdjbVZoWkVac2IyRjBRa1VnS0c5bVpuTmxkQ3dnYm05QmMzTmxjblFwSUh0Y2JpQWdhV1lnS0NGdWIwRnpjMlZ5ZENrZ1kyaGxZMnRQWm1aelpYUW9iMlptYzJWMExDQTBMQ0IwYUdsekxteGxibWQwYUNsY2JpQWdjbVYwZFhKdUlHbGxaV1UzTlRRdWNtVmhaQ2gwYUdsekxDQnZabVp6WlhRc0lHWmhiSE5sTENBeU15d2dOQ2xjYm4xY2JseHVRblZtWm1WeUxuQnliM1J2ZEhsd1pTNXlaV0ZrUkc5MVlteGxURVVnUFNCbWRXNWpkR2x2YmlCeVpXRmtSRzkxWW14bFRFVWdLRzltWm5ObGRDd2dibTlCYzNObGNuUXBJSHRjYmlBZ2FXWWdLQ0Z1YjBGemMyVnlkQ2tnWTJobFkydFBabVp6WlhRb2IyWm1jMlYwTENBNExDQjBhR2x6TG14bGJtZDBhQ2xjYmlBZ2NtVjBkWEp1SUdsbFpXVTNOVFF1Y21WaFpDaDBhR2x6TENCdlptWnpaWFFzSUhSeWRXVXNJRFV5TENBNEtWeHVmVnh1WEc1Q2RXWm1aWEl1Y0hKdmRHOTBlWEJsTG5KbFlXUkViM1ZpYkdWQ1JTQTlJR1oxYm1OMGFXOXVJSEpsWVdSRWIzVmliR1ZDUlNBb2IyWm1jMlYwTENCdWIwRnpjMlZ5ZENrZ2UxeHVJQ0JwWmlBb0lXNXZRWE56WlhKMEtTQmphR1ZqYTA5bVpuTmxkQ2h2Wm1aelpYUXNJRGdzSUhSb2FYTXViR1Z1WjNSb0tWeHVJQ0J5WlhSMWNtNGdhV1ZsWlRjMU5DNXlaV0ZrS0hSb2FYTXNJRzltWm5ObGRDd2dabUZzYzJVc0lEVXlMQ0E0S1Z4dWZWeHVYRzVtZFc1amRHbHZiaUJqYUdWamEwbHVkQ0FvWW5WbUxDQjJZV3gxWlN3Z2IyWm1jMlYwTENCbGVIUXNJRzFoZUN3Z2JXbHVLU0I3WEc0Z0lHbG1JQ2doUW5WbVptVnlMbWx6UW5WbVptVnlLR0oxWmlrcElIUm9jbTkzSUc1bGR5QlVlWEJsUlhKeWIzSW9KMkoxWm1abGNpQnRkWE4wSUdKbElHRWdRblZtWm1WeUlHbHVjM1JoYm1ObEp5bGNiaUFnYVdZZ0tIWmhiSFZsSUQ0Z2JXRjRJSHg4SUhaaGJIVmxJRHdnYldsdUtTQjBhSEp2ZHlCdVpYY2dVbUZ1WjJWRmNuSnZjaWduZG1Gc2RXVWdhWE1nYjNWMElHOW1JR0p2ZFc1a2N5Y3BYRzRnSUdsbUlDaHZabVp6WlhRZ0t5QmxlSFFnUGlCaWRXWXViR1Z1WjNSb0tTQjBhSEp2ZHlCdVpYY2dVbUZ1WjJWRmNuSnZjaWduYVc1a1pYZ2diM1YwSUc5bUlISmhibWRsSnlsY2JuMWNibHh1UW5WbVptVnlMbkJ5YjNSdmRIbHdaUzUzY21sMFpWVkpiblJNUlNBOUlHWjFibU4wYVc5dUlIZHlhWFJsVlVsdWRFeEZJQ2gyWVd4MVpTd2diMlptYzJWMExDQmllWFJsVEdWdVozUm9MQ0J1YjBGemMyVnlkQ2tnZTF4dUlDQjJZV3gxWlNBOUlDdDJZV3gxWlZ4dUlDQnZabVp6WlhRZ1BTQnZabVp6WlhRZ2ZDQXdYRzRnSUdKNWRHVk1aVzVuZEdnZ1BTQmllWFJsVEdWdVozUm9JSHdnTUZ4dUlDQnBaaUFvSVc1dlFYTnpaWEowS1NCamFHVmphMGx1ZENoMGFHbHpMQ0IyWVd4MVpTd2diMlptYzJWMExDQmllWFJsVEdWdVozUm9MQ0JOWVhSb0xuQnZkeWd5TENBNElDb2dZbmwwWlV4bGJtZDBhQ2tzSURBcFhHNWNiaUFnZG1GeUlHMTFiQ0E5SURGY2JpQWdkbUZ5SUdrZ1BTQXdYRzRnSUhSb2FYTmJiMlptYzJWMFhTQTlJSFpoYkhWbElDWWdNSGhHUmx4dUlDQjNhR2xzWlNBb0t5dHBJRHdnWW5sMFpVeGxibWQwYUNBbUppQW9iWFZzSUNvOUlEQjRNVEF3S1NrZ2UxeHVJQ0FnSUhSb2FYTmJiMlptYzJWMElDc2dhVjBnUFNBb2RtRnNkV1VnTHlCdGRXd3BJQ1lnTUhoR1JseHVJQ0I5WEc1Y2JpQWdjbVYwZFhKdUlHOW1abk5sZENBcklHSjVkR1ZNWlc1bmRHaGNibjFjYmx4dVFuVm1abVZ5TG5CeWIzUnZkSGx3WlM1M2NtbDBaVlZKYm5SQ1JTQTlJR1oxYm1OMGFXOXVJSGR5YVhSbFZVbHVkRUpGSUNoMllXeDFaU3dnYjJabWMyVjBMQ0JpZVhSbFRHVnVaM1JvTENCdWIwRnpjMlZ5ZENrZ2UxeHVJQ0IyWVd4MVpTQTlJQ3QyWVd4MVpWeHVJQ0J2Wm1aelpYUWdQU0J2Wm1aelpYUWdmQ0F3WEc0Z0lHSjVkR1ZNWlc1bmRHZ2dQU0JpZVhSbFRHVnVaM1JvSUh3Z01GeHVJQ0JwWmlBb0lXNXZRWE56WlhKMEtTQmphR1ZqYTBsdWRDaDBhR2x6TENCMllXeDFaU3dnYjJabWMyVjBMQ0JpZVhSbFRHVnVaM1JvTENCTllYUm9MbkJ2ZHlneUxDQTRJQ29nWW5sMFpVeGxibWQwYUNrc0lEQXBYRzVjYmlBZ2RtRnlJR2tnUFNCaWVYUmxUR1Z1WjNSb0lDMGdNVnh1SUNCMllYSWdiWFZzSUQwZ01WeHVJQ0IwYUdselcyOW1abk5sZENBcklHbGRJRDBnZG1Gc2RXVWdKaUF3ZUVaR1hHNGdJSGRvYVd4bElDZ3RMV2tnUGowZ01DQW1KaUFvYlhWc0lDbzlJREI0TVRBd0tTa2dlMXh1SUNBZ0lIUm9hWE5iYjJabWMyVjBJQ3NnYVYwZ1BTQW9kbUZzZFdVZ0x5QnRkV3dwSUNZZ01IaEdSbHh1SUNCOVhHNWNiaUFnY21WMGRYSnVJRzltWm5ObGRDQXJJR0o1ZEdWTVpXNW5kR2hjYm4xY2JseHVRblZtWm1WeUxuQnliM1J2ZEhsd1pTNTNjbWwwWlZWSmJuUTRJRDBnWm5WdVkzUnBiMjRnZDNKcGRHVlZTVzUwT0NBb2RtRnNkV1VzSUc5bVpuTmxkQ3dnYm05QmMzTmxjblFwSUh0Y2JpQWdkbUZzZFdVZ1BTQXJkbUZzZFdWY2JpQWdiMlptYzJWMElEMGdiMlptYzJWMElId2dNRnh1SUNCcFppQW9JVzV2UVhOelpYSjBLU0JqYUdWamEwbHVkQ2gwYUdsekxDQjJZV3gxWlN3Z2IyWm1jMlYwTENBeExDQXdlR1ptTENBd0tWeHVJQ0JwWmlBb0lVSjFabVpsY2k1VVdWQkZSRjlCVWxKQldWOVRWVkJRVDFKVUtTQjJZV3gxWlNBOUlFMWhkR2d1Wm14dmIzSW9kbUZzZFdVcFhHNGdJSFJvYVhOYmIyWm1jMlYwWFNBOUlDaDJZV3gxWlNBbUlEQjRabVlwWEc0Z0lISmxkSFZ5YmlCdlptWnpaWFFnS3lBeFhHNTlYRzVjYm1aMWJtTjBhVzl1SUc5aWFtVmpkRmR5YVhSbFZVbHVkREUySUNoaWRXWXNJSFpoYkhWbExDQnZabVp6WlhRc0lHeHBkSFJzWlVWdVpHbGhiaWtnZTF4dUlDQnBaaUFvZG1Gc2RXVWdQQ0F3S1NCMllXeDFaU0E5SURCNFptWm1aaUFySUhaaGJIVmxJQ3NnTVZ4dUlDQm1iM0lnS0haaGNpQnBJRDBnTUN3Z2FpQTlJRTFoZEdndWJXbHVLR0oxWmk1c1pXNW5kR2dnTFNCdlptWnpaWFFzSURJcE95QnBJRHdnYWpzZ2FTc3JLU0I3WEc0Z0lDQWdZblZtVzI5bVpuTmxkQ0FySUdsZElEMGdLSFpoYkhWbElDWWdLREI0Wm1ZZ1BEd2dLRGdnS2lBb2JHbDBkR3hsUlc1a2FXRnVJRDhnYVNBNklERWdMU0JwS1NrcEtTQStQajVjYmlBZ0lDQWdJQ2hzYVhSMGJHVkZibVJwWVc0Z1B5QnBJRG9nTVNBdElHa3BJQ29nT0Z4dUlDQjlYRzU5WEc1Y2JrSjFabVpsY2k1d2NtOTBiM1I1Y0dVdWQzSnBkR1ZWU1c1ME1UWk1SU0E5SUdaMWJtTjBhVzl1SUhkeWFYUmxWVWx1ZERFMlRFVWdLSFpoYkhWbExDQnZabVp6WlhRc0lHNXZRWE56WlhKMEtTQjdYRzRnSUhaaGJIVmxJRDBnSzNaaGJIVmxYRzRnSUc5bVpuTmxkQ0E5SUc5bVpuTmxkQ0I4SURCY2JpQWdhV1lnS0NGdWIwRnpjMlZ5ZENrZ1kyaGxZMnRKYm5Rb2RHaHBjeXdnZG1Gc2RXVXNJRzltWm5ObGRDd2dNaXdnTUhobVptWm1MQ0F3S1Z4dUlDQnBaaUFvUW5WbVptVnlMbFJaVUVWRVgwRlNVa0ZaWDFOVlVGQlBVbFFwSUh0Y2JpQWdJQ0IwYUdselcyOW1abk5sZEYwZ1BTQW9kbUZzZFdVZ0ppQXdlR1ptS1Z4dUlDQWdJSFJvYVhOYmIyWm1jMlYwSUNzZ01WMGdQU0FvZG1Gc2RXVWdQajQrSURncFhHNGdJSDBnWld4elpTQjdYRzRnSUNBZ2IySnFaV04wVjNKcGRHVlZTVzUwTVRZb2RHaHBjeXdnZG1Gc2RXVXNJRzltWm5ObGRDd2dkSEoxWlNsY2JpQWdmVnh1SUNCeVpYUjFjbTRnYjJabWMyVjBJQ3NnTWx4dWZWeHVYRzVDZFdabVpYSXVjSEp2ZEc5MGVYQmxMbmR5YVhSbFZVbHVkREUyUWtVZ1BTQm1kVzVqZEdsdmJpQjNjbWwwWlZWSmJuUXhOa0pGSUNoMllXeDFaU3dnYjJabWMyVjBMQ0J1YjBGemMyVnlkQ2tnZTF4dUlDQjJZV3gxWlNBOUlDdDJZV3gxWlZ4dUlDQnZabVp6WlhRZ1BTQnZabVp6WlhRZ2ZDQXdYRzRnSUdsbUlDZ2hibTlCYzNObGNuUXBJR05vWldOclNXNTBLSFJvYVhNc0lIWmhiSFZsTENCdlptWnpaWFFzSURJc0lEQjRabVptWml3Z01DbGNiaUFnYVdZZ0tFSjFabVpsY2k1VVdWQkZSRjlCVWxKQldWOVRWVkJRVDFKVUtTQjdYRzRnSUNBZ2RHaHBjMXR2Wm1aelpYUmRJRDBnS0haaGJIVmxJRDQrUGlBNEtWeHVJQ0FnSUhSb2FYTmJiMlptYzJWMElDc2dNVjBnUFNBb2RtRnNkV1VnSmlBd2VHWm1LVnh1SUNCOUlHVnNjMlVnZTF4dUlDQWdJRzlpYW1WamRGZHlhWFJsVlVsdWRERTJLSFJvYVhNc0lIWmhiSFZsTENCdlptWnpaWFFzSUdaaGJITmxLVnh1SUNCOVhHNGdJSEpsZEhWeWJpQnZabVp6WlhRZ0t5QXlYRzU5WEc1Y2JtWjFibU4wYVc5dUlHOWlhbVZqZEZkeWFYUmxWVWx1ZERNeUlDaGlkV1lzSUhaaGJIVmxMQ0J2Wm1aelpYUXNJR3hwZEhSc1pVVnVaR2xoYmlrZ2UxeHVJQ0JwWmlBb2RtRnNkV1VnUENBd0tTQjJZV3gxWlNBOUlEQjRabVptWm1abVptWWdLeUIyWVd4MVpTQXJJREZjYmlBZ1ptOXlJQ2gyWVhJZ2FTQTlJREFzSUdvZ1BTQk5ZWFJvTG0xcGJpaGlkV1l1YkdWdVozUm9JQzBnYjJabWMyVjBMQ0EwS1RzZ2FTQThJR283SUdrckt5a2dlMXh1SUNBZ0lHSjFabHR2Wm1aelpYUWdLeUJwWFNBOUlDaDJZV3gxWlNBK1BqNGdLR3hwZEhSc1pVVnVaR2xoYmlBL0lHa2dPaUF6SUMwZ2FTa2dLaUE0S1NBbUlEQjRabVpjYmlBZ2ZWeHVmVnh1WEc1Q2RXWm1aWEl1Y0hKdmRHOTBlWEJsTG5keWFYUmxWVWx1ZERNeVRFVWdQU0JtZFc1amRHbHZiaUIzY21sMFpWVkpiblF6TWt4RklDaDJZV3gxWlN3Z2IyWm1jMlYwTENCdWIwRnpjMlZ5ZENrZ2UxeHVJQ0IyWVd4MVpTQTlJQ3QyWVd4MVpWeHVJQ0J2Wm1aelpYUWdQU0J2Wm1aelpYUWdmQ0F3WEc0Z0lHbG1JQ2doYm05QmMzTmxjblFwSUdOb1pXTnJTVzUwS0hSb2FYTXNJSFpoYkhWbExDQnZabVp6WlhRc0lEUXNJREI0Wm1abVptWm1abVlzSURBcFhHNGdJR2xtSUNoQ2RXWm1aWEl1VkZsUVJVUmZRVkpTUVZsZlUxVlFVRTlTVkNrZ2UxeHVJQ0FnSUhSb2FYTmJiMlptYzJWMElDc2dNMTBnUFNBb2RtRnNkV1VnUGo0K0lESTBLVnh1SUNBZ0lIUm9hWE5iYjJabWMyVjBJQ3NnTWwwZ1BTQW9kbUZzZFdVZ1BqNCtJREUyS1Z4dUlDQWdJSFJvYVhOYmIyWm1jMlYwSUNzZ01WMGdQU0FvZG1Gc2RXVWdQajQrSURncFhHNGdJQ0FnZEdocGMxdHZabVp6WlhSZElEMGdLSFpoYkhWbElDWWdNSGhtWmlsY2JpQWdmU0JsYkhObElIdGNiaUFnSUNCdlltcGxZM1JYY21sMFpWVkpiblF6TWloMGFHbHpMQ0IyWVd4MVpTd2diMlptYzJWMExDQjBjblZsS1Z4dUlDQjlYRzRnSUhKbGRIVnliaUJ2Wm1aelpYUWdLeUEwWEc1OVhHNWNia0oxWm1abGNpNXdjbTkwYjNSNWNHVXVkM0pwZEdWVlNXNTBNekpDUlNBOUlHWjFibU4wYVc5dUlIZHlhWFJsVlVsdWRETXlRa1VnS0haaGJIVmxMQ0J2Wm1aelpYUXNJRzV2UVhOelpYSjBLU0I3WEc0Z0lIWmhiSFZsSUQwZ0szWmhiSFZsWEc0Z0lHOW1abk5sZENBOUlHOW1abk5sZENCOElEQmNiaUFnYVdZZ0tDRnViMEZ6YzJWeWRDa2dZMmhsWTJ0SmJuUW9kR2hwY3l3Z2RtRnNkV1VzSUc5bVpuTmxkQ3dnTkN3Z01IaG1abVptWm1abVppd2dNQ2xjYmlBZ2FXWWdLRUoxWm1abGNpNVVXVkJGUkY5QlVsSkJXVjlUVlZCUVQxSlVLU0I3WEc0Z0lDQWdkR2hwYzF0dlptWnpaWFJkSUQwZ0tIWmhiSFZsSUQ0K1BpQXlOQ2xjYmlBZ0lDQjBhR2x6VzI5bVpuTmxkQ0FySURGZElEMGdLSFpoYkhWbElENCtQaUF4TmlsY2JpQWdJQ0IwYUdselcyOW1abk5sZENBcklESmRJRDBnS0haaGJIVmxJRDQrUGlBNEtWeHVJQ0FnSUhSb2FYTmJiMlptYzJWMElDc2dNMTBnUFNBb2RtRnNkV1VnSmlBd2VHWm1LVnh1SUNCOUlHVnNjMlVnZTF4dUlDQWdJRzlpYW1WamRGZHlhWFJsVlVsdWRETXlLSFJvYVhNc0lIWmhiSFZsTENCdlptWnpaWFFzSUdaaGJITmxLVnh1SUNCOVhHNGdJSEpsZEhWeWJpQnZabVp6WlhRZ0t5QTBYRzU5WEc1Y2JrSjFabVpsY2k1d2NtOTBiM1I1Y0dVdWQzSnBkR1ZKYm5STVJTQTlJR1oxYm1OMGFXOXVJSGR5YVhSbFNXNTBURVVnS0haaGJIVmxMQ0J2Wm1aelpYUXNJR0o1ZEdWTVpXNW5kR2dzSUc1dlFYTnpaWEowS1NCN1hHNGdJSFpoYkhWbElEMGdLM1poYkhWbFhHNGdJRzltWm5ObGRDQTlJRzltWm5ObGRDQjhJREJjYmlBZ2FXWWdLQ0Z1YjBGemMyVnlkQ2tnZTF4dUlDQWdJSFpoY2lCc2FXMXBkQ0E5SUUxaGRHZ3VjRzkzS0RJc0lEZ2dLaUJpZVhSbFRHVnVaM1JvSUMwZ01TbGNibHh1SUNBZ0lHTm9aV05yU1c1MEtIUm9hWE1zSUhaaGJIVmxMQ0J2Wm1aelpYUXNJR0o1ZEdWTVpXNW5kR2dzSUd4cGJXbDBJQzBnTVN3Z0xXeHBiV2wwS1Z4dUlDQjlYRzVjYmlBZ2RtRnlJR2tnUFNBd1hHNGdJSFpoY2lCdGRXd2dQU0F4WEc0Z0lIWmhjaUJ6ZFdJZ1BTQjJZV3gxWlNBOElEQWdQeUF4SURvZ01GeHVJQ0IwYUdselcyOW1abk5sZEYwZ1BTQjJZV3gxWlNBbUlEQjRSa1pjYmlBZ2QyaHBiR1VnS0NzcmFTQThJR0o1ZEdWTVpXNW5kR2dnSmlZZ0tHMTFiQ0FxUFNBd2VERXdNQ2twSUh0Y2JpQWdJQ0IwYUdselcyOW1abk5sZENBcklHbGRJRDBnS0NoMllXeDFaU0F2SUcxMWJDa2dQajRnTUNrZ0xTQnpkV0lnSmlBd2VFWkdYRzRnSUgxY2JseHVJQ0J5WlhSMWNtNGdiMlptYzJWMElDc2dZbmwwWlV4bGJtZDBhRnh1ZlZ4dVhHNUNkV1ptWlhJdWNISnZkRzkwZVhCbExuZHlhWFJsU1c1MFFrVWdQU0JtZFc1amRHbHZiaUIzY21sMFpVbHVkRUpGSUNoMllXeDFaU3dnYjJabWMyVjBMQ0JpZVhSbFRHVnVaM1JvTENCdWIwRnpjMlZ5ZENrZ2UxeHVJQ0IyWVd4MVpTQTlJQ3QyWVd4MVpWeHVJQ0J2Wm1aelpYUWdQU0J2Wm1aelpYUWdmQ0F3WEc0Z0lHbG1JQ2doYm05QmMzTmxjblFwSUh0Y2JpQWdJQ0IyWVhJZ2JHbHRhWFFnUFNCTllYUm9MbkJ2ZHlneUxDQTRJQ29nWW5sMFpVeGxibWQwYUNBdElERXBYRzVjYmlBZ0lDQmphR1ZqYTBsdWRDaDBhR2x6TENCMllXeDFaU3dnYjJabWMyVjBMQ0JpZVhSbFRHVnVaM1JvTENCc2FXMXBkQ0F0SURFc0lDMXNhVzFwZENsY2JpQWdmVnh1WEc0Z0lIWmhjaUJwSUQwZ1lubDBaVXhsYm1kMGFDQXRJREZjYmlBZ2RtRnlJRzExYkNBOUlERmNiaUFnZG1GeUlITjFZaUE5SUhaaGJIVmxJRHdnTUNBL0lERWdPaUF3WEc0Z0lIUm9hWE5iYjJabWMyVjBJQ3NnYVYwZ1BTQjJZV3gxWlNBbUlEQjRSa1pjYmlBZ2QyaHBiR1VnS0MwdGFTQStQU0F3SUNZbUlDaHRkV3dnS2owZ01IZ3hNREFwS1NCN1hHNGdJQ0FnZEdocGMxdHZabVp6WlhRZ0t5QnBYU0E5SUNnb2RtRnNkV1VnTHlCdGRXd3BJRDQrSURBcElDMGdjM1ZpSUNZZ01IaEdSbHh1SUNCOVhHNWNiaUFnY21WMGRYSnVJRzltWm5ObGRDQXJJR0o1ZEdWTVpXNW5kR2hjYm4xY2JseHVRblZtWm1WeUxuQnliM1J2ZEhsd1pTNTNjbWwwWlVsdWREZ2dQU0JtZFc1amRHbHZiaUIzY21sMFpVbHVkRGdnS0haaGJIVmxMQ0J2Wm1aelpYUXNJRzV2UVhOelpYSjBLU0I3WEc0Z0lIWmhiSFZsSUQwZ0szWmhiSFZsWEc0Z0lHOW1abk5sZENBOUlHOW1abk5sZENCOElEQmNiaUFnYVdZZ0tDRnViMEZ6YzJWeWRDa2dZMmhsWTJ0SmJuUW9kR2hwY3l3Z2RtRnNkV1VzSUc5bVpuTmxkQ3dnTVN3Z01IZzNaaXdnTFRCNE9EQXBYRzRnSUdsbUlDZ2hRblZtWm1WeUxsUlpVRVZFWDBGU1VrRlpYMU5WVUZCUFVsUXBJSFpoYkhWbElEMGdUV0YwYUM1bWJHOXZjaWgyWVd4MVpTbGNiaUFnYVdZZ0tIWmhiSFZsSUR3Z01Da2dkbUZzZFdVZ1BTQXdlR1ptSUNzZ2RtRnNkV1VnS3lBeFhHNGdJSFJvYVhOYmIyWm1jMlYwWFNBOUlDaDJZV3gxWlNBbUlEQjRabVlwWEc0Z0lISmxkSFZ5YmlCdlptWnpaWFFnS3lBeFhHNTlYRzVjYmtKMVptWmxjaTV3Y205MGIzUjVjR1V1ZDNKcGRHVkpiblF4Tmt4RklEMGdablZ1WTNScGIyNGdkM0pwZEdWSmJuUXhOa3hGSUNoMllXeDFaU3dnYjJabWMyVjBMQ0J1YjBGemMyVnlkQ2tnZTF4dUlDQjJZV3gxWlNBOUlDdDJZV3gxWlZ4dUlDQnZabVp6WlhRZ1BTQnZabVp6WlhRZ2ZDQXdYRzRnSUdsbUlDZ2hibTlCYzNObGNuUXBJR05vWldOclNXNTBLSFJvYVhNc0lIWmhiSFZsTENCdlptWnpaWFFzSURJc0lEQjROMlptWml3Z0xUQjRPREF3TUNsY2JpQWdhV1lnS0VKMVptWmxjaTVVV1ZCRlJGOUJVbEpCV1Y5VFZWQlFUMUpVS1NCN1hHNGdJQ0FnZEdocGMxdHZabVp6WlhSZElEMGdLSFpoYkhWbElDWWdNSGhtWmlsY2JpQWdJQ0IwYUdselcyOW1abk5sZENBcklERmRJRDBnS0haaGJIVmxJRDQrUGlBNEtWeHVJQ0I5SUdWc2MyVWdlMXh1SUNBZ0lHOWlhbVZqZEZkeWFYUmxWVWx1ZERFMktIUm9hWE1zSUhaaGJIVmxMQ0J2Wm1aelpYUXNJSFJ5ZFdVcFhHNGdJSDFjYmlBZ2NtVjBkWEp1SUc5bVpuTmxkQ0FySURKY2JuMWNibHh1UW5WbVptVnlMbkJ5YjNSdmRIbHdaUzUzY21sMFpVbHVkREUyUWtVZ1BTQm1kVzVqZEdsdmJpQjNjbWwwWlVsdWRERTJRa1VnS0haaGJIVmxMQ0J2Wm1aelpYUXNJRzV2UVhOelpYSjBLU0I3WEc0Z0lIWmhiSFZsSUQwZ0szWmhiSFZsWEc0Z0lHOW1abk5sZENBOUlHOW1abk5sZENCOElEQmNiaUFnYVdZZ0tDRnViMEZ6YzJWeWRDa2dZMmhsWTJ0SmJuUW9kR2hwY3l3Z2RtRnNkV1VzSUc5bVpuTmxkQ3dnTWl3Z01IZzNabVptTENBdE1IZzRNREF3S1Z4dUlDQnBaaUFvUW5WbVptVnlMbFJaVUVWRVgwRlNVa0ZaWDFOVlVGQlBVbFFwSUh0Y2JpQWdJQ0IwYUdselcyOW1abk5sZEYwZ1BTQW9kbUZzZFdVZ1BqNCtJRGdwWEc0Z0lDQWdkR2hwYzF0dlptWnpaWFFnS3lBeFhTQTlJQ2gyWVd4MVpTQW1JREI0Wm1ZcFhHNGdJSDBnWld4elpTQjdYRzRnSUNBZ2IySnFaV04wVjNKcGRHVlZTVzUwTVRZb2RHaHBjeXdnZG1Gc2RXVXNJRzltWm5ObGRDd2dabUZzYzJVcFhHNGdJSDFjYmlBZ2NtVjBkWEp1SUc5bVpuTmxkQ0FySURKY2JuMWNibHh1UW5WbVptVnlMbkJ5YjNSdmRIbHdaUzUzY21sMFpVbHVkRE15VEVVZ1BTQm1kVzVqZEdsdmJpQjNjbWwwWlVsdWRETXlURVVnS0haaGJIVmxMQ0J2Wm1aelpYUXNJRzV2UVhOelpYSjBLU0I3WEc0Z0lIWmhiSFZsSUQwZ0szWmhiSFZsWEc0Z0lHOW1abk5sZENBOUlHOW1abk5sZENCOElEQmNiaUFnYVdZZ0tDRnViMEZ6YzJWeWRDa2dZMmhsWTJ0SmJuUW9kR2hwY3l3Z2RtRnNkV1VzSUc5bVpuTmxkQ3dnTkN3Z01IZzNabVptWm1abVppd2dMVEI0T0RBd01EQXdNREFwWEc0Z0lHbG1JQ2hDZFdabVpYSXVWRmxRUlVSZlFWSlNRVmxmVTFWUVVFOVNWQ2tnZTF4dUlDQWdJSFJvYVhOYmIyWm1jMlYwWFNBOUlDaDJZV3gxWlNBbUlEQjRabVlwWEc0Z0lDQWdkR2hwYzF0dlptWnpaWFFnS3lBeFhTQTlJQ2gyWVd4MVpTQStQajRnT0NsY2JpQWdJQ0IwYUdselcyOW1abk5sZENBcklESmRJRDBnS0haaGJIVmxJRDQrUGlBeE5pbGNiaUFnSUNCMGFHbHpXMjltWm5ObGRDQXJJRE5kSUQwZ0tIWmhiSFZsSUQ0K1BpQXlOQ2xjYmlBZ2ZTQmxiSE5sSUh0Y2JpQWdJQ0J2WW1wbFkzUlhjbWwwWlZWSmJuUXpNaWgwYUdsekxDQjJZV3gxWlN3Z2IyWm1jMlYwTENCMGNuVmxLVnh1SUNCOVhHNGdJSEpsZEhWeWJpQnZabVp6WlhRZ0t5QTBYRzU5WEc1Y2JrSjFabVpsY2k1d2NtOTBiM1I1Y0dVdWQzSnBkR1ZKYm5Rek1rSkZJRDBnWm5WdVkzUnBiMjRnZDNKcGRHVkpiblF6TWtKRklDaDJZV3gxWlN3Z2IyWm1jMlYwTENCdWIwRnpjMlZ5ZENrZ2UxeHVJQ0IyWVd4MVpTQTlJQ3QyWVd4MVpWeHVJQ0J2Wm1aelpYUWdQU0J2Wm1aelpYUWdmQ0F3WEc0Z0lHbG1JQ2doYm05QmMzTmxjblFwSUdOb1pXTnJTVzUwS0hSb2FYTXNJSFpoYkhWbExDQnZabVp6WlhRc0lEUXNJREI0TjJabVptWm1abVlzSUMwd2VEZ3dNREF3TURBd0tWeHVJQ0JwWmlBb2RtRnNkV1VnUENBd0tTQjJZV3gxWlNBOUlEQjRabVptWm1abVptWWdLeUIyWVd4MVpTQXJJREZjYmlBZ2FXWWdLRUoxWm1abGNpNVVXVkJGUkY5QlVsSkJXVjlUVlZCUVQxSlVLU0I3WEc0Z0lDQWdkR2hwYzF0dlptWnpaWFJkSUQwZ0tIWmhiSFZsSUQ0K1BpQXlOQ2xjYmlBZ0lDQjBhR2x6VzI5bVpuTmxkQ0FySURGZElEMGdLSFpoYkhWbElENCtQaUF4TmlsY2JpQWdJQ0IwYUdselcyOW1abk5sZENBcklESmRJRDBnS0haaGJIVmxJRDQrUGlBNEtWeHVJQ0FnSUhSb2FYTmJiMlptYzJWMElDc2dNMTBnUFNBb2RtRnNkV1VnSmlBd2VHWm1LVnh1SUNCOUlHVnNjMlVnZTF4dUlDQWdJRzlpYW1WamRGZHlhWFJsVlVsdWRETXlLSFJvYVhNc0lIWmhiSFZsTENCdlptWnpaWFFzSUdaaGJITmxLVnh1SUNCOVhHNGdJSEpsZEhWeWJpQnZabVp6WlhRZ0t5QTBYRzU5WEc1Y2JtWjFibU4wYVc5dUlHTm9aV05yU1VWRlJUYzFOQ0FvWW5WbUxDQjJZV3gxWlN3Z2IyWm1jMlYwTENCbGVIUXNJRzFoZUN3Z2JXbHVLU0I3WEc0Z0lHbG1JQ2gyWVd4MVpTQStJRzFoZUNCOGZDQjJZV3gxWlNBOElHMXBiaWtnZEdoeWIzY2dibVYzSUZKaGJtZGxSWEp5YjNJb0ozWmhiSFZsSUdseklHOTFkQ0J2WmlCaWIzVnVaSE1uS1Z4dUlDQnBaaUFvYjJabWMyVjBJQ3NnWlhoMElENGdZblZtTG14bGJtZDBhQ2tnZEdoeWIzY2dibVYzSUZKaGJtZGxSWEp5YjNJb0oybHVaR1Y0SUc5MWRDQnZaaUJ5WVc1blpTY3BYRzRnSUdsbUlDaHZabVp6WlhRZ1BDQXdLU0IwYUhKdmR5QnVaWGNnVW1GdVoyVkZjbkp2Y2lnbmFXNWtaWGdnYjNWMElHOW1JSEpoYm1kbEp5bGNibjFjYmx4dVpuVnVZM1JwYjI0Z2QzSnBkR1ZHYkc5aGRDQW9ZblZtTENCMllXeDFaU3dnYjJabWMyVjBMQ0JzYVhSMGJHVkZibVJwWVc0c0lHNXZRWE56WlhKMEtTQjdYRzRnSUdsbUlDZ2hibTlCYzNObGNuUXBJSHRjYmlBZ0lDQmphR1ZqYTBsRlJVVTNOVFFvWW5WbUxDQjJZV3gxWlN3Z2IyWm1jMlYwTENBMExDQXpMalF3TWpneU16UTJOak00TlRJNE9EWmxLek00TENBdE15NDBNREk0TWpNME5qWXpPRFV5T0RnMlpTc3pPQ2xjYmlBZ2ZWeHVJQ0JwWldWbE56VTBMbmR5YVhSbEtHSjFaaXdnZG1Gc2RXVXNJRzltWm5ObGRDd2diR2wwZEd4bFJXNWthV0Z1TENBeU15d2dOQ2xjYmlBZ2NtVjBkWEp1SUc5bVpuTmxkQ0FySURSY2JuMWNibHh1UW5WbVptVnlMbkJ5YjNSdmRIbHdaUzUzY21sMFpVWnNiMkYwVEVVZ1BTQm1kVzVqZEdsdmJpQjNjbWwwWlVac2IyRjBURVVnS0haaGJIVmxMQ0J2Wm1aelpYUXNJRzV2UVhOelpYSjBLU0I3WEc0Z0lISmxkSFZ5YmlCM2NtbDBaVVpzYjJGMEtIUm9hWE1zSUhaaGJIVmxMQ0J2Wm1aelpYUXNJSFJ5ZFdVc0lHNXZRWE56WlhKMEtWeHVmVnh1WEc1Q2RXWm1aWEl1Y0hKdmRHOTBlWEJsTG5keWFYUmxSbXh2WVhSQ1JTQTlJR1oxYm1OMGFXOXVJSGR5YVhSbFJteHZZWFJDUlNBb2RtRnNkV1VzSUc5bVpuTmxkQ3dnYm05QmMzTmxjblFwSUh0Y2JpQWdjbVYwZFhKdUlIZHlhWFJsUm14dllYUW9kR2hwY3l3Z2RtRnNkV1VzSUc5bVpuTmxkQ3dnWm1Gc2MyVXNJRzV2UVhOelpYSjBLVnh1ZlZ4dVhHNW1kVzVqZEdsdmJpQjNjbWwwWlVSdmRXSnNaU0FvWW5WbUxDQjJZV3gxWlN3Z2IyWm1jMlYwTENCc2FYUjBiR1ZGYm1ScFlXNHNJRzV2UVhOelpYSjBLU0I3WEc0Z0lHbG1JQ2doYm05QmMzTmxjblFwSUh0Y2JpQWdJQ0JqYUdWamEwbEZSVVUzTlRRb1luVm1MQ0IyWVd4MVpTd2diMlptYzJWMExDQTRMQ0F4TGpjNU56WTVNekV6TkRnMk1qTXhOVGRGS3pNd09Dd2dMVEV1TnprM05qa3pNVE0wT0RZeU16RTFOMFVyTXpBNEtWeHVJQ0I5WEc0Z0lHbGxaV1UzTlRRdWQzSnBkR1VvWW5WbUxDQjJZV3gxWlN3Z2IyWm1jMlYwTENCc2FYUjBiR1ZGYm1ScFlXNHNJRFV5TENBNEtWeHVJQ0J5WlhSMWNtNGdiMlptYzJWMElDc2dPRnh1ZlZ4dVhHNUNkV1ptWlhJdWNISnZkRzkwZVhCbExuZHlhWFJsUkc5MVlteGxURVVnUFNCbWRXNWpkR2x2YmlCM2NtbDBaVVJ2ZFdKc1pVeEZJQ2gyWVd4MVpTd2diMlptYzJWMExDQnViMEZ6YzJWeWRDa2dlMXh1SUNCeVpYUjFjbTRnZDNKcGRHVkViM1ZpYkdVb2RHaHBjeXdnZG1Gc2RXVXNJRzltWm5ObGRDd2dkSEoxWlN3Z2JtOUJjM05sY25RcFhHNTlYRzVjYmtKMVptWmxjaTV3Y205MGIzUjVjR1V1ZDNKcGRHVkViM1ZpYkdWQ1JTQTlJR1oxYm1OMGFXOXVJSGR5YVhSbFJHOTFZbXhsUWtVZ0tIWmhiSFZsTENCdlptWnpaWFFzSUc1dlFYTnpaWEowS1NCN1hHNGdJSEpsZEhWeWJpQjNjbWwwWlVSdmRXSnNaU2gwYUdsekxDQjJZV3gxWlN3Z2IyWm1jMlYwTENCbVlXeHpaU3dnYm05QmMzTmxjblFwWEc1OVhHNWNiaTh2SUdOdmNIa29kR0Z5WjJWMFFuVm1abVZ5TENCMFlYSm5aWFJUZEdGeWREMHdMQ0J6YjNWeVkyVlRkR0Z5ZEQwd0xDQnpiM1Z5WTJWRmJtUTlZblZtWm1WeUxteGxibWQwYUNsY2JrSjFabVpsY2k1d2NtOTBiM1I1Y0dVdVkyOXdlU0E5SUdaMWJtTjBhVzl1SUdOdmNIa2dLSFJoY21kbGRDd2dkR0Z5WjJWMFUzUmhjblFzSUhOMFlYSjBMQ0JsYm1RcElIdGNiaUFnYVdZZ0tDRnpkR0Z5ZENrZ2MzUmhjblFnUFNBd1hHNGdJR2xtSUNnaFpXNWtJQ1ltSUdWdVpDQWhQVDBnTUNrZ1pXNWtJRDBnZEdocGN5NXNaVzVuZEdoY2JpQWdhV1lnS0hSaGNtZGxkRk4wWVhKMElENDlJSFJoY21kbGRDNXNaVzVuZEdncElIUmhjbWRsZEZOMFlYSjBJRDBnZEdGeVoyVjBMbXhsYm1kMGFGeHVJQ0JwWmlBb0lYUmhjbWRsZEZOMFlYSjBLU0IwWVhKblpYUlRkR0Z5ZENBOUlEQmNiaUFnYVdZZ0tHVnVaQ0ErSURBZ0ppWWdaVzVrSUR3Z2MzUmhjblFwSUdWdVpDQTlJSE4wWVhKMFhHNWNiaUFnTHk4Z1EyOXdlU0F3SUdKNWRHVnpPeUIzWlNkeVpTQmtiMjVsWEc0Z0lHbG1JQ2hsYm1RZ1BUMDlJSE4wWVhKMEtTQnlaWFIxY200Z01GeHVJQ0JwWmlBb2RHRnlaMlYwTG14bGJtZDBhQ0E5UFQwZ01DQjhmQ0IwYUdsekxteGxibWQwYUNBOVBUMGdNQ2tnY21WMGRYSnVJREJjYmx4dUlDQXZMeUJHWVhSaGJDQmxjbkp2Y2lCamIyNWthWFJwYjI1elhHNGdJR2xtSUNoMFlYSm5aWFJUZEdGeWRDQThJREFwSUh0Y2JpQWdJQ0IwYUhKdmR5QnVaWGNnVW1GdVoyVkZjbkp2Y2lnbmRHRnlaMlYwVTNSaGNuUWdiM1YwSUc5bUlHSnZkVzVrY3ljcFhHNGdJSDFjYmlBZ2FXWWdLSE4wWVhKMElEd2dNQ0I4ZkNCemRHRnlkQ0ErUFNCMGFHbHpMbXhsYm1kMGFDa2dkR2h5YjNjZ2JtVjNJRkpoYm1kbFJYSnliM0lvSjNOdmRYSmpaVk4wWVhKMElHOTFkQ0J2WmlCaWIzVnVaSE1uS1Z4dUlDQnBaaUFvWlc1a0lEd2dNQ2tnZEdoeWIzY2dibVYzSUZKaGJtZGxSWEp5YjNJb0ozTnZkWEpqWlVWdVpDQnZkWFFnYjJZZ1ltOTFibVJ6SnlsY2JseHVJQ0F2THlCQmNtVWdkMlVnYjI5aVAxeHVJQ0JwWmlBb1pXNWtJRDRnZEdocGN5NXNaVzVuZEdncElHVnVaQ0E5SUhSb2FYTXViR1Z1WjNSb1hHNGdJR2xtSUNoMFlYSm5aWFF1YkdWdVozUm9JQzBnZEdGeVoyVjBVM1JoY25RZ1BDQmxibVFnTFNCemRHRnlkQ2tnZTF4dUlDQWdJR1Z1WkNBOUlIUmhjbWRsZEM1c1pXNW5kR2dnTFNCMFlYSm5aWFJUZEdGeWRDQXJJSE4wWVhKMFhHNGdJSDFjYmx4dUlDQjJZWElnYkdWdUlEMGdaVzVrSUMwZ2MzUmhjblJjYmlBZ2RtRnlJR2xjYmx4dUlDQnBaaUFvZEdocGN5QTlQVDBnZEdGeVoyVjBJQ1ltSUhOMFlYSjBJRHdnZEdGeVoyVjBVM1JoY25RZ0ppWWdkR0Z5WjJWMFUzUmhjblFnUENCbGJtUXBJSHRjYmlBZ0lDQXZMeUJrWlhOalpXNWthVzVuSUdOdmNIa2dabkp2YlNCbGJtUmNiaUFnSUNCbWIzSWdLR2tnUFNCc1pXNGdMU0F4T3lCcElENDlJREE3SUdrdExTa2dlMXh1SUNBZ0lDQWdkR0Z5WjJWMFcya2dLeUIwWVhKblpYUlRkR0Z5ZEYwZ1BTQjBhR2x6VzJrZ0t5QnpkR0Z5ZEYxY2JpQWdJQ0I5WEc0Z0lIMGdaV3h6WlNCcFppQW9iR1Z1SUR3Z01UQXdNQ0I4ZkNBaFFuVm1abVZ5TGxSWlVFVkVYMEZTVWtGWlgxTlZVRkJQVWxRcElIdGNiaUFnSUNBdkx5QmhjMk5sYm1ScGJtY2dZMjl3ZVNCbWNtOXRJSE4wWVhKMFhHNGdJQ0FnWm05eUlDaHBJRDBnTURzZ2FTQThJR3hsYmpzZ2FTc3JLU0I3WEc0Z0lDQWdJQ0IwWVhKblpYUmJhU0FySUhSaGNtZGxkRk4wWVhKMFhTQTlJSFJvYVhOYmFTQXJJSE4wWVhKMFhWeHVJQ0FnSUgxY2JpQWdmU0JsYkhObElIdGNiaUFnSUNCMFlYSm5aWFF1WDNObGRDaDBhR2x6TG5OMVltRnljbUY1S0hOMFlYSjBMQ0J6ZEdGeWRDQXJJR3hsYmlrc0lIUmhjbWRsZEZOMFlYSjBLVnh1SUNCOVhHNWNiaUFnY21WMGRYSnVJR3hsYmx4dWZWeHVYRzR2THlCbWFXeHNLSFpoYkhWbExDQnpkR0Z5ZEQwd0xDQmxibVE5WW5WbVptVnlMbXhsYm1kMGFDbGNia0oxWm1abGNpNXdjbTkwYjNSNWNHVXVabWxzYkNBOUlHWjFibU4wYVc5dUlHWnBiR3dnS0haaGJIVmxMQ0J6ZEdGeWRDd2daVzVrS1NCN1hHNGdJR2xtSUNnaGRtRnNkV1VwSUhaaGJIVmxJRDBnTUZ4dUlDQnBaaUFvSVhOMFlYSjBLU0J6ZEdGeWRDQTlJREJjYmlBZ2FXWWdLQ0ZsYm1RcElHVnVaQ0E5SUhSb2FYTXViR1Z1WjNSb1hHNWNiaUFnYVdZZ0tHVnVaQ0E4SUhOMFlYSjBLU0IwYUhKdmR5QnVaWGNnVW1GdVoyVkZjbkp2Y2lnblpXNWtJRHdnYzNSaGNuUW5LVnh1WEc0Z0lDOHZJRVpwYkd3Z01DQmllWFJsY3pzZ2QyVW5jbVVnWkc5dVpWeHVJQ0JwWmlBb1pXNWtJRDA5UFNCemRHRnlkQ2tnY21WMGRYSnVYRzRnSUdsbUlDaDBhR2x6TG14bGJtZDBhQ0E5UFQwZ01Da2djbVYwZFhKdVhHNWNiaUFnYVdZZ0tITjBZWEowSUR3Z01DQjhmQ0J6ZEdGeWRDQStQU0IwYUdsekxteGxibWQwYUNrZ2RHaHliM2NnYm1WM0lGSmhibWRsUlhKeWIzSW9KM04wWVhKMElHOTFkQ0J2WmlCaWIzVnVaSE1uS1Z4dUlDQnBaaUFvWlc1a0lEd2dNQ0I4ZkNCbGJtUWdQaUIwYUdsekxteGxibWQwYUNrZ2RHaHliM2NnYm1WM0lGSmhibWRsUlhKeWIzSW9KMlZ1WkNCdmRYUWdiMllnWW05MWJtUnpKeWxjYmx4dUlDQjJZWElnYVZ4dUlDQnBaaUFvZEhsd1pXOW1JSFpoYkhWbElEMDlQU0FuYm5WdFltVnlKeWtnZTF4dUlDQWdJR1p2Y2lBb2FTQTlJSE4wWVhKME95QnBJRHdnWlc1a095QnBLeXNwSUh0Y2JpQWdJQ0FnSUhSb2FYTmJhVjBnUFNCMllXeDFaVnh1SUNBZ0lIMWNiaUFnZlNCbGJITmxJSHRjYmlBZ0lDQjJZWElnWW5sMFpYTWdQU0IxZEdZNFZHOUNlWFJsY3loMllXeDFaUzUwYjFOMGNtbHVaeWdwS1Z4dUlDQWdJSFpoY2lCc1pXNGdQU0JpZVhSbGN5NXNaVzVuZEdoY2JpQWdJQ0JtYjNJZ0tHa2dQU0J6ZEdGeWREc2dhU0E4SUdWdVpEc2dhU3NyS1NCN1hHNGdJQ0FnSUNCMGFHbHpXMmxkSUQwZ1lubDBaWE5iYVNBbElHeGxibDFjYmlBZ0lDQjlYRzRnSUgxY2JseHVJQ0J5WlhSMWNtNGdkR2hwYzF4dWZWeHVYRzR2S2lwY2JpQXFJRU55WldGMFpYTWdZU0J1WlhjZ1lFRnljbUY1UW5WbVptVnlZQ0IzYVhSb0lIUm9aU0FxWTI5d2FXVmtLaUJ0WlcxdmNua2diMllnZEdobElHSjFabVpsY2lCcGJuTjBZVzVqWlM1Y2JpQXFJRUZrWkdWa0lHbHVJRTV2WkdVZ01DNHhNaTRnVDI1c2VTQmhkbUZwYkdGaWJHVWdhVzRnWW5KdmQzTmxjbk1nZEdoaGRDQnpkWEJ3YjNKMElFRnljbUY1UW5WbVptVnlMbHh1SUNvdlhHNUNkV1ptWlhJdWNISnZkRzkwZVhCbExuUnZRWEp5WVhsQ2RXWm1aWElnUFNCbWRXNWpkR2x2YmlCMGIwRnljbUY1UW5WbVptVnlJQ2dwSUh0Y2JpQWdhV1lnS0hSNWNHVnZaaUJWYVc1ME9FRnljbUY1SUNFOVBTQW5kVzVrWldacGJtVmtKeWtnZTF4dUlDQWdJR2xtSUNoQ2RXWm1aWEl1VkZsUVJVUmZRVkpTUVZsZlUxVlFVRTlTVkNrZ2UxeHVJQ0FnSUNBZ2NtVjBkWEp1SUNodVpYY2dRblZtWm1WeUtIUm9hWE1wS1M1aWRXWm1aWEpjYmlBZ0lDQjlJR1ZzYzJVZ2UxeHVJQ0FnSUNBZ2RtRnlJR0oxWmlBOUlHNWxkeUJWYVc1ME9FRnljbUY1S0hSb2FYTXViR1Z1WjNSb0tWeHVJQ0FnSUNBZ1ptOXlJQ2gyWVhJZ2FTQTlJREFzSUd4bGJpQTlJR0oxWmk1c1pXNW5kR2c3SUdrZ1BDQnNaVzQ3SUdrZ0t6MGdNU2tnZTF4dUlDQWdJQ0FnSUNCaWRXWmJhVjBnUFNCMGFHbHpXMmxkWEc0Z0lDQWdJQ0I5WEc0Z0lDQWdJQ0J5WlhSMWNtNGdZblZtTG1KMVptWmxjbHh1SUNBZ0lIMWNiaUFnZlNCbGJITmxJSHRjYmlBZ0lDQjBhSEp2ZHlCdVpYY2dWSGx3WlVWeWNtOXlLQ2RDZFdabVpYSXVkRzlCY25KaGVVSjFabVpsY2lCdWIzUWdjM1Z3Y0c5eWRHVmtJR2x1SUhSb2FYTWdZbkp2ZDNObGNpY3BYRzRnSUgxY2JuMWNibHh1THk4Z1NFVk1VRVZTSUVaVlRrTlVTVTlPVTF4dUx5OGdQVDA5UFQwOVBUMDlQVDA5UFQwOVBWeHVYRzUyWVhJZ1FsQWdQU0JDZFdabVpYSXVjSEp2ZEc5MGVYQmxYRzVjYmk4cUtseHVJQ29nUVhWbmJXVnVkQ0JoSUZWcGJuUTRRWEp5WVhrZ0ttbHVjM1JoYm1ObEtpQW9ibTkwSUhSb1pTQlZhVzUwT0VGeWNtRjVJR05zWVhOeklTa2dkMmwwYUNCQ2RXWm1aWElnYldWMGFHOWtjMXh1SUNvdlhHNUNkV1ptWlhJdVgyRjFaMjFsYm5RZ1BTQm1kVzVqZEdsdmJpQmZZWFZuYldWdWRDQW9ZWEp5S1NCN1hHNGdJR0Z5Y2k1amIyNXpkSEoxWTNSdmNpQTlJRUoxWm1abGNseHVJQ0JoY25JdVgybHpRblZtWm1WeUlEMGdkSEoxWlZ4dVhHNGdJQzh2SUhOaGRtVWdjbVZtWlhKbGJtTmxJSFJ2SUc5eWFXZHBibUZzSUZWcGJuUTRRWEp5WVhrZ2MyVjBJRzFsZEdodlpDQmlaV1p2Y21VZ2IzWmxjbmR5YVhScGJtZGNiaUFnWVhKeUxsOXpaWFFnUFNCaGNuSXVjMlYwWEc1Y2JpQWdMeThnWkdWd2NtVmpZWFJsWkZ4dUlDQmhjbkl1WjJWMElEMGdRbEF1WjJWMFhHNGdJR0Z5Y2k1elpYUWdQU0JDVUM1elpYUmNibHh1SUNCaGNuSXVkM0pwZEdVZ1BTQkNVQzUzY21sMFpWeHVJQ0JoY25JdWRHOVRkSEpwYm1jZ1BTQkNVQzUwYjFOMGNtbHVaMXh1SUNCaGNuSXVkRzlNYjJOaGJHVlRkSEpwYm1jZ1BTQkNVQzUwYjFOMGNtbHVaMXh1SUNCaGNuSXVkRzlLVTA5T0lEMGdRbEF1ZEc5S1UwOU9YRzRnSUdGeWNpNWxjWFZoYkhNZ1BTQkNVQzVsY1hWaGJITmNiaUFnWVhKeUxtTnZiWEJoY21VZ1BTQkNVQzVqYjIxd1lYSmxYRzRnSUdGeWNpNXBibVJsZUU5bUlEMGdRbEF1YVc1a1pYaFBabHh1SUNCaGNuSXVZMjl3ZVNBOUlFSlFMbU52Y0hsY2JpQWdZWEp5TG5Oc2FXTmxJRDBnUWxBdWMyeHBZMlZjYmlBZ1lYSnlMbkpsWVdSVlNXNTBURVVnUFNCQ1VDNXlaV0ZrVlVsdWRFeEZYRzRnSUdGeWNpNXlaV0ZrVlVsdWRFSkZJRDBnUWxBdWNtVmhaRlZKYm5SQ1JWeHVJQ0JoY25JdWNtVmhaRlZKYm5RNElEMGdRbEF1Y21WaFpGVkpiblE0WEc0Z0lHRnljaTV5WldGa1ZVbHVkREUyVEVVZ1BTQkNVQzV5WldGa1ZVbHVkREUyVEVWY2JpQWdZWEp5TG5KbFlXUlZTVzUwTVRaQ1JTQTlJRUpRTG5KbFlXUlZTVzUwTVRaQ1JWeHVJQ0JoY25JdWNtVmhaRlZKYm5Rek1reEZJRDBnUWxBdWNtVmhaRlZKYm5Rek1reEZYRzRnSUdGeWNpNXlaV0ZrVlVsdWRETXlRa1VnUFNCQ1VDNXlaV0ZrVlVsdWRETXlRa1ZjYmlBZ1lYSnlMbkpsWVdSSmJuUk1SU0E5SUVKUUxuSmxZV1JKYm5STVJWeHVJQ0JoY25JdWNtVmhaRWx1ZEVKRklEMGdRbEF1Y21WaFpFbHVkRUpGWEc0Z0lHRnljaTV5WldGa1NXNTBPQ0E5SUVKUUxuSmxZV1JKYm5RNFhHNGdJR0Z5Y2k1eVpXRmtTVzUwTVRaTVJTQTlJRUpRTG5KbFlXUkpiblF4Tmt4RlhHNGdJR0Z5Y2k1eVpXRmtTVzUwTVRaQ1JTQTlJRUpRTG5KbFlXUkpiblF4TmtKRlhHNGdJR0Z5Y2k1eVpXRmtTVzUwTXpKTVJTQTlJRUpRTG5KbFlXUkpiblF6TWt4RlhHNGdJR0Z5Y2k1eVpXRmtTVzUwTXpKQ1JTQTlJRUpRTG5KbFlXUkpiblF6TWtKRlhHNGdJR0Z5Y2k1eVpXRmtSbXh2WVhSTVJTQTlJRUpRTG5KbFlXUkdiRzloZEV4RlhHNGdJR0Z5Y2k1eVpXRmtSbXh2WVhSQ1JTQTlJRUpRTG5KbFlXUkdiRzloZEVKRlhHNGdJR0Z5Y2k1eVpXRmtSRzkxWW14bFRFVWdQU0JDVUM1eVpXRmtSRzkxWW14bFRFVmNiaUFnWVhKeUxuSmxZV1JFYjNWaWJHVkNSU0E5SUVKUUxuSmxZV1JFYjNWaWJHVkNSVnh1SUNCaGNuSXVkM0pwZEdWVlNXNTBPQ0E5SUVKUUxuZHlhWFJsVlVsdWREaGNiaUFnWVhKeUxuZHlhWFJsVlVsdWRFeEZJRDBnUWxBdWQzSnBkR1ZWU1c1MFRFVmNiaUFnWVhKeUxuZHlhWFJsVlVsdWRFSkZJRDBnUWxBdWQzSnBkR1ZWU1c1MFFrVmNiaUFnWVhKeUxuZHlhWFJsVlVsdWRERTJURVVnUFNCQ1VDNTNjbWwwWlZWSmJuUXhOa3hGWEc0Z0lHRnljaTUzY21sMFpWVkpiblF4TmtKRklEMGdRbEF1ZDNKcGRHVlZTVzUwTVRaQ1JWeHVJQ0JoY25JdWQzSnBkR1ZWU1c1ME16Sk1SU0E5SUVKUUxuZHlhWFJsVlVsdWRETXlURVZjYmlBZ1lYSnlMbmR5YVhSbFZVbHVkRE15UWtVZ1BTQkNVQzUzY21sMFpWVkpiblF6TWtKRlhHNGdJR0Z5Y2k1M2NtbDBaVWx1ZEV4RklEMGdRbEF1ZDNKcGRHVkpiblJNUlZ4dUlDQmhjbkl1ZDNKcGRHVkpiblJDUlNBOUlFSlFMbmR5YVhSbFNXNTBRa1ZjYmlBZ1lYSnlMbmR5YVhSbFNXNTBPQ0E5SUVKUUxuZHlhWFJsU1c1ME9GeHVJQ0JoY25JdWQzSnBkR1ZKYm5ReE5reEZJRDBnUWxBdWQzSnBkR1ZKYm5ReE5reEZYRzRnSUdGeWNpNTNjbWwwWlVsdWRERTJRa1VnUFNCQ1VDNTNjbWwwWlVsdWRERTJRa1ZjYmlBZ1lYSnlMbmR5YVhSbFNXNTBNekpNUlNBOUlFSlFMbmR5YVhSbFNXNTBNekpNUlZ4dUlDQmhjbkl1ZDNKcGRHVkpiblF6TWtKRklEMGdRbEF1ZDNKcGRHVkpiblF6TWtKRlhHNGdJR0Z5Y2k1M2NtbDBaVVpzYjJGMFRFVWdQU0JDVUM1M2NtbDBaVVpzYjJGMFRFVmNiaUFnWVhKeUxuZHlhWFJsUm14dllYUkNSU0E5SUVKUUxuZHlhWFJsUm14dllYUkNSVnh1SUNCaGNuSXVkM0pwZEdWRWIzVmliR1ZNUlNBOUlFSlFMbmR5YVhSbFJHOTFZbXhsVEVWY2JpQWdZWEp5TG5keWFYUmxSRzkxWW14bFFrVWdQU0JDVUM1M2NtbDBaVVJ2ZFdKc1pVSkZYRzRnSUdGeWNpNW1hV3hzSUQwZ1FsQXVabWxzYkZ4dUlDQmhjbkl1YVc1emNHVmpkQ0E5SUVKUUxtbHVjM0JsWTNSY2JpQWdZWEp5TG5SdlFYSnlZWGxDZFdabVpYSWdQU0JDVUM1MGIwRnljbUY1UW5WbVptVnlYRzVjYmlBZ2NtVjBkWEp1SUdGeWNseHVmVnh1WEc1MllYSWdTVTVXUVV4SlJGOUNRVk5GTmpSZlVrVWdQU0F2VzE0clhGd3ZNQzA1UVMxYVlTMTZMVjlkTDJkY2JseHVablZ1WTNScGIyNGdZbUZ6WlRZMFkyeGxZVzRnS0hOMGNpa2dlMXh1SUNBdkx5Qk9iMlJsSUhOMGNtbHdjeUJ2ZFhRZ2FXNTJZV3hwWkNCamFHRnlZV04wWlhKeklHeHBhMlVnWEZ4dUlHRnVaQ0JjWEhRZ1puSnZiU0IwYUdVZ2MzUnlhVzVuTENCaVlYTmxOalF0YW5NZ1pHOWxjeUJ1YjNSY2JpQWdjM1J5SUQwZ2MzUnlhVzVuZEhKcGJTaHpkSElwTG5KbGNHeGhZMlVvU1U1V1FVeEpSRjlDUVZORk5qUmZVa1VzSUNjbktWeHVJQ0F2THlCT2IyUmxJR052Ym5abGNuUnpJSE4wY21sdVozTWdkMmwwYUNCc1pXNW5kR2dnUENBeUlIUnZJQ2NuWEc0Z0lHbG1JQ2h6ZEhJdWJHVnVaM1JvSUR3Z01pa2djbVYwZFhKdUlDY25YRzRnSUM4dklFNXZaR1VnWVd4c2IzZHpJR1p2Y2lCdWIyNHRjR0ZrWkdWa0lHSmhjMlUyTkNCemRISnBibWR6SUNodGFYTnphVzVuSUhSeVlXbHNhVzVuSUQwOVBTa3NJR0poYzJVMk5DMXFjeUJrYjJWeklHNXZkRnh1SUNCM2FHbHNaU0FvYzNSeUxteGxibWQwYUNBbElEUWdJVDA5SURBcElIdGNiaUFnSUNCemRISWdQU0J6ZEhJZ0t5QW5QU2RjYmlBZ2ZWeHVJQ0J5WlhSMWNtNGdjM1J5WEc1OVhHNWNibVoxYm1OMGFXOXVJSE4wY21sdVozUnlhVzBnS0hOMGNpa2dlMXh1SUNCcFppQW9jM1J5TG5SeWFXMHBJSEpsZEhWeWJpQnpkSEl1ZEhKcGJTZ3BYRzRnSUhKbGRIVnliaUJ6ZEhJdWNtVndiR0ZqWlNndlhseGNjeXQ4WEZ4ekt5UXZaeXdnSnljcFhHNTlYRzVjYm1aMWJtTjBhVzl1SUhSdlNHVjRJQ2h1S1NCN1hHNGdJR2xtSUNodUlEd2dNVFlwSUhKbGRIVnliaUFuTUNjZ0t5QnVMblJ2VTNSeWFXNW5LREUyS1Z4dUlDQnlaWFIxY200Z2JpNTBiMU4wY21sdVp5Z3hOaWxjYm4xY2JseHVablZ1WTNScGIyNGdkWFJtT0ZSdlFubDBaWE1nS0hOMGNtbHVaeXdnZFc1cGRITXBJSHRjYmlBZ2RXNXBkSE1nUFNCMWJtbDBjeUI4ZkNCSmJtWnBibWwwZVZ4dUlDQjJZWElnWTI5a1pWQnZhVzUwWEc0Z0lIWmhjaUJzWlc1bmRHZ2dQU0J6ZEhKcGJtY3ViR1Z1WjNSb1hHNGdJSFpoY2lCc1pXRmtVM1Z5Y205bllYUmxJRDBnYm5Wc2JGeHVJQ0IyWVhJZ1lubDBaWE1nUFNCYlhWeHVYRzRnSUdadmNpQW9kbUZ5SUdrZ1BTQXdPeUJwSUR3Z2JHVnVaM1JvT3lCcEt5c3BJSHRjYmlBZ0lDQmpiMlJsVUc5cGJuUWdQU0J6ZEhKcGJtY3VZMmhoY2tOdlpHVkJkQ2hwS1Z4dVhHNGdJQ0FnTHk4Z2FYTWdjM1Z5Y205bllYUmxJR052YlhCdmJtVnVkRnh1SUNBZ0lHbG1JQ2hqYjJSbFVHOXBiblFnUGlBd2VFUTNSa1lnSmlZZ1kyOWtaVkJ2YVc1MElEd2dNSGhGTURBd0tTQjdYRzRnSUNBZ0lDQXZMeUJzWVhOMElHTm9ZWElnZDJGeklHRWdiR1ZoWkZ4dUlDQWdJQ0FnYVdZZ0tDRnNaV0ZrVTNWeWNtOW5ZWFJsS1NCN1hHNGdJQ0FnSUNBZ0lDOHZJRzV2SUd4bFlXUWdlV1YwWEc0Z0lDQWdJQ0FnSUdsbUlDaGpiMlJsVUc5cGJuUWdQaUF3ZUVSQ1JrWXBJSHRjYmlBZ0lDQWdJQ0FnSUNBdkx5QjFibVY0Y0dWamRHVmtJSFJ5WVdsc1hHNGdJQ0FnSUNBZ0lDQWdhV1lnS0NoMWJtbDBjeUF0UFNBektTQStJQzB4S1NCaWVYUmxjeTV3ZFhOb0tEQjRSVVlzSURCNFFrWXNJREI0UWtRcFhHNGdJQ0FnSUNBZ0lDQWdZMjl1ZEdsdWRXVmNiaUFnSUNBZ0lDQWdmU0JsYkhObElHbG1JQ2hwSUNzZ01TQTlQVDBnYkdWdVozUm9LU0I3WEc0Z0lDQWdJQ0FnSUNBZ0x5OGdkVzV3WVdseVpXUWdiR1ZoWkZ4dUlDQWdJQ0FnSUNBZ0lHbG1JQ2dvZFc1cGRITWdMVDBnTXlrZ1BpQXRNU2tnWW5sMFpYTXVjSFZ6YUNnd2VFVkdMQ0F3ZUVKR0xDQXdlRUpFS1Z4dUlDQWdJQ0FnSUNBZ0lHTnZiblJwYm5WbFhHNGdJQ0FnSUNBZ0lIMWNibHh1SUNBZ0lDQWdJQ0F2THlCMllXeHBaQ0JzWldGa1hHNGdJQ0FnSUNBZ0lHeGxZV1JUZFhKeWIyZGhkR1VnUFNCamIyUmxVRzlwYm5SY2JseHVJQ0FnSUNBZ0lDQmpiMjUwYVc1MVpWeHVJQ0FnSUNBZ2ZWeHVYRzRnSUNBZ0lDQXZMeUF5SUd4bFlXUnpJR2x1SUdFZ2NtOTNYRzRnSUNBZ0lDQnBaaUFvWTI5a1pWQnZhVzUwSUR3Z01IaEVRekF3S1NCN1hHNGdJQ0FnSUNBZ0lHbG1JQ2dvZFc1cGRITWdMVDBnTXlrZ1BpQXRNU2tnWW5sMFpYTXVjSFZ6YUNnd2VFVkdMQ0F3ZUVKR0xDQXdlRUpFS1Z4dUlDQWdJQ0FnSUNCc1pXRmtVM1Z5Y205bllYUmxJRDBnWTI5a1pWQnZhVzUwWEc0Z0lDQWdJQ0FnSUdOdmJuUnBiblZsWEc0Z0lDQWdJQ0I5WEc1Y2JpQWdJQ0FnSUM4dklIWmhiR2xrSUhOMWNuSnZaMkYwWlNCd1lXbHlYRzRnSUNBZ0lDQmpiMlJsVUc5cGJuUWdQU0FvYkdWaFpGTjFjbkp2WjJGMFpTQXRJREI0UkRnd01DQThQQ0F4TUNCOElHTnZaR1ZRYjJsdWRDQXRJREI0UkVNd01Da2dLeUF3ZURFd01EQXdYRzRnSUNBZ2ZTQmxiSE5sSUdsbUlDaHNaV0ZrVTNWeWNtOW5ZWFJsS1NCN1hHNGdJQ0FnSUNBdkx5QjJZV3hwWkNCaWJYQWdZMmhoY2l3Z1luVjBJR3hoYzNRZ1kyaGhjaUIzWVhNZ1lTQnNaV0ZrWEc0Z0lDQWdJQ0JwWmlBb0tIVnVhWFJ6SUMwOUlETXBJRDRnTFRFcElHSjVkR1Z6TG5CMWMyZ29NSGhGUml3Z01IaENSaXdnTUhoQ1JDbGNiaUFnSUNCOVhHNWNiaUFnSUNCc1pXRmtVM1Z5Y205bllYUmxJRDBnYm5Wc2JGeHVYRzRnSUNBZ0x5OGdaVzVqYjJSbElIVjBaamhjYmlBZ0lDQnBaaUFvWTI5a1pWQnZhVzUwSUR3Z01IZzRNQ2tnZTF4dUlDQWdJQ0FnYVdZZ0tDaDFibWwwY3lBdFBTQXhLU0E4SURBcElHSnlaV0ZyWEc0Z0lDQWdJQ0JpZVhSbGN5NXdkWE5vS0dOdlpHVlFiMmx1ZENsY2JpQWdJQ0I5SUdWc2MyVWdhV1lnS0dOdlpHVlFiMmx1ZENBOElEQjRPREF3S1NCN1hHNGdJQ0FnSUNCcFppQW9LSFZ1YVhSeklDMDlJRElwSUR3Z01Da2dZbkpsWVd0Y2JpQWdJQ0FnSUdKNWRHVnpMbkIxYzJnb1hHNGdJQ0FnSUNBZ0lHTnZaR1ZRYjJsdWRDQStQaUF3ZURZZ2ZDQXdlRU13TEZ4dUlDQWdJQ0FnSUNCamIyUmxVRzlwYm5RZ0ppQXdlRE5HSUh3Z01IZzRNRnh1SUNBZ0lDQWdLVnh1SUNBZ0lIMGdaV3h6WlNCcFppQW9ZMjlrWlZCdmFXNTBJRHdnTUhneE1EQXdNQ2tnZTF4dUlDQWdJQ0FnYVdZZ0tDaDFibWwwY3lBdFBTQXpLU0E4SURBcElHSnlaV0ZyWEc0Z0lDQWdJQ0JpZVhSbGN5NXdkWE5vS0Z4dUlDQWdJQ0FnSUNCamIyUmxVRzlwYm5RZ1BqNGdNSGhESUh3Z01IaEZNQ3hjYmlBZ0lDQWdJQ0FnWTI5a1pWQnZhVzUwSUQ0K0lEQjROaUFtSURCNE0wWWdmQ0F3ZURnd0xGeHVJQ0FnSUNBZ0lDQmpiMlJsVUc5cGJuUWdKaUF3ZUROR0lId2dNSGc0TUZ4dUlDQWdJQ0FnS1Z4dUlDQWdJSDBnWld4elpTQnBaaUFvWTI5a1pWQnZhVzUwSUR3Z01IZ3hNVEF3TURBcElIdGNiaUFnSUNBZ0lHbG1JQ2dvZFc1cGRITWdMVDBnTkNrZ1BDQXdLU0JpY21WaGExeHVJQ0FnSUNBZ1lubDBaWE11Y0hWemFDaGNiaUFnSUNBZ0lDQWdZMjlrWlZCdmFXNTBJRDQrSURCNE1USWdmQ0F3ZUVZd0xGeHVJQ0FnSUNBZ0lDQmpiMlJsVUc5cGJuUWdQajRnTUhoRElDWWdNSGd6UmlCOElEQjRPREFzWEc0Z0lDQWdJQ0FnSUdOdlpHVlFiMmx1ZENBK1BpQXdlRFlnSmlBd2VETkdJSHdnTUhnNE1DeGNiaUFnSUNBZ0lDQWdZMjlrWlZCdmFXNTBJQ1lnTUhnelJpQjhJREI0T0RCY2JpQWdJQ0FnSUNsY2JpQWdJQ0I5SUdWc2MyVWdlMXh1SUNBZ0lDQWdkR2h5YjNjZ2JtVjNJRVZ5Y205eUtDZEpiblpoYkdsa0lHTnZaR1VnY0c5cGJuUW5LVnh1SUNBZ0lIMWNiaUFnZlZ4dVhHNGdJSEpsZEhWeWJpQmllWFJsYzF4dWZWeHVYRzVtZFc1amRHbHZiaUJoYzJOcGFWUnZRbmwwWlhNZ0tITjBjaWtnZTF4dUlDQjJZWElnWW5sMFpVRnljbUY1SUQwZ1cxMWNiaUFnWm05eUlDaDJZWElnYVNBOUlEQTdJR2tnUENCemRISXViR1Z1WjNSb095QnBLeXNwSUh0Y2JpQWdJQ0F2THlCT2IyUmxKM01nWTI5a1pTQnpaV1Z0Y3lCMGJ5QmlaU0JrYjJsdVp5QjBhR2x6SUdGdVpDQnViM1FnSmlBd2VEZEdMaTVjYmlBZ0lDQmllWFJsUVhKeVlYa3VjSFZ6YUNoemRISXVZMmhoY2tOdlpHVkJkQ2hwS1NBbUlEQjRSa1lwWEc0Z0lIMWNiaUFnY21WMGRYSnVJR0o1ZEdWQmNuSmhlVnh1ZlZ4dVhHNW1kVzVqZEdsdmJpQjFkR1l4Tm14bFZHOUNlWFJsY3lBb2MzUnlMQ0IxYm1sMGN5a2dlMXh1SUNCMllYSWdZeXdnYUdrc0lHeHZYRzRnSUhaaGNpQmllWFJsUVhKeVlYa2dQU0JiWFZ4dUlDQm1iM0lnS0haaGNpQnBJRDBnTURzZ2FTQThJSE4wY2k1c1pXNW5kR2c3SUdrckt5a2dlMXh1SUNBZ0lHbG1JQ2dvZFc1cGRITWdMVDBnTWlrZ1BDQXdLU0JpY21WaGExeHVYRzRnSUNBZ1l5QTlJSE4wY2k1amFHRnlRMjlrWlVGMEtHa3BYRzRnSUNBZ2FHa2dQU0JqSUQ0K0lEaGNiaUFnSUNCc2J5QTlJR01nSlNBeU5UWmNiaUFnSUNCaWVYUmxRWEp5WVhrdWNIVnphQ2hzYnlsY2JpQWdJQ0JpZVhSbFFYSnlZWGt1Y0hWemFDaG9hU2xjYmlBZ2ZWeHVYRzRnSUhKbGRIVnliaUJpZVhSbFFYSnlZWGxjYm4xY2JseHVablZ1WTNScGIyNGdZbUZ6WlRZMFZHOUNlWFJsY3lBb2MzUnlLU0I3WEc0Z0lISmxkSFZ5YmlCaVlYTmxOalF1ZEc5Q2VYUmxRWEp5WVhrb1ltRnpaVFkwWTJ4bFlXNG9jM1J5S1NsY2JuMWNibHh1Wm5WdVkzUnBiMjRnWW14cGRFSjFabVpsY2lBb2MzSmpMQ0JrYzNRc0lHOW1abk5sZEN3Z2JHVnVaM1JvS1NCN1hHNGdJR1p2Y2lBb2RtRnlJR2tnUFNBd095QnBJRHdnYkdWdVozUm9PeUJwS3lzcElIdGNiaUFnSUNCcFppQW9LR2tnS3lCdlptWnpaWFFnUGowZ1pITjBMbXhsYm1kMGFDa2dmSHdnS0drZ1BqMGdjM0pqTG14bGJtZDBhQ2twSUdKeVpXRnJYRzRnSUNBZ1pITjBXMmtnS3lCdlptWnpaWFJkSUQwZ2MzSmpXMmxkWEc0Z0lIMWNiaUFnY21WMGRYSnVJR2xjYm4xY2JpSmRmUT09IiwidmFyIGxvb2t1cCA9ICdBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvJztcblxuOyhmdW5jdGlvbiAoZXhwb3J0cykge1xuXHQndXNlIHN0cmljdCc7XG5cbiAgdmFyIEFyciA9ICh0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcpXG4gICAgPyBVaW50OEFycmF5XG4gICAgOiBBcnJheVxuXG5cdHZhciBQTFVTICAgPSAnKycuY2hhckNvZGVBdCgwKVxuXHR2YXIgU0xBU0ggID0gJy8nLmNoYXJDb2RlQXQoMClcblx0dmFyIE5VTUJFUiA9ICcwJy5jaGFyQ29kZUF0KDApXG5cdHZhciBMT1dFUiAgPSAnYScuY2hhckNvZGVBdCgwKVxuXHR2YXIgVVBQRVIgID0gJ0EnLmNoYXJDb2RlQXQoMClcblx0dmFyIFBMVVNfVVJMX1NBRkUgPSAnLScuY2hhckNvZGVBdCgwKVxuXHR2YXIgU0xBU0hfVVJMX1NBRkUgPSAnXycuY2hhckNvZGVBdCgwKVxuXG5cdGZ1bmN0aW9uIGRlY29kZSAoZWx0KSB7XG5cdFx0dmFyIGNvZGUgPSBlbHQuY2hhckNvZGVBdCgwKVxuXHRcdGlmIChjb2RlID09PSBQTFVTIHx8XG5cdFx0ICAgIGNvZGUgPT09IFBMVVNfVVJMX1NBRkUpXG5cdFx0XHRyZXR1cm4gNjIgLy8gJysnXG5cdFx0aWYgKGNvZGUgPT09IFNMQVNIIHx8XG5cdFx0ICAgIGNvZGUgPT09IFNMQVNIX1VSTF9TQUZFKVxuXHRcdFx0cmV0dXJuIDYzIC8vICcvJ1xuXHRcdGlmIChjb2RlIDwgTlVNQkVSKVxuXHRcdFx0cmV0dXJuIC0xIC8vbm8gbWF0Y2hcblx0XHRpZiAoY29kZSA8IE5VTUJFUiArIDEwKVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBOVU1CRVIgKyAyNiArIDI2XG5cdFx0aWYgKGNvZGUgPCBVUFBFUiArIDI2KVxuXHRcdFx0cmV0dXJuIGNvZGUgLSBVUFBFUlxuXHRcdGlmIChjb2RlIDwgTE9XRVIgKyAyNilcblx0XHRcdHJldHVybiBjb2RlIC0gTE9XRVIgKyAyNlxuXHR9XG5cblx0ZnVuY3Rpb24gYjY0VG9CeXRlQXJyYXkgKGI2NCkge1xuXHRcdHZhciBpLCBqLCBsLCB0bXAsIHBsYWNlSG9sZGVycywgYXJyXG5cblx0XHRpZiAoYjY0Lmxlbmd0aCAlIDQgPiAwKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc3RyaW5nLiBMZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIDQnKVxuXHRcdH1cblxuXHRcdC8vIHRoZSBudW1iZXIgb2YgZXF1YWwgc2lnbnMgKHBsYWNlIGhvbGRlcnMpXG5cdFx0Ly8gaWYgdGhlcmUgYXJlIHR3byBwbGFjZWhvbGRlcnMsIHRoYW4gdGhlIHR3byBjaGFyYWN0ZXJzIGJlZm9yZSBpdFxuXHRcdC8vIHJlcHJlc2VudCBvbmUgYnl0ZVxuXHRcdC8vIGlmIHRoZXJlIGlzIG9ubHkgb25lLCB0aGVuIHRoZSB0aHJlZSBjaGFyYWN0ZXJzIGJlZm9yZSBpdCByZXByZXNlbnQgMiBieXRlc1xuXHRcdC8vIHRoaXMgaXMganVzdCBhIGNoZWFwIGhhY2sgdG8gbm90IGRvIGluZGV4T2YgdHdpY2Vcblx0XHR2YXIgbGVuID0gYjY0Lmxlbmd0aFxuXHRcdHBsYWNlSG9sZGVycyA9ICc9JyA9PT0gYjY0LmNoYXJBdChsZW4gLSAyKSA/IDIgOiAnPScgPT09IGI2NC5jaGFyQXQobGVuIC0gMSkgPyAxIDogMFxuXG5cdFx0Ly8gYmFzZTY0IGlzIDQvMyArIHVwIHRvIHR3byBjaGFyYWN0ZXJzIG9mIHRoZSBvcmlnaW5hbCBkYXRhXG5cdFx0YXJyID0gbmV3IEFycihiNjQubGVuZ3RoICogMyAvIDQgLSBwbGFjZUhvbGRlcnMpXG5cblx0XHQvLyBpZiB0aGVyZSBhcmUgcGxhY2Vob2xkZXJzLCBvbmx5IGdldCB1cCB0byB0aGUgbGFzdCBjb21wbGV0ZSA0IGNoYXJzXG5cdFx0bCA9IHBsYWNlSG9sZGVycyA+IDAgPyBiNjQubGVuZ3RoIC0gNCA6IGI2NC5sZW5ndGhcblxuXHRcdHZhciBMID0gMFxuXG5cdFx0ZnVuY3Rpb24gcHVzaCAodikge1xuXHRcdFx0YXJyW0wrK10gPSB2XG5cdFx0fVxuXG5cdFx0Zm9yIChpID0gMCwgaiA9IDA7IGkgPCBsOyBpICs9IDQsIGogKz0gMykge1xuXHRcdFx0dG1wID0gKGRlY29kZShiNjQuY2hhckF0KGkpKSA8PCAxOCkgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA8PCAxMikgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDIpKSA8PCA2KSB8IGRlY29kZShiNjQuY2hhckF0KGkgKyAzKSlcblx0XHRcdHB1c2goKHRtcCAmIDB4RkYwMDAwKSA+PiAxNilcblx0XHRcdHB1c2goKHRtcCAmIDB4RkYwMCkgPj4gOClcblx0XHRcdHB1c2godG1wICYgMHhGRilcblx0XHR9XG5cblx0XHRpZiAocGxhY2VIb2xkZXJzID09PSAyKSB7XG5cdFx0XHR0bXAgPSAoZGVjb2RlKGI2NC5jaGFyQXQoaSkpIDw8IDIpIHwgKGRlY29kZShiNjQuY2hhckF0KGkgKyAxKSkgPj4gNClcblx0XHRcdHB1c2godG1wICYgMHhGRilcblx0XHR9IGVsc2UgaWYgKHBsYWNlSG9sZGVycyA9PT0gMSkge1xuXHRcdFx0dG1wID0gKGRlY29kZShiNjQuY2hhckF0KGkpKSA8PCAxMCkgfCAoZGVjb2RlKGI2NC5jaGFyQXQoaSArIDEpKSA8PCA0KSB8IChkZWNvZGUoYjY0LmNoYXJBdChpICsgMikpID4+IDIpXG5cdFx0XHRwdXNoKCh0bXAgPj4gOCkgJiAweEZGKVxuXHRcdFx0cHVzaCh0bXAgJiAweEZGKVxuXHRcdH1cblxuXHRcdHJldHVybiBhcnJcblx0fVxuXG5cdGZ1bmN0aW9uIHVpbnQ4VG9CYXNlNjQgKHVpbnQ4KSB7XG5cdFx0dmFyIGksXG5cdFx0XHRleHRyYUJ5dGVzID0gdWludDgubGVuZ3RoICUgMywgLy8gaWYgd2UgaGF2ZSAxIGJ5dGUgbGVmdCwgcGFkIDIgYnl0ZXNcblx0XHRcdG91dHB1dCA9IFwiXCIsXG5cdFx0XHR0ZW1wLCBsZW5ndGhcblxuXHRcdGZ1bmN0aW9uIGVuY29kZSAobnVtKSB7XG5cdFx0XHRyZXR1cm4gbG9va3VwLmNoYXJBdChudW0pXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gdHJpcGxldFRvQmFzZTY0IChudW0pIHtcblx0XHRcdHJldHVybiBlbmNvZGUobnVtID4+IDE4ICYgMHgzRikgKyBlbmNvZGUobnVtID4+IDEyICYgMHgzRikgKyBlbmNvZGUobnVtID4+IDYgJiAweDNGKSArIGVuY29kZShudW0gJiAweDNGKVxuXHRcdH1cblxuXHRcdC8vIGdvIHRocm91Z2ggdGhlIGFycmF5IGV2ZXJ5IHRocmVlIGJ5dGVzLCB3ZSdsbCBkZWFsIHdpdGggdHJhaWxpbmcgc3R1ZmYgbGF0ZXJcblx0XHRmb3IgKGkgPSAwLCBsZW5ndGggPSB1aW50OC5sZW5ndGggLSBleHRyYUJ5dGVzOyBpIDwgbGVuZ3RoOyBpICs9IDMpIHtcblx0XHRcdHRlbXAgPSAodWludDhbaV0gPDwgMTYpICsgKHVpbnQ4W2kgKyAxXSA8PCA4KSArICh1aW50OFtpICsgMl0pXG5cdFx0XHRvdXRwdXQgKz0gdHJpcGxldFRvQmFzZTY0KHRlbXApXG5cdFx0fVxuXG5cdFx0Ly8gcGFkIHRoZSBlbmQgd2l0aCB6ZXJvcywgYnV0IG1ha2Ugc3VyZSB0byBub3QgZm9yZ2V0IHRoZSBleHRyYSBieXRlc1xuXHRcdHN3aXRjaCAoZXh0cmFCeXRlcykge1xuXHRcdFx0Y2FzZSAxOlxuXHRcdFx0XHR0ZW1wID0gdWludDhbdWludDgubGVuZ3RoIC0gMV1cblx0XHRcdFx0b3V0cHV0ICs9IGVuY29kZSh0ZW1wID4+IDIpXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPDwgNCkgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gJz09J1xuXHRcdFx0XHRicmVha1xuXHRcdFx0Y2FzZSAyOlxuXHRcdFx0XHR0ZW1wID0gKHVpbnQ4W3VpbnQ4Lmxlbmd0aCAtIDJdIDw8IDgpICsgKHVpbnQ4W3VpbnQ4Lmxlbmd0aCAtIDFdKVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKHRlbXAgPj4gMTApXG5cdFx0XHRcdG91dHB1dCArPSBlbmNvZGUoKHRlbXAgPj4gNCkgJiAweDNGKVxuXHRcdFx0XHRvdXRwdXQgKz0gZW5jb2RlKCh0ZW1wIDw8IDIpICYgMHgzRilcblx0XHRcdFx0b3V0cHV0ICs9ICc9J1xuXHRcdFx0XHRicmVha1xuXHRcdH1cblxuXHRcdHJldHVybiBvdXRwdXRcblx0fVxuXG5cdGV4cG9ydHMudG9CeXRlQXJyYXkgPSBiNjRUb0J5dGVBcnJheVxuXHRleHBvcnRzLmZyb21CeXRlQXJyYXkgPSB1aW50OFRvQmFzZTY0XG59KHR5cGVvZiBleHBvcnRzID09PSAndW5kZWZpbmVkJyA/ICh0aGlzLmJhc2U2NGpzID0ge30pIDogZXhwb3J0cykpXG4iLCJleHBvcnRzLnJlYWQgPSBmdW5jdGlvbiAoYnVmZmVyLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbVxuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIG5CaXRzID0gLTdcbiAgdmFyIGkgPSBpc0xFID8gKG5CeXRlcyAtIDEpIDogMFxuICB2YXIgZCA9IGlzTEUgPyAtMSA6IDFcbiAgdmFyIHMgPSBidWZmZXJbb2Zmc2V0ICsgaV1cblxuICBpICs9IGRcblxuICBlID0gcyAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBzID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBlTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IGUgPSBlICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgbSA9IGUgJiAoKDEgPDwgKC1uQml0cykpIC0gMSlcbiAgZSA+Pj0gKC1uQml0cylcbiAgbkJpdHMgKz0gbUxlblxuICBmb3IgKDsgbkJpdHMgPiAwOyBtID0gbSAqIDI1NiArIGJ1ZmZlcltvZmZzZXQgKyBpXSwgaSArPSBkLCBuQml0cyAtPSA4KSB7fVxuXG4gIGlmIChlID09PSAwKSB7XG4gICAgZSA9IDEgLSBlQmlhc1xuICB9IGVsc2UgaWYgKGUgPT09IGVNYXgpIHtcbiAgICByZXR1cm4gbSA/IE5hTiA6ICgocyA/IC0xIDogMSkgKiBJbmZpbml0eSlcbiAgfSBlbHNlIHtcbiAgICBtID0gbSArIE1hdGgucG93KDIsIG1MZW4pXG4gICAgZSA9IGUgLSBlQmlhc1xuICB9XG4gIHJldHVybiAocyA/IC0xIDogMSkgKiBtICogTWF0aC5wb3coMiwgZSAtIG1MZW4pXG59XG5cbmV4cG9ydHMud3JpdGUgPSBmdW5jdGlvbiAoYnVmZmVyLCB2YWx1ZSwgb2Zmc2V0LCBpc0xFLCBtTGVuLCBuQnl0ZXMpIHtcbiAgdmFyIGUsIG0sIGNcbiAgdmFyIGVMZW4gPSBuQnl0ZXMgKiA4IC0gbUxlbiAtIDFcbiAgdmFyIGVNYXggPSAoMSA8PCBlTGVuKSAtIDFcbiAgdmFyIGVCaWFzID0gZU1heCA+PiAxXG4gIHZhciBydCA9IChtTGVuID09PSAyMyA/IE1hdGgucG93KDIsIC0yNCkgLSBNYXRoLnBvdygyLCAtNzcpIDogMClcbiAgdmFyIGkgPSBpc0xFID8gMCA6IChuQnl0ZXMgLSAxKVxuICB2YXIgZCA9IGlzTEUgPyAxIDogLTFcbiAgdmFyIHMgPSB2YWx1ZSA8IDAgfHwgKHZhbHVlID09PSAwICYmIDEgLyB2YWx1ZSA8IDApID8gMSA6IDBcblxuICB2YWx1ZSA9IE1hdGguYWJzKHZhbHVlKVxuXG4gIGlmIChpc05hTih2YWx1ZSkgfHwgdmFsdWUgPT09IEluZmluaXR5KSB7XG4gICAgbSA9IGlzTmFOKHZhbHVlKSA/IDEgOiAwXG4gICAgZSA9IGVNYXhcbiAgfSBlbHNlIHtcbiAgICBlID0gTWF0aC5mbG9vcihNYXRoLmxvZyh2YWx1ZSkgLyBNYXRoLkxOMilcbiAgICBpZiAodmFsdWUgKiAoYyA9IE1hdGgucG93KDIsIC1lKSkgPCAxKSB7XG4gICAgICBlLS1cbiAgICAgIGMgKj0gMlxuICAgIH1cbiAgICBpZiAoZSArIGVCaWFzID49IDEpIHtcbiAgICAgIHZhbHVlICs9IHJ0IC8gY1xuICAgIH0gZWxzZSB7XG4gICAgICB2YWx1ZSArPSBydCAqIE1hdGgucG93KDIsIDEgLSBlQmlhcylcbiAgICB9XG4gICAgaWYgKHZhbHVlICogYyA+PSAyKSB7XG4gICAgICBlKytcbiAgICAgIGMgLz0gMlxuICAgIH1cblxuICAgIGlmIChlICsgZUJpYXMgPj0gZU1heCkge1xuICAgICAgbSA9IDBcbiAgICAgIGUgPSBlTWF4XG4gICAgfSBlbHNlIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgbSA9ICh2YWx1ZSAqIGMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gZSArIGVCaWFzXG4gICAgfSBlbHNlIHtcbiAgICAgIG0gPSB2YWx1ZSAqIE1hdGgucG93KDIsIGVCaWFzIC0gMSkgKiBNYXRoLnBvdygyLCBtTGVuKVxuICAgICAgZSA9IDBcbiAgICB9XG4gIH1cblxuICBmb3IgKDsgbUxlbiA+PSA4OyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBtICYgMHhmZiwgaSArPSBkLCBtIC89IDI1NiwgbUxlbiAtPSA4KSB7fVxuXG4gIGUgPSAoZSA8PCBtTGVuKSB8IG1cbiAgZUxlbiArPSBtTGVuXG4gIGZvciAoOyBlTGVuID4gMDsgYnVmZmVyW29mZnNldCArIGldID0gZSAmIDB4ZmYsIGkgKz0gZCwgZSAvPSAyNTYsIGVMZW4gLT0gOCkge31cblxuICBidWZmZXJbb2Zmc2V0ICsgaSAtIGRdIHw9IHMgKiAxMjhcbn1cbiIsInZhciB0b1N0cmluZyA9IHt9LnRvU3RyaW5nO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEFycmF5LmlzQXJyYXkgfHwgZnVuY3Rpb24gKGFycikge1xuICByZXR1cm4gdG9TdHJpbmcuY2FsbChhcnIpID09ICdbb2JqZWN0IEFycmF5XSc7XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCJcblxubW9kdWxlLmV4cG9ydHMgPSBLRFRIZWFwXG5cbnZhciBwb29sID0gcmVxdWlyZShcInR5cGVkYXJyYXktcG9vbFwiKVxuXG5mdW5jdGlvbiBoZWFwUGFyZW50KGkpIHtcbiAgaWYoaSAmIDEpIHtcbiAgICByZXR1cm4gKGkgLSAxKSA+PiAxXG4gIH1cbiAgcmV0dXJuIChpID4+IDEpIC0gMVxufVxuXG5mdW5jdGlvbiBLRFRIZWFwKG4sIGQpIHtcbiAgdGhpcy5jb3VudCA9IDBcbiAgdGhpcy5kYXRhU2l6ZSA9IGRcbiAgdGhpcy5pbmRleCA9IHBvb2wubWFsbG9jSW50MzIobilcbiAgdGhpcy5kYXRhID0gcG9vbC5tYWxsb2NGbG9hdDY0KG4qZClcbn1cblxudmFyIHByb3RvID0gS0RUSGVhcC5wcm90b3R5cGVcblxucHJvdG8uaGVhcFN3YXAgPSBmdW5jdGlvbihfaSxfaikge1xuICB2YXIgZGF0YSA9IHRoaXMuZGF0YVxuICB2YXIgaW5kZXggPSB0aGlzLmluZGV4XG4gIHZhciBkID0gdGhpcy5kYXRhU2l6ZVxuICB2YXIgdG1wID0gaW5kZXhbX2ldXG4gIGluZGV4W19pXSA9IGluZGV4W19qXVxuICBpbmRleFtfal0gPSB0bXBcbiAgdmFyIGFwdHIgPSBkKl9pXG4gIHZhciBicHRyID0gZCpfalxuICBmb3IodmFyIF9rPTA7IF9rPGQ7ICsrX2spIHtcbiAgICB2YXIgdDIgPSBkYXRhW2FwdHJdXG4gICAgZGF0YVthcHRyXSA9IGRhdGFbYnB0cl1cbiAgICBkYXRhW2JwdHJdID0gdDJcbiAgICBhcHRyICs9IDFcbiAgICBicHRyICs9IDFcbiAgfVxufVxuXG5wcm90by5oZWFwVXAgPSBmdW5jdGlvbihpKSB7XG4gIHZhciBkID0gdGhpcy5kYXRhU2l6ZVxuICB2YXIgaW5kZXggPSB0aGlzLmluZGV4XG4gIHZhciBkYXRhID0gdGhpcy5kYXRhXG4gIHZhciB3ID0gZGF0YVtkKmldXG4gIHdoaWxlKGk+MCkge1xuICAgIHZhciBwYXJlbnQgPSBoZWFwUGFyZW50KGkpXG4gICAgaWYocGFyZW50ID49IDApIHtcbiAgICAgIHZhciBwdyA9IGRhdGFbZCpwYXJlbnRdXG4gICAgICBpZih3IDwgcHcpIHtcbiAgICAgICAgdGhpcy5oZWFwU3dhcChpLCBwYXJlbnQpXG4gICAgICAgIGkgPSBwYXJlbnRcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cbiAgICB9XG4gICAgYnJlYWtcbiAgfVxufVxuXG5wcm90by5oZWFwRG93biA9IGZ1bmN0aW9uKGkpIHtcbiAgdmFyIGQgPSB0aGlzLmRhdGFTaXplXG4gIHZhciBpbmRleCA9IHRoaXMuaW5kZXhcbiAgdmFyIGRhdGEgPSB0aGlzLmRhdGFcbiAgdmFyIGNvdW50ID0gdGhpcy5jb3VudFxuICB2YXIgdyA9IGRhdGFbZCppXVxuICB3aGlsZSh0cnVlKSB7XG4gICAgdmFyIHR3ID0gd1xuICAgIHZhciBsZWZ0ICA9IDIqaSArIDFcbiAgICB2YXIgcmlnaHQgPSAyKihpICsgMSlcbiAgICB2YXIgbmV4dCA9IGlcbiAgICBpZihsZWZ0IDwgY291bnQpIHtcbiAgICAgIHZhciBsdyA9IGRhdGFbZCpsZWZ0XVxuICAgICAgaWYobHcgPCB0dykge1xuICAgICAgICBuZXh0ID0gbGVmdFxuICAgICAgICB0dyA9IGx3XG4gICAgICB9XG4gICAgfVxuICAgIGlmKHJpZ2h0IDwgY291bnQpIHtcbiAgICAgIHZhciBydyA9IGRhdGFbZCpyaWdodF1cbiAgICAgIGlmKHJ3IDwgdHcpIHtcbiAgICAgICAgbmV4dCA9IHJpZ2h0XG4gICAgICB9XG4gICAgfVxuICAgIGlmKG5leHQgPT09IGkpIHtcbiAgICAgIGJyZWFrXG4gICAgfVxuICAgIHRoaXMuaGVhcFN3YXAoaSwgbmV4dClcbiAgICBpID0gbmV4dCAgICAgIFxuICB9XG59XG5cbi8vQ2xlYXIgaXRlbSBmcm9tIHRvcCBvZiBoZWFwXG5wcm90by5wb3AgPSBmdW5jdGlvbigpIHtcbiAgdGhpcy5jb3VudCAtPSAxXG4gIHRoaXMuaGVhcFN3YXAoMCwgdGhpcy5jb3VudClcbiAgdGhpcy5oZWFwRG93bigwKVxufVxuXG4vL0Fzc3VtZSBvYmplY3QgYWxyZWFkeSB3cml0dGVuIHRvIGRhdGFcbnByb3RvLnB1c2ggPSBmdW5jdGlvbigpIHtcbiAgdGhpcy5oZWFwVXAodGhpcy5jb3VudClcbiAgdGhpcy5jb3VudCArPSAxXG59XG5cbnByb3RvLmRpc3Bvc2UgPSBmdW5jdGlvbigpIHtcbiAgcG9vbC5mcmVlSW50MzIodGhpcy5pbmRleClcbiAgcG9vbC5mcmVlRmxvYXQ2NCh0aGlzLmRhdGEpXG59IiwiLyoqXG4gKiBCaXQgdHdpZGRsaW5nIGhhY2tzIGZvciBKYXZhU2NyaXB0LlxuICpcbiAqIEF1dGhvcjogTWlrb2xhIEx5c2Vua29cbiAqXG4gKiBQb3J0ZWQgZnJvbSBTdGFuZm9yZCBiaXQgdHdpZGRsaW5nIGhhY2sgbGlicmFyeTpcbiAqICAgIGh0dHA6Ly9ncmFwaGljcy5zdGFuZm9yZC5lZHUvfnNlYW5kZXIvYml0aGFja3MuaHRtbFxuICovXG5cblwidXNlIHN0cmljdFwiOyBcInVzZSByZXN0cmljdFwiO1xuXG4vL051bWJlciBvZiBiaXRzIGluIGFuIGludGVnZXJcbnZhciBJTlRfQklUUyA9IDMyO1xuXG4vL0NvbnN0YW50c1xuZXhwb3J0cy5JTlRfQklUUyAgPSBJTlRfQklUUztcbmV4cG9ydHMuSU5UX01BWCAgID0gIDB4N2ZmZmZmZmY7XG5leHBvcnRzLklOVF9NSU4gICA9IC0xPDwoSU5UX0JJVFMtMSk7XG5cbi8vUmV0dXJucyAtMSwgMCwgKzEgZGVwZW5kaW5nIG9uIHNpZ24gb2YgeFxuZXhwb3J0cy5zaWduID0gZnVuY3Rpb24odikge1xuICByZXR1cm4gKHYgPiAwKSAtICh2IDwgMCk7XG59XG5cbi8vQ29tcHV0ZXMgYWJzb2x1dGUgdmFsdWUgb2YgaW50ZWdlclxuZXhwb3J0cy5hYnMgPSBmdW5jdGlvbih2KSB7XG4gIHZhciBtYXNrID0gdiA+PiAoSU5UX0JJVFMtMSk7XG4gIHJldHVybiAodiBeIG1hc2spIC0gbWFzaztcbn1cblxuLy9Db21wdXRlcyBtaW5pbXVtIG9mIGludGVnZXJzIHggYW5kIHlcbmV4cG9ydHMubWluID0gZnVuY3Rpb24oeCwgeSkge1xuICByZXR1cm4geSBeICgoeCBeIHkpICYgLSh4IDwgeSkpO1xufVxuXG4vL0NvbXB1dGVzIG1heGltdW0gb2YgaW50ZWdlcnMgeCBhbmQgeVxuZXhwb3J0cy5tYXggPSBmdW5jdGlvbih4LCB5KSB7XG4gIHJldHVybiB4IF4gKCh4IF4geSkgJiAtKHggPCB5KSk7XG59XG5cbi8vQ2hlY2tzIGlmIGEgbnVtYmVyIGlzIGEgcG93ZXIgb2YgdHdvXG5leHBvcnRzLmlzUG93MiA9IGZ1bmN0aW9uKHYpIHtcbiAgcmV0dXJuICEodiAmICh2LTEpKSAmJiAoISF2KTtcbn1cblxuLy9Db21wdXRlcyBsb2cgYmFzZSAyIG9mIHZcbmV4cG9ydHMubG9nMiA9IGZ1bmN0aW9uKHYpIHtcbiAgdmFyIHIsIHNoaWZ0O1xuICByID0gICAgICh2ID4gMHhGRkZGKSA8PCA0OyB2ID4+Pj0gcjtcbiAgc2hpZnQgPSAodiA+IDB4RkYgICkgPDwgMzsgdiA+Pj49IHNoaWZ0OyByIHw9IHNoaWZ0O1xuICBzaGlmdCA9ICh2ID4gMHhGICAgKSA8PCAyOyB2ID4+Pj0gc2hpZnQ7IHIgfD0gc2hpZnQ7XG4gIHNoaWZ0ID0gKHYgPiAweDMgICApIDw8IDE7IHYgPj4+PSBzaGlmdDsgciB8PSBzaGlmdDtcbiAgcmV0dXJuIHIgfCAodiA+PiAxKTtcbn1cblxuLy9Db21wdXRlcyBsb2cgYmFzZSAxMCBvZiB2XG5leHBvcnRzLmxvZzEwID0gZnVuY3Rpb24odikge1xuICByZXR1cm4gICh2ID49IDEwMDAwMDAwMDApID8gOSA6ICh2ID49IDEwMDAwMDAwMCkgPyA4IDogKHYgPj0gMTAwMDAwMDApID8gNyA6XG4gICAgICAgICAgKHYgPj0gMTAwMDAwMCkgPyA2IDogKHYgPj0gMTAwMDAwKSA/IDUgOiAodiA+PSAxMDAwMCkgPyA0IDpcbiAgICAgICAgICAodiA+PSAxMDAwKSA/IDMgOiAodiA+PSAxMDApID8gMiA6ICh2ID49IDEwKSA/IDEgOiAwO1xufVxuXG4vL0NvdW50cyBudW1iZXIgb2YgYml0c1xuZXhwb3J0cy5wb3BDb3VudCA9IGZ1bmN0aW9uKHYpIHtcbiAgdiA9IHYgLSAoKHYgPj4+IDEpICYgMHg1NTU1NTU1NSk7XG4gIHYgPSAodiAmIDB4MzMzMzMzMzMpICsgKCh2ID4+PiAyKSAmIDB4MzMzMzMzMzMpO1xuICByZXR1cm4gKCh2ICsgKHYgPj4+IDQpICYgMHhGMEYwRjBGKSAqIDB4MTAxMDEwMSkgPj4+IDI0O1xufVxuXG4vL0NvdW50cyBudW1iZXIgb2YgdHJhaWxpbmcgemVyb3NcbmZ1bmN0aW9uIGNvdW50VHJhaWxpbmdaZXJvcyh2KSB7XG4gIHZhciBjID0gMzI7XG4gIHYgJj0gLXY7XG4gIGlmICh2KSBjLS07XG4gIGlmICh2ICYgMHgwMDAwRkZGRikgYyAtPSAxNjtcbiAgaWYgKHYgJiAweDAwRkYwMEZGKSBjIC09IDg7XG4gIGlmICh2ICYgMHgwRjBGMEYwRikgYyAtPSA0O1xuICBpZiAodiAmIDB4MzMzMzMzMzMpIGMgLT0gMjtcbiAgaWYgKHYgJiAweDU1NTU1NTU1KSBjIC09IDE7XG4gIHJldHVybiBjO1xufVxuZXhwb3J0cy5jb3VudFRyYWlsaW5nWmVyb3MgPSBjb3VudFRyYWlsaW5nWmVyb3M7XG5cbi8vUm91bmRzIHRvIG5leHQgcG93ZXIgb2YgMlxuZXhwb3J0cy5uZXh0UG93MiA9IGZ1bmN0aW9uKHYpIHtcbiAgdiArPSB2ID09PSAwO1xuICAtLXY7XG4gIHYgfD0gdiA+Pj4gMTtcbiAgdiB8PSB2ID4+PiAyO1xuICB2IHw9IHYgPj4+IDQ7XG4gIHYgfD0gdiA+Pj4gODtcbiAgdiB8PSB2ID4+PiAxNjtcbiAgcmV0dXJuIHYgKyAxO1xufVxuXG4vL1JvdW5kcyBkb3duIHRvIHByZXZpb3VzIHBvd2VyIG9mIDJcbmV4cG9ydHMucHJldlBvdzIgPSBmdW5jdGlvbih2KSB7XG4gIHYgfD0gdiA+Pj4gMTtcbiAgdiB8PSB2ID4+PiAyO1xuICB2IHw9IHYgPj4+IDQ7XG4gIHYgfD0gdiA+Pj4gODtcbiAgdiB8PSB2ID4+PiAxNjtcbiAgcmV0dXJuIHYgLSAodj4+PjEpO1xufVxuXG4vL0NvbXB1dGVzIHBhcml0eSBvZiB3b3JkXG5leHBvcnRzLnBhcml0eSA9IGZ1bmN0aW9uKHYpIHtcbiAgdiBePSB2ID4+PiAxNjtcbiAgdiBePSB2ID4+PiA4O1xuICB2IF49IHYgPj4+IDQ7XG4gIHYgJj0gMHhmO1xuICByZXR1cm4gKDB4Njk5NiA+Pj4gdikgJiAxO1xufVxuXG52YXIgUkVWRVJTRV9UQUJMRSA9IG5ldyBBcnJheSgyNTYpO1xuXG4oZnVuY3Rpb24odGFiKSB7XG4gIGZvcih2YXIgaT0wOyBpPDI1NjsgKytpKSB7XG4gICAgdmFyIHYgPSBpLCByID0gaSwgcyA9IDc7XG4gICAgZm9yICh2ID4+Pj0gMTsgdjsgdiA+Pj49IDEpIHtcbiAgICAgIHIgPDw9IDE7XG4gICAgICByIHw9IHYgJiAxO1xuICAgICAgLS1zO1xuICAgIH1cbiAgICB0YWJbaV0gPSAociA8PCBzKSAmIDB4ZmY7XG4gIH1cbn0pKFJFVkVSU0VfVEFCTEUpO1xuXG4vL1JldmVyc2UgYml0cyBpbiBhIDMyIGJpdCB3b3JkXG5leHBvcnRzLnJldmVyc2UgPSBmdW5jdGlvbih2KSB7XG4gIHJldHVybiAgKFJFVkVSU0VfVEFCTEVbIHYgICAgICAgICAmIDB4ZmZdIDw8IDI0KSB8XG4gICAgICAgICAgKFJFVkVSU0VfVEFCTEVbKHYgPj4+IDgpICAmIDB4ZmZdIDw8IDE2KSB8XG4gICAgICAgICAgKFJFVkVSU0VfVEFCTEVbKHYgPj4+IDE2KSAmIDB4ZmZdIDw8IDgpICB8XG4gICAgICAgICAgIFJFVkVSU0VfVEFCTEVbKHYgPj4+IDI0KSAmIDB4ZmZdO1xufVxuXG4vL0ludGVybGVhdmUgYml0cyBvZiAyIGNvb3JkaW5hdGVzIHdpdGggMTYgYml0cy4gIFVzZWZ1bCBmb3IgZmFzdCBxdWFkdHJlZSBjb2Rlc1xuZXhwb3J0cy5pbnRlcmxlYXZlMiA9IGZ1bmN0aW9uKHgsIHkpIHtcbiAgeCAmPSAweEZGRkY7XG4gIHggPSAoeCB8ICh4IDw8IDgpKSAmIDB4MDBGRjAwRkY7XG4gIHggPSAoeCB8ICh4IDw8IDQpKSAmIDB4MEYwRjBGMEY7XG4gIHggPSAoeCB8ICh4IDw8IDIpKSAmIDB4MzMzMzMzMzM7XG4gIHggPSAoeCB8ICh4IDw8IDEpKSAmIDB4NTU1NTU1NTU7XG5cbiAgeSAmPSAweEZGRkY7XG4gIHkgPSAoeSB8ICh5IDw8IDgpKSAmIDB4MDBGRjAwRkY7XG4gIHkgPSAoeSB8ICh5IDw8IDQpKSAmIDB4MEYwRjBGMEY7XG4gIHkgPSAoeSB8ICh5IDw8IDIpKSAmIDB4MzMzMzMzMzM7XG4gIHkgPSAoeSB8ICh5IDw8IDEpKSAmIDB4NTU1NTU1NTU7XG5cbiAgcmV0dXJuIHggfCAoeSA8PCAxKTtcbn1cblxuLy9FeHRyYWN0cyB0aGUgbnRoIGludGVybGVhdmVkIGNvbXBvbmVudFxuZXhwb3J0cy5kZWludGVybGVhdmUyID0gZnVuY3Rpb24odiwgbikge1xuICB2ID0gKHYgPj4+IG4pICYgMHg1NTU1NTU1NTtcbiAgdiA9ICh2IHwgKHYgPj4+IDEpKSAgJiAweDMzMzMzMzMzO1xuICB2ID0gKHYgfCAodiA+Pj4gMikpICAmIDB4MEYwRjBGMEY7XG4gIHYgPSAodiB8ICh2ID4+PiA0KSkgICYgMHgwMEZGMDBGRjtcbiAgdiA9ICh2IHwgKHYgPj4+IDE2KSkgJiAweDAwMEZGRkY7XG4gIHJldHVybiAodiA8PCAxNikgPj4gMTY7XG59XG5cblxuLy9JbnRlcmxlYXZlIGJpdHMgb2YgMyBjb29yZGluYXRlcywgZWFjaCB3aXRoIDEwIGJpdHMuICBVc2VmdWwgZm9yIGZhc3Qgb2N0cmVlIGNvZGVzXG5leHBvcnRzLmludGVybGVhdmUzID0gZnVuY3Rpb24oeCwgeSwgeikge1xuICB4ICY9IDB4M0ZGO1xuICB4ICA9ICh4IHwgKHg8PDE2KSkgJiA0Mjc4MTkwMzM1O1xuICB4ICA9ICh4IHwgKHg8PDgpKSAgJiAyNTE3MTk2OTU7XG4gIHggID0gKHggfCAoeDw8NCkpICAmIDMyNzIzNTYwMzU7XG4gIHggID0gKHggfCAoeDw8MikpICAmIDEyMjcxMzM1MTM7XG5cbiAgeSAmPSAweDNGRjtcbiAgeSAgPSAoeSB8ICh5PDwxNikpICYgNDI3ODE5MDMzNTtcbiAgeSAgPSAoeSB8ICh5PDw4KSkgICYgMjUxNzE5Njk1O1xuICB5ICA9ICh5IHwgKHk8PDQpKSAgJiAzMjcyMzU2MDM1O1xuICB5ICA9ICh5IHwgKHk8PDIpKSAgJiAxMjI3MTMzNTEzO1xuICB4IHw9ICh5IDw8IDEpO1xuICBcbiAgeiAmPSAweDNGRjtcbiAgeiAgPSAoeiB8ICh6PDwxNikpICYgNDI3ODE5MDMzNTtcbiAgeiAgPSAoeiB8ICh6PDw4KSkgICYgMjUxNzE5Njk1O1xuICB6ICA9ICh6IHwgKHo8PDQpKSAgJiAzMjcyMzU2MDM1O1xuICB6ICA9ICh6IHwgKHo8PDIpKSAgJiAxMjI3MTMzNTEzO1xuICBcbiAgcmV0dXJuIHggfCAoeiA8PCAyKTtcbn1cblxuLy9FeHRyYWN0cyBudGggaW50ZXJsZWF2ZWQgY29tcG9uZW50IG9mIGEgMy10dXBsZVxuZXhwb3J0cy5kZWludGVybGVhdmUzID0gZnVuY3Rpb24odiwgbikge1xuICB2ID0gKHYgPj4+IG4pICAgICAgICYgMTIyNzEzMzUxMztcbiAgdiA9ICh2IHwgKHY+Pj4yKSkgICAmIDMyNzIzNTYwMzU7XG4gIHYgPSAodiB8ICh2Pj4+NCkpICAgJiAyNTE3MTk2OTU7XG4gIHYgPSAodiB8ICh2Pj4+OCkpICAgJiA0Mjc4MTkwMzM1O1xuICB2ID0gKHYgfCAodj4+PjE2KSkgICYgMHgzRkY7XG4gIHJldHVybiAodjw8MjIpPj4yMjtcbn1cblxuLy9Db21wdXRlcyBuZXh0IGNvbWJpbmF0aW9uIGluIGNvbGV4aWNvZ3JhcGhpYyBvcmRlciAodGhpcyBpcyBtaXN0YWtlbmx5IGNhbGxlZCBuZXh0UGVybXV0YXRpb24gb24gdGhlIGJpdCB0d2lkZGxpbmcgaGFja3MgcGFnZSlcbmV4cG9ydHMubmV4dENvbWJpbmF0aW9uID0gZnVuY3Rpb24odikge1xuICB2YXIgdCA9IHYgfCAodiAtIDEpO1xuICByZXR1cm4gKHQgKyAxKSB8ICgoKH50ICYgLX50KSAtIDEpID4+PiAoY291bnRUcmFpbGluZ1plcm9zKHYpICsgMSkpO1xufVxuXG4iLCJcInVzZSBzdHJpY3RcIlxuXG52YXIgYml0cyA9IHJlcXVpcmUoXCJiaXQtdHdpZGRsZVwiKVxuXG5mdW5jdGlvbiByb290SW5vcmRlcihuKSB7XG4gIHZhciBwdHJlZSA9IChiaXRzLm5leHRQb3cyKG4rMSk+Pj4xKSAtIDFcbiAgdmFyIGYgICAgID0gbiAtIHB0cmVlXG4gIGlmKGJpdHMubmV4dFBvdzIoZiktMSA+PSBwdHJlZSkge1xuICAgIHJldHVybiBwdHJlZVxuICB9XG4gIHJldHVybiAocHRyZWU+Pj4xKStmXG59XG5leHBvcnRzLnJvb3QgPSByb290SW5vcmRlclxuXG5mdW5jdGlvbiBiZWdpbklub3JkZXIobikge1xuICByZXR1cm4gMFxufVxuZXhwb3J0cy5iZWdpbiA9IGJlZ2luSW5vcmRlclxuXG5mdW5jdGlvbiBlbmRJbm9yZGVyKG4pIHtcbiAgcmV0dXJuIG4tMVxufVxuZXhwb3J0cy5lbmQgPSBlbmRJbm9yZGVyXG5cblxuLy9UaGlzIGlzIHJlYWxseSBob3JyaWJsZSBiZWNhdXNlIG4gaXMgbm90IG5lY2Vzc2FyaWx5IGEgcG93ZXIgb2YgMlxuLy8gSWYgaXQgd2FzLCB3ZSBjb3VsZCBqdXN0IGRvOlxuLy9cbi8vICAgIGhlaWdodCA9IGJpdHMuY291bnRUcmFpbGluZ1plcm9zKH54KVxuLy9cbi8vIEluc3RlYWQsIHdlIGp1c3QgYmluYXJ5IHNlYXJjaCBiZWNhdXNlIGRvaW5nIHRoZSByaWdodCB0aGluZyBoZXJlIGlzIHdheSB0b28gY29tcGxpY2F0ZWQuXG5mdW5jdGlvbiBoZWlnaHRJbm9yZGVyKG4sIHgpIHtcbiAgaWYobiA8PSAwKSB7XG4gICAgcmV0dXJuIDBcbiAgfVxuICB2YXIgciA9IHJvb3RJbm9yZGVyKG4pXG4gIGlmKHggPiByKSB7XG4gICAgcmV0dXJuIGhlaWdodElub3JkZXIobi1yLTEsIHgtci0xKVxuICB9IGVsc2UgaWYoeCA9PT0gcikge1xuICAgIHJldHVybiBiaXRzLmxvZzIobilcbiAgfVxuICByZXR1cm4gaGVpZ2h0SW5vcmRlcihyLCB4KVxufVxuZXhwb3J0cy5oZWlnaHQgPSBoZWlnaHRJbm9yZGVyXG5cbmZ1bmN0aW9uIHByZXZJbm9yZGVyKG4sIHgpIHtcbiAgcmV0dXJuIE1hdGgubWF4KHgtMSwwKVxufVxuZXhwb3J0cy5wcmV2ID0gcHJldklub3JkZXJcblxuZnVuY3Rpb24gbmV4dElub3JkZXIobiwgeCkge1xuICByZXR1cm4gTWF0aC5taW4oeCsxLG4tMSlcbn1cbmV4cG9ydHMubmV4dCA9IG5leHRJbm9yZGVyXG5cblxuLy9UaGUgdmVyc2lvbiBmb3IgbiA9ICgxPDxrKS0xOlxuLy9cbi8vICBwYXJlbnQgPSAoeCAmIH4oMTw8KGgrMSkpKSArICgxPDxoKVxuLy9cbmZ1bmN0aW9uIHBhcmVudElub3JkZXIobiwgeCkge1xuICBpZihuIDw9IDApIHtcbiAgICByZXR1cm4gLTFcbiAgfVxuICB2YXIgciA9IHJvb3RJbm9yZGVyKG4pXG4gIGlmKHggPiByKSB7XG4gICAgdmFyIHEgPSBwYXJlbnRJbm9yZGVyKG4tci0xLCB4LXItMSlcbiAgICBpZihxIDwgMCkge1xuICAgICAgcmV0dXJuIHJcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHEgKyByICsgMVxuICAgIH1cbiAgfSBlbHNlIGlmKHggPT09IHIpIHtcbiAgICByZXR1cm4gLTFcbiAgfVxuICB2YXIgcSA9ICBwYXJlbnRJbm9yZGVyKHIsIHgpXG4gIGlmKHEgPCAwKSB7XG4gICAgcmV0dXJuIHJcbiAgfVxuICByZXR1cm4gcVxufVxuZXhwb3J0cy5wYXJlbnQgPSBwYXJlbnRJbm9yZGVyXG5cblxuLy9BZ2Fpbiwgd2UgZ2V0IHNjcmV3ZWQgYmVjYXVzZSBuIGlzIG5vdCBhIHBvd2VyIG9mIHR3byAtMS4gIElmIGl0IHdhcywgd2UgY291bGQgZG86XG4vL1xuLy8gICAgbGVmdCA9IHggLSAoMSA8PCAoaC0xKSApXG4vL1xuLy8gV2hlcmUgaCBpcyB0aGUgaGVpZ2h0IG9mIHRoZSBub2RlXG4vL1xuZnVuY3Rpb24gbGVmdElub3JkZXIobiwgeCkge1xuICBpZihuIDw9IDApIHtcbiAgICByZXR1cm4gMFxuICB9XG4gIHZhciByID0gcm9vdElub3JkZXIobilcbiAgaWYoeCA+IHIpIHtcbiAgICByZXR1cm4gbGVmdElub3JkZXIobi1yLTEsIHgtci0xKSArIHIgKyAxXG4gIH0gZWxzZSBpZih4ID09PSByKSB7XG4gICAgcmV0dXJuIHJvb3RJbm9yZGVyKHgpXG4gIH1cbiAgcmV0dXJuIGxlZnRJbm9yZGVyKHIsIHgpXG5cbn1cbmV4cG9ydHMubGVmdCA9IGxlZnRJbm9yZGVyXG5cbi8vZm9yIHBvd2VyIG9mIHR3byBtaW51cyBvbmU6XG4vL1xuLy8gICAgcmlnaHQgPSB4ICsgKDE8PChoLTEpKVxuLy9cbmZ1bmN0aW9uIHJpZ2h0SW5vcmRlcihuLCB4KSB7XG4gIGlmKG4gPD0gMCkge1xuICAgIHJldHVybiAwXG4gIH1cbiAgdmFyIHIgPSByb290SW5vcmRlcihuKVxuICBpZih4ID4gcikge1xuICAgIHJldHVybiByaWdodElub3JkZXIobi1yLTEsIHgtci0xKSArIHIgKyAxXG4gIH0gZWxzZSBpZih4ID09PSByKSB7XG4gICAgcmV0dXJuIHJvb3RJbm9yZGVyKG4tci0xKSArIHIgKyAxXG4gIH1cbiAgcmV0dXJuIHJpZ2h0SW5vcmRlcihyLCB4KVxufVxuZXhwb3J0cy5yaWdodCA9IHJpZ2h0SW5vcmRlclxuXG5cbmZ1bmN0aW9uIGxlYWZJbm9yZGVyKG4sIHgpIHtcbiAgcmV0dXJuIGhlaWdodElub3JkZXIobiwgeCkgPT09IDBcbn1cbmV4cG9ydHMubGVhZiA9IGxlYWZJbm9yZGVyXG5cblxuZnVuY3Rpb24gbG9Jbm9yZGVyKG4sIHgpIHtcbiAgbiB8PSAwXG4gIHggfD0gMFxuICB2YXIgbCA9IDBcbiAgd2hpbGUobiA+IDEpIHtcbiAgICB2YXIgciA9IHJvb3RJbm9yZGVyKG4pXG4gICAgaWYoeCA+IHIpIHtcbiAgICAgIGwgKz0gciArIDFcbiAgICAgIG4gLT0gciArIDFcbiAgICAgIHggLT0gciArIDFcbiAgICB9IGVsc2UgaWYoeCA9PT0gcikge1xuICAgICAgYnJlYWtcbiAgICB9IGVsc2Uge1xuICAgICAgbiA9IHJcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGxcbn1cbmV4cG9ydHMubG8gPSBsb0lub3JkZXJcblxuZnVuY3Rpb24gaGlJbm9yZGVyKG4sIHgpIHtcbiAgbiB8PSAwXG4gIHggfD0gMFxuICB2YXIgbCA9IDBcbiAgd2hpbGUobiA+IDEpIHtcbiAgICB2YXIgciA9IHJvb3RJbm9yZGVyKG4pXG4gICAgaWYoeCA+IHIpIHtcbiAgICAgIGwgKz0gciArIDFcbiAgICAgIG4gLT0gciArIDFcbiAgICAgIHggLT0gciArIDFcbiAgICB9IGVsc2UgaWYoeCA9PT0gcikge1xuICAgICAgbCArPSBuLTFcbiAgICAgIGJyZWFrXG4gICAgfSBlbHNlIHtcbiAgICAgIG4gPSByXG4gICAgfVxuICB9XG4gIHJldHVybiBsXG59XG5leHBvcnRzLmhpID0gaGlJbm9yZGVyXG4iLCJcInVzZSBzdHJpY3RcIlxuXG52YXIgY29tcGlsZSA9IHJlcXVpcmUoXCJjd2lzZS1jb21waWxlclwiKVxuXG52YXIgRW1wdHlQcm9jID0ge1xuICBib2R5OiBcIlwiLFxuICBhcmdzOiBbXSxcbiAgdGhpc1ZhcnM6IFtdLFxuICBsb2NhbFZhcnM6IFtdXG59XG5cbmZ1bmN0aW9uIGZpeHVwKHgpIHtcbiAgaWYoIXgpIHtcbiAgICByZXR1cm4gRW1wdHlQcm9jXG4gIH1cbiAgZm9yKHZhciBpPTA7IGk8eC5hcmdzLmxlbmd0aDsgKytpKSB7XG4gICAgdmFyIGEgPSB4LmFyZ3NbaV1cbiAgICBpZihpID09PSAwKSB7XG4gICAgICB4LmFyZ3NbaV0gPSB7bmFtZTogYSwgbHZhbHVlOnRydWUsIHJ2YWx1ZTogISF4LnJ2YWx1ZSwgY291bnQ6eC5jb3VudHx8MSB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHguYXJnc1tpXSA9IHtuYW1lOiBhLCBsdmFsdWU6ZmFsc2UsIHJ2YWx1ZTp0cnVlLCBjb3VudDogMX1cbiAgICB9XG4gIH1cbiAgaWYoIXgudGhpc1ZhcnMpIHtcbiAgICB4LnRoaXNWYXJzID0gW11cbiAgfVxuICBpZigheC5sb2NhbFZhcnMpIHtcbiAgICB4LmxvY2FsVmFycyA9IFtdXG4gIH1cbiAgcmV0dXJuIHhcbn1cblxuZnVuY3Rpb24gcGNvbXBpbGUodXNlcl9hcmdzKSB7XG4gIHJldHVybiBjb21waWxlKHtcbiAgICBhcmdzOiAgICAgdXNlcl9hcmdzLmFyZ3MsXG4gICAgcHJlOiAgICAgIGZpeHVwKHVzZXJfYXJncy5wcmUpLFxuICAgIGJvZHk6ICAgICBmaXh1cCh1c2VyX2FyZ3MuYm9keSksXG4gICAgcG9zdDogICAgIGZpeHVwKHVzZXJfYXJncy5wcm9jKSxcbiAgICBmdW5jTmFtZTogdXNlcl9hcmdzLmZ1bmNOYW1lXG4gIH0pXG59XG5cbmZ1bmN0aW9uIG1ha2VPcCh1c2VyX2FyZ3MpIHtcbiAgdmFyIGFyZ3MgPSBbXVxuICBmb3IodmFyIGk9MDsgaTx1c2VyX2FyZ3MuYXJncy5sZW5ndGg7ICsraSkge1xuICAgIGFyZ3MucHVzaChcImFcIitpKVxuICB9XG4gIHZhciB3cmFwcGVyID0gbmV3IEZ1bmN0aW9uKFwiUFwiLCBbXG4gICAgXCJyZXR1cm4gZnVuY3Rpb24gXCIsIHVzZXJfYXJncy5mdW5jTmFtZSwgXCJfbmRhcnJheW9wcyhcIiwgYXJncy5qb2luKFwiLFwiKSwgXCIpIHtQKFwiLCBhcmdzLmpvaW4oXCIsXCIpLCBcIik7cmV0dXJuIGEwfVwiXG4gIF0uam9pbihcIlwiKSlcbiAgcmV0dXJuIHdyYXBwZXIocGNvbXBpbGUodXNlcl9hcmdzKSlcbn1cblxudmFyIGFzc2lnbl9vcHMgPSB7XG4gIGFkZDogIFwiK1wiLFxuICBzdWI6ICBcIi1cIixcbiAgbXVsOiAgXCIqXCIsXG4gIGRpdjogIFwiL1wiLFxuICBtb2Q6ICBcIiVcIixcbiAgYmFuZDogXCImXCIsXG4gIGJvcjogIFwifFwiLFxuICBieG9yOiBcIl5cIixcbiAgbHNoaWZ0OiBcIjw8XCIsXG4gIHJzaGlmdDogXCI+PlwiLFxuICBycnNoaWZ0OiBcIj4+PlwiXG59XG47KGZ1bmN0aW9uKCl7XG4gIGZvcih2YXIgaWQgaW4gYXNzaWduX29wcykge1xuICAgIHZhciBvcCA9IGFzc2lnbl9vcHNbaWRdXG4gICAgZXhwb3J0c1tpZF0gPSBtYWtlT3Aoe1xuICAgICAgYXJnczogW1wiYXJyYXlcIixcImFycmF5XCIsXCJhcnJheVwiXSxcbiAgICAgIGJvZHk6IHthcmdzOltcImFcIixcImJcIixcImNcIl0sXG4gICAgICAgICAgICAgYm9keTogXCJhPWJcIitvcCtcImNcIn0sXG4gICAgICBmdW5jTmFtZTogaWRcbiAgICB9KVxuICAgIGV4cG9ydHNbaWQrXCJlcVwiXSA9IG1ha2VPcCh7XG4gICAgICBhcmdzOiBbXCJhcnJheVwiLFwiYXJyYXlcIl0sXG4gICAgICBib2R5OiB7YXJnczpbXCJhXCIsXCJiXCJdLFxuICAgICAgICAgICAgIGJvZHk6XCJhXCIrb3ArXCI9YlwifSxcbiAgICAgIHJ2YWx1ZTogdHJ1ZSxcbiAgICAgIGZ1bmNOYW1lOiBpZCtcImVxXCJcbiAgICB9KVxuICAgIGV4cG9ydHNbaWQrXCJzXCJdID0gbWFrZU9wKHtcbiAgICAgIGFyZ3M6IFtcImFycmF5XCIsIFwiYXJyYXlcIiwgXCJzY2FsYXJcIl0sXG4gICAgICBib2R5OiB7YXJnczpbXCJhXCIsXCJiXCIsXCJzXCJdLFxuICAgICAgICAgICAgIGJvZHk6XCJhPWJcIitvcCtcInNcIn0sXG4gICAgICBmdW5jTmFtZTogaWQrXCJzXCJcbiAgICB9KVxuICAgIGV4cG9ydHNbaWQrXCJzZXFcIl0gPSBtYWtlT3Aoe1xuICAgICAgYXJnczogW1wiYXJyYXlcIixcInNjYWxhclwiXSxcbiAgICAgIGJvZHk6IHthcmdzOltcImFcIixcInNcIl0sXG4gICAgICAgICAgICAgYm9keTpcImFcIitvcCtcIj1zXCJ9LFxuICAgICAgcnZhbHVlOiB0cnVlLFxuICAgICAgZnVuY05hbWU6IGlkK1wic2VxXCJcbiAgICB9KVxuICB9XG59KSgpO1xuXG52YXIgdW5hcnlfb3BzID0ge1xuICBub3Q6IFwiIVwiLFxuICBibm90OiBcIn5cIixcbiAgbmVnOiBcIi1cIixcbiAgcmVjaXA6IFwiMS4wL1wiXG59XG47KGZ1bmN0aW9uKCl7XG4gIGZvcih2YXIgaWQgaW4gdW5hcnlfb3BzKSB7XG4gICAgdmFyIG9wID0gdW5hcnlfb3BzW2lkXVxuICAgIGV4cG9ydHNbaWRdID0gbWFrZU9wKHtcbiAgICAgIGFyZ3M6IFtcImFycmF5XCIsIFwiYXJyYXlcIl0sXG4gICAgICBib2R5OiB7YXJnczpbXCJhXCIsXCJiXCJdLFxuICAgICAgICAgICAgIGJvZHk6XCJhPVwiK29wK1wiYlwifSxcbiAgICAgIGZ1bmNOYW1lOiBpZFxuICAgIH0pXG4gICAgZXhwb3J0c1tpZCtcImVxXCJdID0gbWFrZU9wKHtcbiAgICAgIGFyZ3M6IFtcImFycmF5XCJdLFxuICAgICAgYm9keToge2FyZ3M6W1wiYVwiXSxcbiAgICAgICAgICAgICBib2R5OlwiYT1cIitvcCtcImFcIn0sXG4gICAgICBydmFsdWU6IHRydWUsXG4gICAgICBjb3VudDogMixcbiAgICAgIGZ1bmNOYW1lOiBpZCtcImVxXCJcbiAgICB9KVxuICB9XG59KSgpO1xuXG52YXIgYmluYXJ5X29wcyA9IHtcbiAgYW5kOiBcIiYmXCIsXG4gIG9yOiBcInx8XCIsXG4gIGVxOiBcIj09PVwiLFxuICBuZXE6IFwiIT09XCIsXG4gIGx0OiBcIjxcIixcbiAgZ3Q6IFwiPlwiLFxuICBsZXE6IFwiPD1cIixcbiAgZ2VxOiBcIj49XCJcbn1cbjsoZnVuY3Rpb24oKSB7XG4gIGZvcih2YXIgaWQgaW4gYmluYXJ5X29wcykge1xuICAgIHZhciBvcCA9IGJpbmFyeV9vcHNbaWRdXG4gICAgZXhwb3J0c1tpZF0gPSBtYWtlT3Aoe1xuICAgICAgYXJnczogW1wiYXJyYXlcIixcImFycmF5XCIsXCJhcnJheVwiXSxcbiAgICAgIGJvZHk6IHthcmdzOltcImFcIiwgXCJiXCIsIFwiY1wiXSxcbiAgICAgICAgICAgICBib2R5OlwiYT1iXCIrb3ArXCJjXCJ9LFxuICAgICAgZnVuY05hbWU6IGlkXG4gICAgfSlcbiAgICBleHBvcnRzW2lkK1wic1wiXSA9IG1ha2VPcCh7XG4gICAgICBhcmdzOiBbXCJhcnJheVwiLFwiYXJyYXlcIixcInNjYWxhclwiXSxcbiAgICAgIGJvZHk6IHthcmdzOltcImFcIiwgXCJiXCIsIFwic1wiXSxcbiAgICAgICAgICAgICBib2R5OlwiYT1iXCIrb3ArXCJzXCJ9LFxuICAgICAgZnVuY05hbWU6IGlkK1wic1wiXG4gICAgfSlcbiAgICBleHBvcnRzW2lkK1wiZXFcIl0gPSBtYWtlT3Aoe1xuICAgICAgYXJnczogW1wiYXJyYXlcIiwgXCJhcnJheVwiXSxcbiAgICAgIGJvZHk6IHthcmdzOltcImFcIiwgXCJiXCJdLFxuICAgICAgICAgICAgIGJvZHk6XCJhPWFcIitvcCtcImJcIn0sXG4gICAgICBydmFsdWU6dHJ1ZSxcbiAgICAgIGNvdW50OjIsXG4gICAgICBmdW5jTmFtZTogaWQrXCJlcVwiXG4gICAgfSlcbiAgICBleHBvcnRzW2lkK1wic2VxXCJdID0gbWFrZU9wKHtcbiAgICAgIGFyZ3M6IFtcImFycmF5XCIsIFwic2NhbGFyXCJdLFxuICAgICAgYm9keToge2FyZ3M6W1wiYVwiLFwic1wiXSxcbiAgICAgICAgICAgICBib2R5OlwiYT1hXCIrb3ArXCJzXCJ9LFxuICAgICAgcnZhbHVlOnRydWUsXG4gICAgICBjb3VudDoyLFxuICAgICAgZnVuY05hbWU6IGlkK1wic2VxXCJcbiAgICB9KVxuICB9XG59KSgpO1xuXG52YXIgbWF0aF91bmFyeSA9IFtcbiAgXCJhYnNcIixcbiAgXCJhY29zXCIsXG4gIFwiYXNpblwiLFxuICBcImF0YW5cIixcbiAgXCJjZWlsXCIsXG4gIFwiY29zXCIsXG4gIFwiZXhwXCIsXG4gIFwiZmxvb3JcIixcbiAgXCJsb2dcIixcbiAgXCJyb3VuZFwiLFxuICBcInNpblwiLFxuICBcInNxcnRcIixcbiAgXCJ0YW5cIlxuXVxuOyhmdW5jdGlvbigpIHtcbiAgZm9yKHZhciBpPTA7IGk8bWF0aF91bmFyeS5sZW5ndGg7ICsraSkge1xuICAgIHZhciBmID0gbWF0aF91bmFyeVtpXVxuICAgIGV4cG9ydHNbZl0gPSBtYWtlT3Aoe1xuICAgICAgICAgICAgICAgICAgICBhcmdzOiBbXCJhcnJheVwiLCBcImFycmF5XCJdLFxuICAgICAgICAgICAgICAgICAgICBwcmU6IHthcmdzOltdLCBib2R5OlwidGhpc19mPU1hdGguXCIrZiwgdGhpc1ZhcnM6W1widGhpc19mXCJdfSxcbiAgICAgICAgICAgICAgICAgICAgYm9keToge2FyZ3M6W1wiYVwiLFwiYlwiXSwgYm9keTpcImE9dGhpc19mKGIpXCIsIHRoaXNWYXJzOltcInRoaXNfZlwiXX0sXG4gICAgICAgICAgICAgICAgICAgIGZ1bmNOYW1lOiBmXG4gICAgICAgICAgICAgICAgICB9KVxuICAgIGV4cG9ydHNbZitcImVxXCJdID0gbWFrZU9wKHtcbiAgICAgICAgICAgICAgICAgICAgICBhcmdzOiBbXCJhcnJheVwiXSxcbiAgICAgICAgICAgICAgICAgICAgICBwcmU6IHthcmdzOltdLCBib2R5OlwidGhpc19mPU1hdGguXCIrZiwgdGhpc1ZhcnM6W1widGhpc19mXCJdfSxcbiAgICAgICAgICAgICAgICAgICAgICBib2R5OiB7YXJnczogW1wiYVwiXSwgYm9keTpcImE9dGhpc19mKGEpXCIsIHRoaXNWYXJzOltcInRoaXNfZlwiXX0sXG4gICAgICAgICAgICAgICAgICAgICAgcnZhbHVlOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgIGNvdW50OiAyLFxuICAgICAgICAgICAgICAgICAgICAgIGZ1bmNOYW1lOiBmK1wiZXFcIlxuICAgICAgICAgICAgICAgICAgICB9KVxuICB9XG59KSgpO1xuXG52YXIgbWF0aF9jb21tID0gW1xuICBcIm1heFwiLFxuICBcIm1pblwiLFxuICBcImF0YW4yXCIsXG4gIFwicG93XCJcbl1cbjsoZnVuY3Rpb24oKXtcbiAgZm9yKHZhciBpPTA7IGk8bWF0aF9jb21tLmxlbmd0aDsgKytpKSB7XG4gICAgdmFyIGY9IG1hdGhfY29tbVtpXVxuICAgIGV4cG9ydHNbZl0gPSBtYWtlT3Aoe1xuICAgICAgICAgICAgICAgICAgYXJnczpbXCJhcnJheVwiLCBcImFycmF5XCIsIFwiYXJyYXlcIl0sXG4gICAgICAgICAgICAgICAgICBwcmU6IHthcmdzOltdLCBib2R5OlwidGhpc19mPU1hdGguXCIrZiwgdGhpc1ZhcnM6W1widGhpc19mXCJdfSxcbiAgICAgICAgICAgICAgICAgIGJvZHk6IHthcmdzOltcImFcIixcImJcIixcImNcIl0sIGJvZHk6XCJhPXRoaXNfZihiLGMpXCIsIHRoaXNWYXJzOltcInRoaXNfZlwiXX0sXG4gICAgICAgICAgICAgICAgICBmdW5jTmFtZTogZlxuICAgICAgICAgICAgICAgIH0pXG4gICAgZXhwb3J0c1tmK1wic1wiXSA9IG1ha2VPcCh7XG4gICAgICAgICAgICAgICAgICBhcmdzOltcImFycmF5XCIsIFwiYXJyYXlcIiwgXCJzY2FsYXJcIl0sXG4gICAgICAgICAgICAgICAgICBwcmU6IHthcmdzOltdLCBib2R5OlwidGhpc19mPU1hdGguXCIrZiwgdGhpc1ZhcnM6W1widGhpc19mXCJdfSxcbiAgICAgICAgICAgICAgICAgIGJvZHk6IHthcmdzOltcImFcIixcImJcIixcImNcIl0sIGJvZHk6XCJhPXRoaXNfZihiLGMpXCIsIHRoaXNWYXJzOltcInRoaXNfZlwiXX0sXG4gICAgICAgICAgICAgICAgICBmdW5jTmFtZTogZitcInNcIlxuICAgICAgICAgICAgICAgICAgfSlcbiAgICBleHBvcnRzW2YrXCJlcVwiXSA9IG1ha2VPcCh7IGFyZ3M6W1wiYXJyYXlcIiwgXCJhcnJheVwiXSxcbiAgICAgICAgICAgICAgICAgIHByZToge2FyZ3M6W10sIGJvZHk6XCJ0aGlzX2Y9TWF0aC5cIitmLCB0aGlzVmFyczpbXCJ0aGlzX2ZcIl19LFxuICAgICAgICAgICAgICAgICAgYm9keToge2FyZ3M6W1wiYVwiLFwiYlwiXSwgYm9keTpcImE9dGhpc19mKGEsYilcIiwgdGhpc1ZhcnM6W1widGhpc19mXCJdfSxcbiAgICAgICAgICAgICAgICAgIHJ2YWx1ZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgIGNvdW50OiAyLFxuICAgICAgICAgICAgICAgICAgZnVuY05hbWU6IGYrXCJlcVwiXG4gICAgICAgICAgICAgICAgICB9KVxuICAgIGV4cG9ydHNbZitcInNlcVwiXSA9IG1ha2VPcCh7IGFyZ3M6W1wiYXJyYXlcIiwgXCJzY2FsYXJcIl0sXG4gICAgICAgICAgICAgICAgICBwcmU6IHthcmdzOltdLCBib2R5OlwidGhpc19mPU1hdGguXCIrZiwgdGhpc1ZhcnM6W1widGhpc19mXCJdfSxcbiAgICAgICAgICAgICAgICAgIGJvZHk6IHthcmdzOltcImFcIixcImJcIl0sIGJvZHk6XCJhPXRoaXNfZihhLGIpXCIsIHRoaXNWYXJzOltcInRoaXNfZlwiXX0sXG4gICAgICAgICAgICAgICAgICBydmFsdWU6dHJ1ZSxcbiAgICAgICAgICAgICAgICAgIGNvdW50OjIsXG4gICAgICAgICAgICAgICAgICBmdW5jTmFtZTogZitcInNlcVwiXG4gICAgICAgICAgICAgICAgICB9KVxuICB9XG59KSgpO1xuXG52YXIgbWF0aF9ub25jb21tID0gW1xuICBcImF0YW4yXCIsXG4gIFwicG93XCJcbl1cbjsoZnVuY3Rpb24oKXtcbiAgZm9yKHZhciBpPTA7IGk8bWF0aF9ub25jb21tLmxlbmd0aDsgKytpKSB7XG4gICAgdmFyIGY9IG1hdGhfbm9uY29tbVtpXVxuICAgIGV4cG9ydHNbZitcIm9wXCJdID0gbWFrZU9wKHtcbiAgICAgICAgICAgICAgICAgIGFyZ3M6W1wiYXJyYXlcIiwgXCJhcnJheVwiLCBcImFycmF5XCJdLFxuICAgICAgICAgICAgICAgICAgcHJlOiB7YXJnczpbXSwgYm9keTpcInRoaXNfZj1NYXRoLlwiK2YsIHRoaXNWYXJzOltcInRoaXNfZlwiXX0sXG4gICAgICAgICAgICAgICAgICBib2R5OiB7YXJnczpbXCJhXCIsXCJiXCIsXCJjXCJdLCBib2R5OlwiYT10aGlzX2YoYyxiKVwiLCB0aGlzVmFyczpbXCJ0aGlzX2ZcIl19LFxuICAgICAgICAgICAgICAgICAgZnVuY05hbWU6IGYrXCJvcFwiXG4gICAgICAgICAgICAgICAgfSlcbiAgICBleHBvcnRzW2YrXCJvcHNcIl0gPSBtYWtlT3Aoe1xuICAgICAgICAgICAgICAgICAgYXJnczpbXCJhcnJheVwiLCBcImFycmF5XCIsIFwic2NhbGFyXCJdLFxuICAgICAgICAgICAgICAgICAgcHJlOiB7YXJnczpbXSwgYm9keTpcInRoaXNfZj1NYXRoLlwiK2YsIHRoaXNWYXJzOltcInRoaXNfZlwiXX0sXG4gICAgICAgICAgICAgICAgICBib2R5OiB7YXJnczpbXCJhXCIsXCJiXCIsXCJjXCJdLCBib2R5OlwiYT10aGlzX2YoYyxiKVwiLCB0aGlzVmFyczpbXCJ0aGlzX2ZcIl19LFxuICAgICAgICAgICAgICAgICAgZnVuY05hbWU6IGYrXCJvcHNcIlxuICAgICAgICAgICAgICAgICAgfSlcbiAgICBleHBvcnRzW2YrXCJvcGVxXCJdID0gbWFrZU9wKHsgYXJnczpbXCJhcnJheVwiLCBcImFycmF5XCJdLFxuICAgICAgICAgICAgICAgICAgcHJlOiB7YXJnczpbXSwgYm9keTpcInRoaXNfZj1NYXRoLlwiK2YsIHRoaXNWYXJzOltcInRoaXNfZlwiXX0sXG4gICAgICAgICAgICAgICAgICBib2R5OiB7YXJnczpbXCJhXCIsXCJiXCJdLCBib2R5OlwiYT10aGlzX2YoYixhKVwiLCB0aGlzVmFyczpbXCJ0aGlzX2ZcIl19LFxuICAgICAgICAgICAgICAgICAgcnZhbHVlOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgY291bnQ6IDIsXG4gICAgICAgICAgICAgICAgICBmdW5jTmFtZTogZitcIm9wZXFcIlxuICAgICAgICAgICAgICAgICAgfSlcbiAgICBleHBvcnRzW2YrXCJvcHNlcVwiXSA9IG1ha2VPcCh7IGFyZ3M6W1wiYXJyYXlcIiwgXCJzY2FsYXJcIl0sXG4gICAgICAgICAgICAgICAgICBwcmU6IHthcmdzOltdLCBib2R5OlwidGhpc19mPU1hdGguXCIrZiwgdGhpc1ZhcnM6W1widGhpc19mXCJdfSxcbiAgICAgICAgICAgICAgICAgIGJvZHk6IHthcmdzOltcImFcIixcImJcIl0sIGJvZHk6XCJhPXRoaXNfZihiLGEpXCIsIHRoaXNWYXJzOltcInRoaXNfZlwiXX0sXG4gICAgICAgICAgICAgICAgICBydmFsdWU6dHJ1ZSxcbiAgICAgICAgICAgICAgICAgIGNvdW50OjIsXG4gICAgICAgICAgICAgICAgICBmdW5jTmFtZTogZitcIm9wc2VxXCJcbiAgICAgICAgICAgICAgICAgIH0pXG4gIH1cbn0pKCk7XG5cbmV4cG9ydHMuYW55ID0gY29tcGlsZSh7XG4gIGFyZ3M6W1wiYXJyYXlcIl0sXG4gIHByZTogRW1wdHlQcm9jLFxuICBib2R5OiB7YXJnczpbe25hbWU6XCJhXCIsIGx2YWx1ZTpmYWxzZSwgcnZhbHVlOnRydWUsIGNvdW50OjF9XSwgYm9keTogXCJpZihhKXtyZXR1cm4gdHJ1ZX1cIiwgbG9jYWxWYXJzOiBbXSwgdGhpc1ZhcnM6IFtdfSxcbiAgcG9zdDoge2FyZ3M6W10sIGxvY2FsVmFyczpbXSwgdGhpc1ZhcnM6W10sIGJvZHk6XCJyZXR1cm4gZmFsc2VcIn0sXG4gIGZ1bmNOYW1lOiBcImFueVwiXG59KVxuXG5leHBvcnRzLmFsbCA9IGNvbXBpbGUoe1xuICBhcmdzOltcImFycmF5XCJdLFxuICBwcmU6IEVtcHR5UHJvYyxcbiAgYm9keToge2FyZ3M6W3tuYW1lOlwieFwiLCBsdmFsdWU6ZmFsc2UsIHJ2YWx1ZTp0cnVlLCBjb3VudDoxfV0sIGJvZHk6IFwiaWYoIXgpe3JldHVybiBmYWxzZX1cIiwgbG9jYWxWYXJzOiBbXSwgdGhpc1ZhcnM6IFtdfSxcbiAgcG9zdDoge2FyZ3M6W10sIGxvY2FsVmFyczpbXSwgdGhpc1ZhcnM6W10sIGJvZHk6XCJyZXR1cm4gdHJ1ZVwifSxcbiAgZnVuY05hbWU6IFwiYWxsXCJcbn0pXG5cbmV4cG9ydHMuc3VtID0gY29tcGlsZSh7XG4gIGFyZ3M6W1wiYXJyYXlcIl0sXG4gIHByZToge2FyZ3M6W10sIGxvY2FsVmFyczpbXSwgdGhpc1ZhcnM6W1widGhpc19zXCJdLCBib2R5OlwidGhpc19zPTBcIn0sXG4gIGJvZHk6IHthcmdzOlt7bmFtZTpcImFcIiwgbHZhbHVlOmZhbHNlLCBydmFsdWU6dHJ1ZSwgY291bnQ6MX1dLCBib2R5OiBcInRoaXNfcys9YVwiLCBsb2NhbFZhcnM6IFtdLCB0aGlzVmFyczogW1widGhpc19zXCJdfSxcbiAgcG9zdDoge2FyZ3M6W10sIGxvY2FsVmFyczpbXSwgdGhpc1ZhcnM6W1widGhpc19zXCJdLCBib2R5OlwicmV0dXJuIHRoaXNfc1wifSxcbiAgZnVuY05hbWU6IFwic3VtXCJcbn0pXG5cbmV4cG9ydHMucHJvZCA9IGNvbXBpbGUoe1xuICBhcmdzOltcImFycmF5XCJdLFxuICBwcmU6IHthcmdzOltdLCBsb2NhbFZhcnM6W10sIHRoaXNWYXJzOltcInRoaXNfc1wiXSwgYm9keTpcInRoaXNfcz0xXCJ9LFxuICBib2R5OiB7YXJnczpbe25hbWU6XCJhXCIsIGx2YWx1ZTpmYWxzZSwgcnZhbHVlOnRydWUsIGNvdW50OjF9XSwgYm9keTogXCJ0aGlzX3MqPWFcIiwgbG9jYWxWYXJzOiBbXSwgdGhpc1ZhcnM6IFtcInRoaXNfc1wiXX0sXG4gIHBvc3Q6IHthcmdzOltdLCBsb2NhbFZhcnM6W10sIHRoaXNWYXJzOltcInRoaXNfc1wiXSwgYm9keTpcInJldHVybiB0aGlzX3NcIn0sXG4gIGZ1bmNOYW1lOiBcInByb2RcIlxufSlcblxuZXhwb3J0cy5ub3JtMnNxdWFyZWQgPSBjb21waWxlKHtcbiAgYXJnczpbXCJhcnJheVwiXSxcbiAgcHJlOiB7YXJnczpbXSwgbG9jYWxWYXJzOltdLCB0aGlzVmFyczpbXCJ0aGlzX3NcIl0sIGJvZHk6XCJ0aGlzX3M9MFwifSxcbiAgYm9keToge2FyZ3M6W3tuYW1lOlwiYVwiLCBsdmFsdWU6ZmFsc2UsIHJ2YWx1ZTp0cnVlLCBjb3VudDoyfV0sIGJvZHk6IFwidGhpc19zKz1hKmFcIiwgbG9jYWxWYXJzOiBbXSwgdGhpc1ZhcnM6IFtcInRoaXNfc1wiXX0sXG4gIHBvc3Q6IHthcmdzOltdLCBsb2NhbFZhcnM6W10sIHRoaXNWYXJzOltcInRoaXNfc1wiXSwgYm9keTpcInJldHVybiB0aGlzX3NcIn0sXG4gIGZ1bmNOYW1lOiBcIm5vcm0yc3F1YXJlZFwiXG59KVxuICBcbmV4cG9ydHMubm9ybTIgPSBjb21waWxlKHtcbiAgYXJnczpbXCJhcnJheVwiXSxcbiAgcHJlOiB7YXJnczpbXSwgbG9jYWxWYXJzOltdLCB0aGlzVmFyczpbXCJ0aGlzX3NcIl0sIGJvZHk6XCJ0aGlzX3M9MFwifSxcbiAgYm9keToge2FyZ3M6W3tuYW1lOlwiYVwiLCBsdmFsdWU6ZmFsc2UsIHJ2YWx1ZTp0cnVlLCBjb3VudDoyfV0sIGJvZHk6IFwidGhpc19zKz1hKmFcIiwgbG9jYWxWYXJzOiBbXSwgdGhpc1ZhcnM6IFtcInRoaXNfc1wiXX0sXG4gIHBvc3Q6IHthcmdzOltdLCBsb2NhbFZhcnM6W10sIHRoaXNWYXJzOltcInRoaXNfc1wiXSwgYm9keTpcInJldHVybiBNYXRoLnNxcnQodGhpc19zKVwifSxcbiAgZnVuY05hbWU6IFwibm9ybTJcIlxufSlcbiAgXG5cbmV4cG9ydHMubm9ybWluZiA9IGNvbXBpbGUoe1xuICBhcmdzOltcImFycmF5XCJdLFxuICBwcmU6IHthcmdzOltdLCBsb2NhbFZhcnM6W10sIHRoaXNWYXJzOltcInRoaXNfc1wiXSwgYm9keTpcInRoaXNfcz0wXCJ9LFxuICBib2R5OiB7YXJnczpbe25hbWU6XCJhXCIsIGx2YWx1ZTpmYWxzZSwgcnZhbHVlOnRydWUsIGNvdW50OjR9XSwgYm9keTpcImlmKC1hPnRoaXNfcyl7dGhpc19zPS1hfWVsc2UgaWYoYT50aGlzX3Mpe3RoaXNfcz1hfVwiLCBsb2NhbFZhcnM6IFtdLCB0aGlzVmFyczogW1widGhpc19zXCJdfSxcbiAgcG9zdDoge2FyZ3M6W10sIGxvY2FsVmFyczpbXSwgdGhpc1ZhcnM6W1widGhpc19zXCJdLCBib2R5OlwicmV0dXJuIHRoaXNfc1wifSxcbiAgZnVuY05hbWU6IFwibm9ybWluZlwiXG59KVxuXG5leHBvcnRzLm5vcm0xID0gY29tcGlsZSh7XG4gIGFyZ3M6W1wiYXJyYXlcIl0sXG4gIHByZToge2FyZ3M6W10sIGxvY2FsVmFyczpbXSwgdGhpc1ZhcnM6W1widGhpc19zXCJdLCBib2R5OlwidGhpc19zPTBcIn0sXG4gIGJvZHk6IHthcmdzOlt7bmFtZTpcImFcIiwgbHZhbHVlOmZhbHNlLCBydmFsdWU6dHJ1ZSwgY291bnQ6M31dLCBib2R5OiBcInRoaXNfcys9YTwwPy1hOmFcIiwgbG9jYWxWYXJzOiBbXSwgdGhpc1ZhcnM6IFtcInRoaXNfc1wiXX0sXG4gIHBvc3Q6IHthcmdzOltdLCBsb2NhbFZhcnM6W10sIHRoaXNWYXJzOltcInRoaXNfc1wiXSwgYm9keTpcInJldHVybiB0aGlzX3NcIn0sXG4gIGZ1bmNOYW1lOiBcIm5vcm0xXCJcbn0pXG5cbmV4cG9ydHMuc3VwID0gY29tcGlsZSh7XG4gIGFyZ3M6IFsgXCJhcnJheVwiIF0sXG4gIHByZTpcbiAgIHsgYm9keTogXCJ0aGlzX2g9LUluZmluaXR5XCIsXG4gICAgIGFyZ3M6IFtdLFxuICAgICB0aGlzVmFyczogWyBcInRoaXNfaFwiIF0sXG4gICAgIGxvY2FsVmFyczogW10gfSxcbiAgYm9keTpcbiAgIHsgYm9keTogXCJpZihfaW5saW5lXzFfYXJnMF8+dGhpc19oKXRoaXNfaD1faW5saW5lXzFfYXJnMF9cIixcbiAgICAgYXJnczogW3tcIm5hbWVcIjpcIl9pbmxpbmVfMV9hcmcwX1wiLFwibHZhbHVlXCI6ZmFsc2UsXCJydmFsdWVcIjp0cnVlLFwiY291bnRcIjoyfSBdLFxuICAgICB0aGlzVmFyczogWyBcInRoaXNfaFwiIF0sXG4gICAgIGxvY2FsVmFyczogW10gfSxcbiAgcG9zdDpcbiAgIHsgYm9keTogXCJyZXR1cm4gdGhpc19oXCIsXG4gICAgIGFyZ3M6IFtdLFxuICAgICB0aGlzVmFyczogWyBcInRoaXNfaFwiIF0sXG4gICAgIGxvY2FsVmFyczogW10gfVxuIH0pXG5cbmV4cG9ydHMuaW5mID0gY29tcGlsZSh7XG4gIGFyZ3M6IFsgXCJhcnJheVwiIF0sXG4gIHByZTpcbiAgIHsgYm9keTogXCJ0aGlzX2g9SW5maW5pdHlcIixcbiAgICAgYXJnczogW10sXG4gICAgIHRoaXNWYXJzOiBbIFwidGhpc19oXCIgXSxcbiAgICAgbG9jYWxWYXJzOiBbXSB9LFxuICBib2R5OlxuICAgeyBib2R5OiBcImlmKF9pbmxpbmVfMV9hcmcwXzx0aGlzX2gpdGhpc19oPV9pbmxpbmVfMV9hcmcwX1wiLFxuICAgICBhcmdzOiBbe1wibmFtZVwiOlwiX2lubGluZV8xX2FyZzBfXCIsXCJsdmFsdWVcIjpmYWxzZSxcInJ2YWx1ZVwiOnRydWUsXCJjb3VudFwiOjJ9IF0sXG4gICAgIHRoaXNWYXJzOiBbIFwidGhpc19oXCIgXSxcbiAgICAgbG9jYWxWYXJzOiBbXSB9LFxuICBwb3N0OlxuICAgeyBib2R5OiBcInJldHVybiB0aGlzX2hcIixcbiAgICAgYXJnczogW10sXG4gICAgIHRoaXNWYXJzOiBbIFwidGhpc19oXCIgXSxcbiAgICAgbG9jYWxWYXJzOiBbXSB9XG4gfSlcblxuZXhwb3J0cy5hcmdtaW4gPSBjb21waWxlKHtcbiAgYXJnczpbXCJpbmRleFwiLFwiYXJyYXlcIixcInNoYXBlXCJdLFxuICBwcmU6e1xuICAgIGJvZHk6XCJ7dGhpc192PUluZmluaXR5O3RoaXNfaT1faW5saW5lXzBfYXJnMl8uc2xpY2UoMCl9XCIsXG4gICAgYXJnczpbXG4gICAgICB7bmFtZTpcIl9pbmxpbmVfMF9hcmcwX1wiLGx2YWx1ZTpmYWxzZSxydmFsdWU6ZmFsc2UsY291bnQ6MH0sXG4gICAgICB7bmFtZTpcIl9pbmxpbmVfMF9hcmcxX1wiLGx2YWx1ZTpmYWxzZSxydmFsdWU6ZmFsc2UsY291bnQ6MH0sXG4gICAgICB7bmFtZTpcIl9pbmxpbmVfMF9hcmcyX1wiLGx2YWx1ZTpmYWxzZSxydmFsdWU6dHJ1ZSxjb3VudDoxfVxuICAgICAgXSxcbiAgICB0aGlzVmFyczpbXCJ0aGlzX2lcIixcInRoaXNfdlwiXSxcbiAgICBsb2NhbFZhcnM6W119LFxuICBib2R5OntcbiAgICBib2R5Olwie2lmKF9pbmxpbmVfMV9hcmcxXzx0aGlzX3Ype3RoaXNfdj1faW5saW5lXzFfYXJnMV87Zm9yKHZhciBfaW5saW5lXzFfaz0wO19pbmxpbmVfMV9rPF9pbmxpbmVfMV9hcmcwXy5sZW5ndGg7KytfaW5saW5lXzFfayl7dGhpc19pW19pbmxpbmVfMV9rXT1faW5saW5lXzFfYXJnMF9bX2lubGluZV8xX2tdfX19XCIsXG4gICAgYXJnczpbXG4gICAgICB7bmFtZTpcIl9pbmxpbmVfMV9hcmcwX1wiLGx2YWx1ZTpmYWxzZSxydmFsdWU6dHJ1ZSxjb3VudDoyfSxcbiAgICAgIHtuYW1lOlwiX2lubGluZV8xX2FyZzFfXCIsbHZhbHVlOmZhbHNlLHJ2YWx1ZTp0cnVlLGNvdW50OjJ9XSxcbiAgICB0aGlzVmFyczpbXCJ0aGlzX2lcIixcInRoaXNfdlwiXSxcbiAgICBsb2NhbFZhcnM6W1wiX2lubGluZV8xX2tcIl19LFxuICBwb3N0OntcbiAgICBib2R5Olwie3JldHVybiB0aGlzX2l9XCIsXG4gICAgYXJnczpbXSxcbiAgICB0aGlzVmFyczpbXCJ0aGlzX2lcIl0sXG4gICAgbG9jYWxWYXJzOltdfVxufSlcblxuZXhwb3J0cy5hcmdtYXggPSBjb21waWxlKHtcbiAgYXJnczpbXCJpbmRleFwiLFwiYXJyYXlcIixcInNoYXBlXCJdLFxuICBwcmU6e1xuICAgIGJvZHk6XCJ7dGhpc192PS1JbmZpbml0eTt0aGlzX2k9X2lubGluZV8wX2FyZzJfLnNsaWNlKDApfVwiLFxuICAgIGFyZ3M6W1xuICAgICAge25hbWU6XCJfaW5saW5lXzBfYXJnMF9cIixsdmFsdWU6ZmFsc2UscnZhbHVlOmZhbHNlLGNvdW50OjB9LFxuICAgICAge25hbWU6XCJfaW5saW5lXzBfYXJnMV9cIixsdmFsdWU6ZmFsc2UscnZhbHVlOmZhbHNlLGNvdW50OjB9LFxuICAgICAge25hbWU6XCJfaW5saW5lXzBfYXJnMl9cIixsdmFsdWU6ZmFsc2UscnZhbHVlOnRydWUsY291bnQ6MX1cbiAgICAgIF0sXG4gICAgdGhpc1ZhcnM6W1widGhpc19pXCIsXCJ0aGlzX3ZcIl0sXG4gICAgbG9jYWxWYXJzOltdfSxcbiAgYm9keTp7XG4gICAgYm9keTpcIntpZihfaW5saW5lXzFfYXJnMV8+dGhpc192KXt0aGlzX3Y9X2lubGluZV8xX2FyZzFfO2Zvcih2YXIgX2lubGluZV8xX2s9MDtfaW5saW5lXzFfazxfaW5saW5lXzFfYXJnMF8ubGVuZ3RoOysrX2lubGluZV8xX2spe3RoaXNfaVtfaW5saW5lXzFfa109X2lubGluZV8xX2FyZzBfW19pbmxpbmVfMV9rXX19fVwiLFxuICAgIGFyZ3M6W1xuICAgICAge25hbWU6XCJfaW5saW5lXzFfYXJnMF9cIixsdmFsdWU6ZmFsc2UscnZhbHVlOnRydWUsY291bnQ6Mn0sXG4gICAgICB7bmFtZTpcIl9pbmxpbmVfMV9hcmcxX1wiLGx2YWx1ZTpmYWxzZSxydmFsdWU6dHJ1ZSxjb3VudDoyfV0sXG4gICAgdGhpc1ZhcnM6W1widGhpc19pXCIsXCJ0aGlzX3ZcIl0sXG4gICAgbG9jYWxWYXJzOltcIl9pbmxpbmVfMV9rXCJdfSxcbiAgcG9zdDp7XG4gICAgYm9keTpcIntyZXR1cm4gdGhpc19pfVwiLFxuICAgIGFyZ3M6W10sXG4gICAgdGhpc1ZhcnM6W1widGhpc19pXCJdLFxuICAgIGxvY2FsVmFyczpbXX1cbn0pICBcblxuZXhwb3J0cy5yYW5kb20gPSBtYWtlT3Aoe1xuICBhcmdzOiBbXCJhcnJheVwiXSxcbiAgcHJlOiB7YXJnczpbXSwgYm9keTpcInRoaXNfZj1NYXRoLnJhbmRvbVwiLCB0aGlzVmFyczpbXCJ0aGlzX2ZcIl19LFxuICBib2R5OiB7YXJnczogW1wiYVwiXSwgYm9keTpcImE9dGhpc19mKClcIiwgdGhpc1ZhcnM6W1widGhpc19mXCJdfSxcbiAgZnVuY05hbWU6IFwicmFuZG9tXCJcbn0pXG5cbmV4cG9ydHMuYXNzaWduID0gbWFrZU9wKHtcbiAgYXJnczpbXCJhcnJheVwiLCBcImFycmF5XCJdLFxuICBib2R5OiB7YXJnczpbXCJhXCIsIFwiYlwiXSwgYm9keTpcImE9YlwifSxcbiAgZnVuY05hbWU6IFwiYXNzaWduXCIgfSlcblxuZXhwb3J0cy5hc3NpZ25zID0gbWFrZU9wKHtcbiAgYXJnczpbXCJhcnJheVwiLCBcInNjYWxhclwiXSxcbiAgYm9keToge2FyZ3M6W1wiYVwiLCBcImJcIl0sIGJvZHk6XCJhPWJcIn0sXG4gIGZ1bmNOYW1lOiBcImFzc2lnbnNcIiB9KVxuXG5cbmV4cG9ydHMuZXF1YWxzID0gY29tcGlsZSh7XG4gIGFyZ3M6W1wiYXJyYXlcIiwgXCJhcnJheVwiXSxcbiAgcHJlOiBFbXB0eVByb2MsXG4gIGJvZHk6IHthcmdzOlt7bmFtZTpcInhcIiwgbHZhbHVlOmZhbHNlLCBydmFsdWU6dHJ1ZSwgY291bnQ6MX0sXG4gICAgICAgICAgICAgICB7bmFtZTpcInlcIiwgbHZhbHVlOmZhbHNlLCBydmFsdWU6dHJ1ZSwgY291bnQ6MX1dLCBcbiAgICAgICAgYm9keTogXCJpZih4IT09eSl7cmV0dXJuIGZhbHNlfVwiLCBcbiAgICAgICAgbG9jYWxWYXJzOiBbXSwgXG4gICAgICAgIHRoaXNWYXJzOiBbXX0sXG4gIHBvc3Q6IHthcmdzOltdLCBsb2NhbFZhcnM6W10sIHRoaXNWYXJzOltdLCBib2R5OlwicmV0dXJuIHRydWVcIn0sXG4gIGZ1bmNOYW1lOiBcImVxdWFsc1wiXG59KVxuXG5cbiIsIlwidXNlIHN0cmljdFwiXHJcblxyXG52YXIgY3JlYXRlVGh1bmsgPSByZXF1aXJlKFwiLi9saWIvdGh1bmsuanNcIilcclxuXHJcbmZ1bmN0aW9uIFByb2NlZHVyZSgpIHtcclxuICB0aGlzLmFyZ1R5cGVzID0gW11cclxuICB0aGlzLnNoaW1BcmdzID0gW11cclxuICB0aGlzLmFycmF5QXJncyA9IFtdXHJcbiAgdGhpcy5hcnJheUJsb2NrSW5kaWNlcyA9IFtdXHJcbiAgdGhpcy5zY2FsYXJBcmdzID0gW11cclxuICB0aGlzLm9mZnNldEFyZ3MgPSBbXVxyXG4gIHRoaXMub2Zmc2V0QXJnSW5kZXggPSBbXVxyXG4gIHRoaXMuaW5kZXhBcmdzID0gW11cclxuICB0aGlzLnNoYXBlQXJncyA9IFtdXHJcbiAgdGhpcy5mdW5jTmFtZSA9IFwiXCJcclxuICB0aGlzLnByZSA9IG51bGxcclxuICB0aGlzLmJvZHkgPSBudWxsXHJcbiAgdGhpcy5wb3N0ID0gbnVsbFxyXG4gIHRoaXMuZGVidWcgPSBmYWxzZVxyXG59XHJcblxyXG5mdW5jdGlvbiBjb21waWxlQ3dpc2UodXNlcl9hcmdzKSB7XHJcbiAgLy9DcmVhdGUgcHJvY2VkdXJlXHJcbiAgdmFyIHByb2MgPSBuZXcgUHJvY2VkdXJlKClcclxuICBcclxuICAvL1BhcnNlIGJsb2Nrc1xyXG4gIHByb2MucHJlICAgID0gdXNlcl9hcmdzLnByZVxyXG4gIHByb2MuYm9keSAgID0gdXNlcl9hcmdzLmJvZHlcclxuICBwcm9jLnBvc3QgICA9IHVzZXJfYXJncy5wb3N0XHJcblxyXG4gIC8vUGFyc2UgYXJndW1lbnRzXHJcbiAgdmFyIHByb2NfYXJncyA9IHVzZXJfYXJncy5hcmdzLnNsaWNlKDApXHJcbiAgcHJvYy5hcmdUeXBlcyA9IHByb2NfYXJnc1xyXG4gIGZvcih2YXIgaT0wOyBpPHByb2NfYXJncy5sZW5ndGg7ICsraSkge1xyXG4gICAgdmFyIGFyZ190eXBlID0gcHJvY19hcmdzW2ldXHJcbiAgICBpZihhcmdfdHlwZSA9PT0gXCJhcnJheVwiIHx8ICh0eXBlb2YgYXJnX3R5cGUgPT09IFwib2JqZWN0XCIgJiYgYXJnX3R5cGUuYmxvY2tJbmRpY2VzKSkge1xyXG4gICAgICBwcm9jLmFyZ1R5cGVzW2ldID0gXCJhcnJheVwiXHJcbiAgICAgIHByb2MuYXJyYXlBcmdzLnB1c2goaSlcclxuICAgICAgcHJvYy5hcnJheUJsb2NrSW5kaWNlcy5wdXNoKGFyZ190eXBlLmJsb2NrSW5kaWNlcyA/IGFyZ190eXBlLmJsb2NrSW5kaWNlcyA6IDApXHJcbiAgICAgIHByb2Muc2hpbUFyZ3MucHVzaChcImFycmF5XCIgKyBpKVxyXG4gICAgICBpZihpIDwgcHJvYy5wcmUuYXJncy5sZW5ndGggJiYgcHJvYy5wcmUuYXJnc1tpXS5jb3VudD4wKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiY3dpc2U6IHByZSgpIGJsb2NrIG1heSBub3QgcmVmZXJlbmNlIGFycmF5IGFyZ3NcIilcclxuICAgICAgfVxyXG4gICAgICBpZihpIDwgcHJvYy5wb3N0LmFyZ3MubGVuZ3RoICYmIHByb2MucG9zdC5hcmdzW2ldLmNvdW50PjApIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogcG9zdCgpIGJsb2NrIG1heSBub3QgcmVmZXJlbmNlIGFycmF5IGFyZ3NcIilcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIGlmKGFyZ190eXBlID09PSBcInNjYWxhclwiKSB7XHJcbiAgICAgIHByb2Muc2NhbGFyQXJncy5wdXNoKGkpXHJcbiAgICAgIHByb2Muc2hpbUFyZ3MucHVzaChcInNjYWxhclwiICsgaSlcclxuICAgIH0gZWxzZSBpZihhcmdfdHlwZSA9PT0gXCJpbmRleFwiKSB7XHJcbiAgICAgIHByb2MuaW5kZXhBcmdzLnB1c2goaSlcclxuICAgICAgaWYoaSA8IHByb2MucHJlLmFyZ3MubGVuZ3RoICYmIHByb2MucHJlLmFyZ3NbaV0uY291bnQgPiAwKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiY3dpc2U6IHByZSgpIGJsb2NrIG1heSBub3QgcmVmZXJlbmNlIGFycmF5IGluZGV4XCIpXHJcbiAgICAgIH1cclxuICAgICAgaWYoaSA8IHByb2MuYm9keS5hcmdzLmxlbmd0aCAmJiBwcm9jLmJvZHkuYXJnc1tpXS5sdmFsdWUpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogYm9keSgpIGJsb2NrIG1heSBub3Qgd3JpdGUgdG8gYXJyYXkgaW5kZXhcIilcclxuICAgICAgfVxyXG4gICAgICBpZihpIDwgcHJvYy5wb3N0LmFyZ3MubGVuZ3RoICYmIHByb2MucG9zdC5hcmdzW2ldLmNvdW50ID4gMCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcImN3aXNlOiBwb3N0KCkgYmxvY2sgbWF5IG5vdCByZWZlcmVuY2UgYXJyYXkgaW5kZXhcIilcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIGlmKGFyZ190eXBlID09PSBcInNoYXBlXCIpIHtcclxuICAgICAgcHJvYy5zaGFwZUFyZ3MucHVzaChpKVxyXG4gICAgICBpZihpIDwgcHJvYy5wcmUuYXJncy5sZW5ndGggJiYgcHJvYy5wcmUuYXJnc1tpXS5sdmFsdWUpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogcHJlKCkgYmxvY2sgbWF5IG5vdCB3cml0ZSB0byBhcnJheSBzaGFwZVwiKVxyXG4gICAgICB9XHJcbiAgICAgIGlmKGkgPCBwcm9jLmJvZHkuYXJncy5sZW5ndGggJiYgcHJvYy5ib2R5LmFyZ3NbaV0ubHZhbHVlKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiY3dpc2U6IGJvZHkoKSBibG9jayBtYXkgbm90IHdyaXRlIHRvIGFycmF5IHNoYXBlXCIpXHJcbiAgICAgIH1cclxuICAgICAgaWYoaSA8IHByb2MucG9zdC5hcmdzLmxlbmd0aCAmJiBwcm9jLnBvc3QuYXJnc1tpXS5sdmFsdWUpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogcG9zdCgpIGJsb2NrIG1heSBub3Qgd3JpdGUgdG8gYXJyYXkgc2hhcGVcIilcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIGlmKHR5cGVvZiBhcmdfdHlwZSA9PT0gXCJvYmplY3RcIiAmJiBhcmdfdHlwZS5vZmZzZXQpIHtcclxuICAgICAgcHJvYy5hcmdUeXBlc1tpXSA9IFwib2Zmc2V0XCJcclxuICAgICAgcHJvYy5vZmZzZXRBcmdzLnB1c2goeyBhcnJheTogYXJnX3R5cGUuYXJyYXksIG9mZnNldDphcmdfdHlwZS5vZmZzZXQgfSlcclxuICAgICAgcHJvYy5vZmZzZXRBcmdJbmRleC5wdXNoKGkpXHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogVW5rbm93biBhcmd1bWVudCB0eXBlIFwiICsgcHJvY19hcmdzW2ldKVxyXG4gICAgfVxyXG4gIH1cclxuICBcclxuICAvL01ha2Ugc3VyZSBhdCBsZWFzdCBvbmUgYXJyYXkgYXJndW1lbnQgd2FzIHNwZWNpZmllZFxyXG4gIGlmKHByb2MuYXJyYXlBcmdzLmxlbmd0aCA8PSAwKSB7XHJcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogTm8gYXJyYXkgYXJndW1lbnRzIHNwZWNpZmllZFwiKVxyXG4gIH1cclxuICBcclxuICAvL01ha2Ugc3VyZSBhcmd1bWVudHMgYXJlIGNvcnJlY3RcclxuICBpZihwcm9jLnByZS5hcmdzLmxlbmd0aCA+IHByb2NfYXJncy5sZW5ndGgpIHtcclxuICAgIHRocm93IG5ldyBFcnJvcihcImN3aXNlOiBUb28gbWFueSBhcmd1bWVudHMgaW4gcHJlKCkgYmxvY2tcIilcclxuICB9XHJcbiAgaWYocHJvYy5ib2R5LmFyZ3MubGVuZ3RoID4gcHJvY19hcmdzLmxlbmd0aCkge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKFwiY3dpc2U6IFRvbyBtYW55IGFyZ3VtZW50cyBpbiBib2R5KCkgYmxvY2tcIilcclxuICB9XHJcbiAgaWYocHJvYy5wb3N0LmFyZ3MubGVuZ3RoID4gcHJvY19hcmdzLmxlbmd0aCkge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKFwiY3dpc2U6IFRvbyBtYW55IGFyZ3VtZW50cyBpbiBwb3N0KCkgYmxvY2tcIilcclxuICB9XHJcblxyXG4gIC8vQ2hlY2sgZGVidWcgZmxhZ1xyXG4gIHByb2MuZGVidWcgPSAhIXVzZXJfYXJncy5wcmludENvZGUgfHwgISF1c2VyX2FyZ3MuZGVidWdcclxuICBcclxuICAvL1JldHJpZXZlIG5hbWVcclxuICBwcm9jLmZ1bmNOYW1lID0gdXNlcl9hcmdzLmZ1bmNOYW1lIHx8IFwiY3dpc2VcIlxyXG4gIFxyXG4gIC8vUmVhZCBpbiBibG9jayBzaXplXHJcbiAgcHJvYy5ibG9ja1NpemUgPSB1c2VyX2FyZ3MuYmxvY2tTaXplIHx8IDY0XHJcblxyXG4gIHJldHVybiBjcmVhdGVUaHVuayhwcm9jKVxyXG59XHJcblxyXG5tb2R1bGUuZXhwb3J0cyA9IGNvbXBpbGVDd2lzZVxyXG4iLCJcInVzZSBzdHJpY3RcIlxyXG5cclxudmFyIHVuaXEgPSByZXF1aXJlKFwidW5pcVwiKVxyXG5cclxuLy8gVGhpcyBmdW5jdGlvbiBnZW5lcmF0ZXMgdmVyeSBzaW1wbGUgbG9vcHMgYW5hbG9nb3VzIHRvIGhvdyB5b3UgdHlwaWNhbGx5IHRyYXZlcnNlIGFycmF5cyAodGhlIG91dGVybW9zdCBsb29wIGNvcnJlc3BvbmRzIHRvIHRoZSBzbG93ZXN0IGNoYW5naW5nIGluZGV4LCB0aGUgaW5uZXJtb3N0IGxvb3AgdG8gdGhlIGZhc3Rlc3QgY2hhbmdpbmcgaW5kZXgpXHJcbi8vIFRPRE86IElmIHR3byBhcnJheXMgaGF2ZSB0aGUgc2FtZSBzdHJpZGVzIChhbmQgb2Zmc2V0cykgdGhlcmUgaXMgcG90ZW50aWFsIGZvciBkZWNyZWFzaW5nIHRoZSBudW1iZXIgb2YgXCJwb2ludGVyc1wiIGFuZCByZWxhdGVkIHZhcmlhYmxlcy4gVGhlIGRyYXdiYWNrIGlzIHRoYXQgdGhlIHR5cGUgc2lnbmF0dXJlIHdvdWxkIGJlY29tZSBtb3JlIHNwZWNpZmljIGFuZCB0aGF0IHRoZXJlIHdvdWxkIHRodXMgYmUgbGVzcyBwb3RlbnRpYWwgZm9yIGNhY2hpbmcsIGJ1dCBpdCBtaWdodCBzdGlsbCBiZSB3b3J0aCBpdCwgZXNwZWNpYWxseSB3aGVuIGRlYWxpbmcgd2l0aCBsYXJnZSBudW1iZXJzIG9mIGFyZ3VtZW50cy5cclxuZnVuY3Rpb24gaW5uZXJGaWxsKG9yZGVyLCBwcm9jLCBib2R5KSB7XHJcbiAgdmFyIGRpbWVuc2lvbiA9IG9yZGVyLmxlbmd0aFxyXG4gICAgLCBuYXJncyA9IHByb2MuYXJyYXlBcmdzLmxlbmd0aFxyXG4gICAgLCBoYXNfaW5kZXggPSBwcm9jLmluZGV4QXJncy5sZW5ndGg+MFxyXG4gICAgLCBjb2RlID0gW11cclxuICAgICwgdmFycyA9IFtdXHJcbiAgICAsIGlkeD0wLCBwaWR4PTAsIGksIGpcclxuICBmb3IoaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7IC8vIEl0ZXJhdGlvbiB2YXJpYWJsZXNcclxuICAgIHZhcnMucHVzaChbXCJpXCIsaSxcIj0wXCJdLmpvaW4oXCJcIikpXHJcbiAgfVxyXG4gIC8vQ29tcHV0ZSBzY2FuIGRlbHRhc1xyXG4gIGZvcihqPTA7IGo8bmFyZ3M7ICsraikge1xyXG4gICAgZm9yKGk9MDsgaTxkaW1lbnNpb247ICsraSkge1xyXG4gICAgICBwaWR4ID0gaWR4XHJcbiAgICAgIGlkeCA9IG9yZGVyW2ldXHJcbiAgICAgIGlmKGkgPT09IDApIHsgLy8gVGhlIGlubmVybW9zdC9mYXN0ZXN0IGRpbWVuc2lvbidzIGRlbHRhIGlzIHNpbXBseSBpdHMgc3RyaWRlXHJcbiAgICAgICAgdmFycy5wdXNoKFtcImRcIixqLFwic1wiLGksXCI9dFwiLGosXCJwXCIsaWR4XS5qb2luKFwiXCIpKVxyXG4gICAgICB9IGVsc2UgeyAvLyBGb3Igb3RoZXIgZGltZW5zaW9ucyB0aGUgZGVsdGEgaXMgYmFzaWNhbGx5IHRoZSBzdHJpZGUgbWludXMgc29tZXRoaW5nIHdoaWNoIGVzc2VudGlhbGx5IFwicmV3aW5kc1wiIHRoZSBwcmV2aW91cyAobW9yZSBpbm5lcikgZGltZW5zaW9uXHJcbiAgICAgICAgdmFycy5wdXNoKFtcImRcIixqLFwic1wiLGksXCI9KHRcIixqLFwicFwiLGlkeCxcIi1zXCIscGlkeCxcIip0XCIsaixcInBcIixwaWR4LFwiKVwiXS5qb2luKFwiXCIpKVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG4gIGNvZGUucHVzaChcInZhciBcIiArIHZhcnMuam9pbihcIixcIikpXHJcbiAgLy9TY2FuIGxvb3BcclxuICBmb3IoaT1kaW1lbnNpb24tMTsgaT49MDsgLS1pKSB7IC8vIFN0YXJ0IGF0IGxhcmdlc3Qgc3RyaWRlIGFuZCB3b3JrIHlvdXIgd2F5IGlud2FyZHNcclxuICAgIGlkeCA9IG9yZGVyW2ldXHJcbiAgICBjb2RlLnB1c2goW1wiZm9yKGlcIixpLFwiPTA7aVwiLGksXCI8c1wiLGlkeCxcIjsrK2lcIixpLFwiKXtcIl0uam9pbihcIlwiKSlcclxuICB9XHJcbiAgLy9QdXNoIGJvZHkgb2YgaW5uZXIgbG9vcFxyXG4gIGNvZGUucHVzaChib2R5KVxyXG4gIC8vQWR2YW5jZSBzY2FuIHBvaW50ZXJzXHJcbiAgZm9yKGk9MDsgaTxkaW1lbnNpb247ICsraSkge1xyXG4gICAgcGlkeCA9IGlkeFxyXG4gICAgaWR4ID0gb3JkZXJbaV1cclxuICAgIGZvcihqPTA7IGo8bmFyZ3M7ICsraikge1xyXG4gICAgICBjb2RlLnB1c2goW1wicFwiLGosXCIrPWRcIixqLFwic1wiLGldLmpvaW4oXCJcIikpXHJcbiAgICB9XHJcbiAgICBpZihoYXNfaW5kZXgpIHtcclxuICAgICAgaWYoaSA+IDApIHtcclxuICAgICAgICBjb2RlLnB1c2goW1wiaW5kZXhbXCIscGlkeCxcIl0tPXNcIixwaWR4XS5qb2luKFwiXCIpKVxyXG4gICAgICB9XHJcbiAgICAgIGNvZGUucHVzaChbXCIrK2luZGV4W1wiLGlkeCxcIl1cIl0uam9pbihcIlwiKSlcclxuICAgIH1cclxuICAgIGNvZGUucHVzaChcIn1cIilcclxuICB9XHJcbiAgcmV0dXJuIGNvZGUuam9pbihcIlxcblwiKVxyXG59XHJcblxyXG4vLyBHZW5lcmF0ZSBcIm91dGVyXCIgbG9vcHMgdGhhdCBsb29wIG92ZXIgYmxvY2tzIG9mIGRhdGEsIGFwcGx5aW5nIFwiaW5uZXJcIiBsb29wcyB0byB0aGUgYmxvY2tzIGJ5IG1hbmlwdWxhdGluZyB0aGUgbG9jYWwgdmFyaWFibGVzIGluIHN1Y2ggYSB3YXkgdGhhdCB0aGUgaW5uZXIgbG9vcCBvbmx5IFwic2Vlc1wiIHRoZSBjdXJyZW50IGJsb2NrLlxyXG4vLyBUT0RPOiBJZiB0aGlzIGlzIHVzZWQsIHRoZW4gdGhlIHByZXZpb3VzIGRlY2xhcmF0aW9uIChkb25lIGJ5IGdlbmVyYXRlQ3dpc2VPcCkgb2YgcyogaXMgZXNzZW50aWFsbHkgdW5uZWNlc3NhcnkuXHJcbi8vICAgICAgIEkgYmVsaWV2ZSB0aGUgcyogYXJlIG5vdCB1c2VkIGVsc2V3aGVyZSAoaW4gcGFydGljdWxhciwgSSBkb24ndCB0aGluayB0aGV5J3JlIHVzZWQgaW4gdGhlIHByZS9wb3N0IHBhcnRzIGFuZCBcInNoYXBlXCIgaXMgZGVmaW5lZCBpbmRlcGVuZGVudGx5KSwgc28gaXQgd291bGQgYmUgcG9zc2libGUgdG8gbWFrZSBkZWZpbmluZyB0aGUgcyogZGVwZW5kZW50IG9uIHdoYXQgbG9vcCBtZXRob2QgaXMgYmVpbmcgdXNlZC5cclxuZnVuY3Rpb24gb3V0ZXJGaWxsKG1hdGNoZWQsIG9yZGVyLCBwcm9jLCBib2R5KSB7XHJcbiAgdmFyIGRpbWVuc2lvbiA9IG9yZGVyLmxlbmd0aFxyXG4gICAgLCBuYXJncyA9IHByb2MuYXJyYXlBcmdzLmxlbmd0aFxyXG4gICAgLCBibG9ja1NpemUgPSBwcm9jLmJsb2NrU2l6ZVxyXG4gICAgLCBoYXNfaW5kZXggPSBwcm9jLmluZGV4QXJncy5sZW5ndGggPiAwXHJcbiAgICAsIGNvZGUgPSBbXVxyXG4gIGZvcih2YXIgaT0wOyBpPG5hcmdzOyArK2kpIHtcclxuICAgIGNvZGUucHVzaChbXCJ2YXIgb2Zmc2V0XCIsaSxcIj1wXCIsaV0uam9pbihcIlwiKSlcclxuICB9XHJcbiAgLy9HZW5lcmF0ZSBsb29wcyBmb3IgdW5tYXRjaGVkIGRpbWVuc2lvbnNcclxuICAvLyBUaGUgb3JkZXIgaW4gd2hpY2ggdGhlc2UgZGltZW5zaW9ucyBhcmUgdHJhdmVyc2VkIGlzIGZhaXJseSBhcmJpdHJhcnkgKGZyb20gc21hbGwgc3RyaWRlIHRvIGxhcmdlIHN0cmlkZSwgZm9yIHRoZSBmaXJzdCBhcmd1bWVudClcclxuICAvLyBUT0RPOiBJdCB3b3VsZCBiZSBuaWNlIGlmIHRoZSBvcmRlciBpbiB3aGljaCB0aGVzZSBsb29wcyBhcmUgcGxhY2VkIHdvdWxkIGFsc28gYmUgc29tZWhvdyBcIm9wdGltYWxcIiAoYXQgdGhlIHZlcnkgbGVhc3Qgd2Ugc2hvdWxkIGNoZWNrIHRoYXQgaXQgcmVhbGx5IGRvZXNuJ3QgaHVydCB1cyBpZiB0aGV5J3JlIG5vdCkuXHJcbiAgZm9yKHZhciBpPW1hdGNoZWQ7IGk8ZGltZW5zaW9uOyArK2kpIHtcclxuICAgIGNvZGUucHVzaChbXCJmb3IodmFyIGpcIitpK1wiPVNTW1wiLCBvcmRlcltpXSwgXCJdfDA7alwiLCBpLCBcIj4wOyl7XCJdLmpvaW4oXCJcIikpIC8vIEl0ZXJhdGUgYmFjayB0byBmcm9udFxyXG4gICAgY29kZS5wdXNoKFtcImlmKGpcIixpLFwiPFwiLGJsb2NrU2l6ZSxcIil7XCJdLmpvaW4oXCJcIikpIC8vIEVpdGhlciBkZWNyZWFzZSBqIGJ5IGJsb2NrU2l6ZSAocyA9IGJsb2NrU2l6ZSksIG9yIHNldCBpdCB0byB6ZXJvIChhZnRlciBzZXR0aW5nIHMgPSBqKS5cclxuICAgIGNvZGUucHVzaChbXCJzXCIsb3JkZXJbaV0sXCI9alwiLGldLmpvaW4oXCJcIikpXHJcbiAgICBjb2RlLnB1c2goW1wialwiLGksXCI9MFwiXS5qb2luKFwiXCIpKVxyXG4gICAgY29kZS5wdXNoKFtcIn1lbHNle3NcIixvcmRlcltpXSxcIj1cIixibG9ja1NpemVdLmpvaW4oXCJcIikpXHJcbiAgICBjb2RlLnB1c2goW1wialwiLGksXCItPVwiLGJsb2NrU2l6ZSxcIn1cIl0uam9pbihcIlwiKSlcclxuICAgIGlmKGhhc19pbmRleCkge1xyXG4gICAgICBjb2RlLnB1c2goW1wiaW5kZXhbXCIsb3JkZXJbaV0sXCJdPWpcIixpXS5qb2luKFwiXCIpKVxyXG4gICAgfVxyXG4gIH1cclxuICBmb3IodmFyIGk9MDsgaTxuYXJnczsgKytpKSB7XHJcbiAgICB2YXIgaW5kZXhTdHIgPSBbXCJvZmZzZXRcIitpXVxyXG4gICAgZm9yKHZhciBqPW1hdGNoZWQ7IGo8ZGltZW5zaW9uOyArK2opIHtcclxuICAgICAgaW5kZXhTdHIucHVzaChbXCJqXCIsaixcIip0XCIsaSxcInBcIixvcmRlcltqXV0uam9pbihcIlwiKSlcclxuICAgIH1cclxuICAgIGNvZGUucHVzaChbXCJwXCIsaSxcIj0oXCIsaW5kZXhTdHIuam9pbihcIitcIiksXCIpXCJdLmpvaW4oXCJcIikpXHJcbiAgfVxyXG4gIGNvZGUucHVzaChpbm5lckZpbGwob3JkZXIsIHByb2MsIGJvZHkpKVxyXG4gIGZvcih2YXIgaT1tYXRjaGVkOyBpPGRpbWVuc2lvbjsgKytpKSB7XHJcbiAgICBjb2RlLnB1c2goXCJ9XCIpXHJcbiAgfVxyXG4gIHJldHVybiBjb2RlLmpvaW4oXCJcXG5cIilcclxufVxyXG5cclxuLy9Db3VudCB0aGUgbnVtYmVyIG9mIGNvbXBhdGlibGUgaW5uZXIgb3JkZXJzXHJcbi8vIFRoaXMgaXMgdGhlIGxlbmd0aCBvZiB0aGUgbG9uZ2VzdCBjb21tb24gcHJlZml4IG9mIHRoZSBhcnJheXMgaW4gb3JkZXJzLlxyXG4vLyBFYWNoIGFycmF5IGluIG9yZGVycyBsaXN0cyB0aGUgZGltZW5zaW9ucyBvZiB0aGUgY29ycmVzcG9uZCBuZGFycmF5IGluIG9yZGVyIG9mIGluY3JlYXNpbmcgc3RyaWRlLlxyXG4vLyBUaGlzIGlzIHRodXMgdGhlIG1heGltdW0gbnVtYmVyIG9mIGRpbWVuc2lvbnMgdGhhdCBjYW4gYmUgZWZmaWNpZW50bHkgdHJhdmVyc2VkIGJ5IHNpbXBsZSBuZXN0ZWQgbG9vcHMgZm9yIGFsbCBhcnJheXMuXHJcbmZ1bmN0aW9uIGNvdW50TWF0Y2hlcyhvcmRlcnMpIHtcclxuICB2YXIgbWF0Y2hlZCA9IDAsIGRpbWVuc2lvbiA9IG9yZGVyc1swXS5sZW5ndGhcclxuICB3aGlsZShtYXRjaGVkIDwgZGltZW5zaW9uKSB7XHJcbiAgICBmb3IodmFyIGo9MTsgajxvcmRlcnMubGVuZ3RoOyArK2opIHtcclxuICAgICAgaWYob3JkZXJzW2pdW21hdGNoZWRdICE9PSBvcmRlcnNbMF1bbWF0Y2hlZF0pIHtcclxuICAgICAgICByZXR1cm4gbWF0Y2hlZFxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICArK21hdGNoZWRcclxuICB9XHJcbiAgcmV0dXJuIG1hdGNoZWRcclxufVxyXG5cclxuLy9Qcm9jZXNzZXMgYSBibG9jayBhY2NvcmRpbmcgdG8gdGhlIGdpdmVuIGRhdGEgdHlwZXNcclxuLy8gUmVwbGFjZXMgdmFyaWFibGUgbmFtZXMgYnkgZGlmZmVyZW50IG9uZXMsIGVpdGhlciBcImxvY2FsXCIgb25lcyAodGhhdCBhcmUgdGhlbiBmZXJyaWVkIGluIGFuZCBvdXQgb2YgdGhlIGdpdmVuIGFycmF5KSBvciBvbmVzIG1hdGNoaW5nIHRoZSBhcmd1bWVudHMgdGhhdCB0aGUgZnVuY3Rpb24gcGVyZm9ybWluZyB0aGUgdWx0aW1hdGUgbG9vcCB3aWxsIGFjY2VwdC5cclxuZnVuY3Rpb24gcHJvY2Vzc0Jsb2NrKGJsb2NrLCBwcm9jLCBkdHlwZXMpIHtcclxuICB2YXIgY29kZSA9IGJsb2NrLmJvZHlcclxuICB2YXIgcHJlID0gW11cclxuICB2YXIgcG9zdCA9IFtdXHJcbiAgZm9yKHZhciBpPTA7IGk8YmxvY2suYXJncy5sZW5ndGg7ICsraSkge1xyXG4gICAgdmFyIGNhcmcgPSBibG9jay5hcmdzW2ldXHJcbiAgICBpZihjYXJnLmNvdW50IDw9IDApIHtcclxuICAgICAgY29udGludWVcclxuICAgIH1cclxuICAgIHZhciByZSA9IG5ldyBSZWdFeHAoY2FyZy5uYW1lLCBcImdcIilcclxuICAgIHZhciBwdHJTdHIgPSBcIlwiXHJcbiAgICB2YXIgYXJyTnVtID0gcHJvYy5hcnJheUFyZ3MuaW5kZXhPZihpKVxyXG4gICAgc3dpdGNoKHByb2MuYXJnVHlwZXNbaV0pIHtcclxuICAgICAgY2FzZSBcIm9mZnNldFwiOlxyXG4gICAgICAgIHZhciBvZmZBcmdJbmRleCA9IHByb2Mub2Zmc2V0QXJnSW5kZXguaW5kZXhPZihpKVxyXG4gICAgICAgIHZhciBvZmZBcmcgPSBwcm9jLm9mZnNldEFyZ3Nbb2ZmQXJnSW5kZXhdXHJcbiAgICAgICAgYXJyTnVtID0gb2ZmQXJnLmFycmF5XHJcbiAgICAgICAgcHRyU3RyID0gXCIrcVwiICsgb2ZmQXJnSW5kZXggLy8gQWRkcyBvZmZzZXQgdG8gdGhlIFwicG9pbnRlclwiIGluIHRoZSBhcnJheVxyXG4gICAgICBjYXNlIFwiYXJyYXlcIjpcclxuICAgICAgICBwdHJTdHIgPSBcInBcIiArIGFyck51bSArIHB0clN0clxyXG4gICAgICAgIHZhciBsb2NhbFN0ciA9IFwibFwiICsgaVxyXG4gICAgICAgIHZhciBhcnJTdHIgPSBcImFcIiArIGFyck51bVxyXG4gICAgICAgIGlmIChwcm9jLmFycmF5QmxvY2tJbmRpY2VzW2Fyck51bV0gPT09IDApIHsgLy8gQXJndW1lbnQgdG8gYm9keSBpcyBqdXN0IGEgc2luZ2xlIHZhbHVlIGZyb20gdGhpcyBhcnJheVxyXG4gICAgICAgICAgaWYoY2FyZy5jb3VudCA9PT0gMSkgeyAvLyBBcmd1bWVudC9hcnJheSB1c2VkIG9ubHkgb25jZSg/KVxyXG4gICAgICAgICAgICBpZihkdHlwZXNbYXJyTnVtXSA9PT0gXCJnZW5lcmljXCIpIHtcclxuICAgICAgICAgICAgICBpZihjYXJnLmx2YWx1ZSkge1xyXG4gICAgICAgICAgICAgICAgcHJlLnB1c2goW1widmFyIFwiLCBsb2NhbFN0ciwgXCI9XCIsIGFyclN0ciwgXCIuZ2V0KFwiLCBwdHJTdHIsIFwiKVwiXS5qb2luKFwiXCIpKSAvLyBJcyB0aGlzIG5lY2Vzc2FyeSBpZiB0aGUgYXJndW1lbnQgaXMgT05MWSB1c2VkIGFzIGFuIGx2YWx1ZT8gKGtlZXAgaW4gbWluZCB0aGF0IHdlIGNhbiBoYXZlIGEgKz0gc29tZXRoaW5nLCBzbyB3ZSB3b3VsZCBhY3R1YWxseSBuZWVkIHRvIGNoZWNrIGNhcmcucnZhbHVlKVxyXG4gICAgICAgICAgICAgICAgY29kZSA9IGNvZGUucmVwbGFjZShyZSwgbG9jYWxTdHIpXHJcbiAgICAgICAgICAgICAgICBwb3N0LnB1c2goW2FyclN0ciwgXCIuc2V0KFwiLCBwdHJTdHIsIFwiLFwiLCBsb2NhbFN0cixcIilcIl0uam9pbihcIlwiKSlcclxuICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgY29kZSA9IGNvZGUucmVwbGFjZShyZSwgW2FyclN0ciwgXCIuZ2V0KFwiLCBwdHJTdHIsIFwiKVwiXS5qb2luKFwiXCIpKVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICBjb2RlID0gY29kZS5yZXBsYWNlKHJlLCBbYXJyU3RyLCBcIltcIiwgcHRyU3RyLCBcIl1cIl0uam9pbihcIlwiKSlcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIGlmKGR0eXBlc1thcnJOdW1dID09PSBcImdlbmVyaWNcIikge1xyXG4gICAgICAgICAgICBwcmUucHVzaChbXCJ2YXIgXCIsIGxvY2FsU3RyLCBcIj1cIiwgYXJyU3RyLCBcIi5nZXQoXCIsIHB0clN0ciwgXCIpXCJdLmpvaW4oXCJcIikpIC8vIFRPRE86IENvdWxkIHdlIG9wdGltaXplIGJ5IGNoZWNraW5nIGZvciBjYXJnLnJ2YWx1ZT9cclxuICAgICAgICAgICAgY29kZSA9IGNvZGUucmVwbGFjZShyZSwgbG9jYWxTdHIpXHJcbiAgICAgICAgICAgIGlmKGNhcmcubHZhbHVlKSB7XHJcbiAgICAgICAgICAgICAgcG9zdC5wdXNoKFthcnJTdHIsIFwiLnNldChcIiwgcHRyU3RyLCBcIixcIiwgbG9jYWxTdHIsXCIpXCJdLmpvaW4oXCJcIikpXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHByZS5wdXNoKFtcInZhciBcIiwgbG9jYWxTdHIsIFwiPVwiLCBhcnJTdHIsIFwiW1wiLCBwdHJTdHIsIFwiXVwiXS5qb2luKFwiXCIpKSAvLyBUT0RPOiBDb3VsZCB3ZSBvcHRpbWl6ZSBieSBjaGVja2luZyBmb3IgY2FyZy5ydmFsdWU/XHJcbiAgICAgICAgICAgIGNvZGUgPSBjb2RlLnJlcGxhY2UocmUsIGxvY2FsU3RyKVxyXG4gICAgICAgICAgICBpZihjYXJnLmx2YWx1ZSkge1xyXG4gICAgICAgICAgICAgIHBvc3QucHVzaChbYXJyU3RyLCBcIltcIiwgcHRyU3RyLCBcIl09XCIsIGxvY2FsU3RyXS5qb2luKFwiXCIpKVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIHsgLy8gQXJndW1lbnQgdG8gYm9keSBpcyBhIFwiYmxvY2tcIlxyXG4gICAgICAgICAgdmFyIHJlU3RyQXJyID0gW2NhcmcubmFtZV0sIHB0clN0ckFyciA9IFtwdHJTdHJdXHJcbiAgICAgICAgICBmb3IodmFyIGo9MDsgajxNYXRoLmFicyhwcm9jLmFycmF5QmxvY2tJbmRpY2VzW2Fyck51bV0pOyBqKyspIHtcclxuICAgICAgICAgICAgcmVTdHJBcnIucHVzaChcIlxcXFxzKlxcXFxbKFteXFxcXF1dKylcXFxcXVwiKVxyXG4gICAgICAgICAgICBwdHJTdHJBcnIucHVzaChcIiRcIiArIChqKzEpICsgXCIqdFwiICsgYXJyTnVtICsgXCJiXCIgKyBqKSAvLyBNYXRjaGVkIGluZGV4IHRpbWVzIHN0cmlkZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmUgPSBuZXcgUmVnRXhwKHJlU3RyQXJyLmpvaW4oXCJcIiksIFwiZ1wiKVxyXG4gICAgICAgICAgcHRyU3RyID0gcHRyU3RyQXJyLmpvaW4oXCIrXCIpXHJcbiAgICAgICAgICBpZihkdHlwZXNbYXJyTnVtXSA9PT0gXCJnZW5lcmljXCIpIHtcclxuICAgICAgICAgICAgLyppZihjYXJnLmx2YWx1ZSkge1xyXG4gICAgICAgICAgICAgIHByZS5wdXNoKFtcInZhciBcIiwgbG9jYWxTdHIsIFwiPVwiLCBhcnJTdHIsIFwiLmdldChcIiwgcHRyU3RyLCBcIilcIl0uam9pbihcIlwiKSkgLy8gSXMgdGhpcyBuZWNlc3NhcnkgaWYgdGhlIGFyZ3VtZW50IGlzIE9OTFkgdXNlZCBhcyBhbiBsdmFsdWU/IChrZWVwIGluIG1pbmQgdGhhdCB3ZSBjYW4gaGF2ZSBhICs9IHNvbWV0aGluZywgc28gd2Ugd291bGQgYWN0dWFsbHkgbmVlZCB0byBjaGVjayBjYXJnLnJ2YWx1ZSlcclxuICAgICAgICAgICAgICBjb2RlID0gY29kZS5yZXBsYWNlKHJlLCBsb2NhbFN0cilcclxuICAgICAgICAgICAgICBwb3N0LnB1c2goW2FyclN0ciwgXCIuc2V0KFwiLCBwdHJTdHIsIFwiLFwiLCBsb2NhbFN0cixcIilcIl0uam9pbihcIlwiKSlcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICBjb2RlID0gY29kZS5yZXBsYWNlKHJlLCBbYXJyU3RyLCBcIi5nZXQoXCIsIHB0clN0ciwgXCIpXCJdLmpvaW4oXCJcIikpXHJcbiAgICAgICAgICAgIH0qL1xyXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogR2VuZXJpYyBhcnJheXMgbm90IHN1cHBvcnRlZCBpbiBjb21iaW5hdGlvbiB3aXRoIGJsb2NrcyFcIilcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIFRoaXMgZG9lcyBub3QgcHJvZHVjZSBhbnkgbG9jYWwgdmFyaWFibGVzLCBldmVuIGlmIHZhcmlhYmxlcyBhcmUgdXNlZCBtdWx0aXBsZSB0aW1lcy4gSXQgd291bGQgYmUgcG9zc2libGUgdG8gZG8gc28sIGJ1dCBpdCB3b3VsZCBjb21wbGljYXRlIHRoaW5ncyBxdWl0ZSBhIGJpdC5cclxuICAgICAgICAgICAgY29kZSA9IGNvZGUucmVwbGFjZShyZSwgW2FyclN0ciwgXCJbXCIsIHB0clN0ciwgXCJdXCJdLmpvaW4oXCJcIikpXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICBicmVha1xyXG4gICAgICBjYXNlIFwic2NhbGFyXCI6XHJcbiAgICAgICAgY29kZSA9IGNvZGUucmVwbGFjZShyZSwgXCJZXCIgKyBwcm9jLnNjYWxhckFyZ3MuaW5kZXhPZihpKSlcclxuICAgICAgYnJlYWtcclxuICAgICAgY2FzZSBcImluZGV4XCI6XHJcbiAgICAgICAgY29kZSA9IGNvZGUucmVwbGFjZShyZSwgXCJpbmRleFwiKVxyXG4gICAgICBicmVha1xyXG4gICAgICBjYXNlIFwic2hhcGVcIjpcclxuICAgICAgICBjb2RlID0gY29kZS5yZXBsYWNlKHJlLCBcInNoYXBlXCIpXHJcbiAgICAgIGJyZWFrXHJcbiAgICB9XHJcbiAgfVxyXG4gIHJldHVybiBbcHJlLmpvaW4oXCJcXG5cIiksIGNvZGUsIHBvc3Quam9pbihcIlxcblwiKV0uam9pbihcIlxcblwiKS50cmltKClcclxufVxyXG5cclxuZnVuY3Rpb24gdHlwZVN1bW1hcnkoZHR5cGVzKSB7XHJcbiAgdmFyIHN1bW1hcnkgPSBuZXcgQXJyYXkoZHR5cGVzLmxlbmd0aClcclxuICB2YXIgYWxsRXF1YWwgPSB0cnVlXHJcbiAgZm9yKHZhciBpPTA7IGk8ZHR5cGVzLmxlbmd0aDsgKytpKSB7XHJcbiAgICB2YXIgdCA9IGR0eXBlc1tpXVxyXG4gICAgdmFyIGRpZ2l0cyA9IHQubWF0Y2goL1xcZCsvKVxyXG4gICAgaWYoIWRpZ2l0cykge1xyXG4gICAgICBkaWdpdHMgPSBcIlwiXHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBkaWdpdHMgPSBkaWdpdHNbMF1cclxuICAgIH1cclxuICAgIGlmKHQuY2hhckF0KDApID09PSAwKSB7XHJcbiAgICAgIHN1bW1hcnlbaV0gPSBcInVcIiArIHQuY2hhckF0KDEpICsgZGlnaXRzXHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBzdW1tYXJ5W2ldID0gdC5jaGFyQXQoMCkgKyBkaWdpdHNcclxuICAgIH1cclxuICAgIGlmKGkgPiAwKSB7XHJcbiAgICAgIGFsbEVxdWFsID0gYWxsRXF1YWwgJiYgc3VtbWFyeVtpXSA9PT0gc3VtbWFyeVtpLTFdXHJcbiAgICB9XHJcbiAgfVxyXG4gIGlmKGFsbEVxdWFsKSB7XHJcbiAgICByZXR1cm4gc3VtbWFyeVswXVxyXG4gIH1cclxuICByZXR1cm4gc3VtbWFyeS5qb2luKFwiXCIpXHJcbn1cclxuXHJcbi8vR2VuZXJhdGVzIGEgY3dpc2Ugb3BlcmF0b3JcclxuZnVuY3Rpb24gZ2VuZXJhdGVDV2lzZU9wKHByb2MsIHR5cGVzaWcpIHtcclxuXHJcbiAgLy9Db21wdXRlIGRpbWVuc2lvblxyXG4gIC8vIEFycmF5cyBnZXQgcHV0IGZpcnN0IGluIHR5cGVzaWcsIGFuZCB0aGVyZSBhcmUgdHdvIGVudHJpZXMgcGVyIGFycmF5IChkdHlwZSBhbmQgb3JkZXIpLCBzbyB0aGlzIGdldHMgdGhlIG51bWJlciBvZiBkaW1lbnNpb25zIGluIHRoZSBmaXJzdCBhcnJheSBhcmcuXHJcbiAgdmFyIGRpbWVuc2lvbiA9ICh0eXBlc2lnWzFdLmxlbmd0aCAtIE1hdGguYWJzKHByb2MuYXJyYXlCbG9ja0luZGljZXNbMF0pKXwwXHJcbiAgdmFyIG9yZGVycyA9IG5ldyBBcnJheShwcm9jLmFycmF5QXJncy5sZW5ndGgpXHJcbiAgdmFyIGR0eXBlcyA9IG5ldyBBcnJheShwcm9jLmFycmF5QXJncy5sZW5ndGgpXHJcbiAgZm9yKHZhciBpPTA7IGk8cHJvYy5hcnJheUFyZ3MubGVuZ3RoOyArK2kpIHtcclxuICAgIGR0eXBlc1tpXSA9IHR5cGVzaWdbMippXVxyXG4gICAgb3JkZXJzW2ldID0gdHlwZXNpZ1syKmkrMV1cclxuICB9XHJcbiAgXHJcbiAgLy9EZXRlcm1pbmUgd2hlcmUgYmxvY2sgYW5kIGxvb3AgaW5kaWNlcyBzdGFydCBhbmQgZW5kXHJcbiAgdmFyIGJsb2NrQmVnaW4gPSBbXSwgYmxvY2tFbmQgPSBbXSAvLyBUaGVzZSBpbmRpY2VzIGFyZSBleHBvc2VkIGFzIGJsb2Nrc1xyXG4gIHZhciBsb29wQmVnaW4gPSBbXSwgbG9vcEVuZCA9IFtdIC8vIFRoZXNlIGluZGljZXMgYXJlIGl0ZXJhdGVkIG92ZXJcclxuICB2YXIgbG9vcE9yZGVycyA9IFtdIC8vIG9yZGVycyByZXN0cmljdGVkIHRvIHRoZSBsb29wIGluZGljZXNcclxuICBmb3IodmFyIGk9MDsgaTxwcm9jLmFycmF5QXJncy5sZW5ndGg7ICsraSkge1xyXG4gICAgaWYgKHByb2MuYXJyYXlCbG9ja0luZGljZXNbaV08MCkge1xyXG4gICAgICBsb29wQmVnaW4ucHVzaCgwKVxyXG4gICAgICBsb29wRW5kLnB1c2goZGltZW5zaW9uKVxyXG4gICAgICBibG9ja0JlZ2luLnB1c2goZGltZW5zaW9uKVxyXG4gICAgICBibG9ja0VuZC5wdXNoKGRpbWVuc2lvbitwcm9jLmFycmF5QmxvY2tJbmRpY2VzW2ldKVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9vcEJlZ2luLnB1c2gocHJvYy5hcnJheUJsb2NrSW5kaWNlc1tpXSkgLy8gTm9uLW5lZ2F0aXZlXHJcbiAgICAgIGxvb3BFbmQucHVzaChwcm9jLmFycmF5QmxvY2tJbmRpY2VzW2ldK2RpbWVuc2lvbilcclxuICAgICAgYmxvY2tCZWdpbi5wdXNoKDApXHJcbiAgICAgIGJsb2NrRW5kLnB1c2gocHJvYy5hcnJheUJsb2NrSW5kaWNlc1tpXSlcclxuICAgIH1cclxuICAgIHZhciBuZXdPcmRlciA9IFtdXHJcbiAgICBmb3IodmFyIGo9MDsgajxvcmRlcnNbaV0ubGVuZ3RoOyBqKyspIHtcclxuICAgICAgaWYgKGxvb3BCZWdpbltpXTw9b3JkZXJzW2ldW2pdICYmIG9yZGVyc1tpXVtqXTxsb29wRW5kW2ldKSB7XHJcbiAgICAgICAgbmV3T3JkZXIucHVzaChvcmRlcnNbaV1bal0tbG9vcEJlZ2luW2ldKSAvLyBJZiB0aGlzIGlzIGEgbG9vcCBpbmRleCwgcHV0IGl0IGluIG5ld09yZGVyLCBzdWJ0cmFjdGluZyBsb29wQmVnaW4sIHRvIG1ha2Ugc3VyZSB0aGF0IGFsbCBsb29wT3JkZXJzIGFyZSB1c2luZyBhIGNvbW1vbiBzZXQgb2YgaW5kaWNlcy5cclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgbG9vcE9yZGVycy5wdXNoKG5ld09yZGVyKVxyXG4gIH1cclxuXHJcbiAgLy9GaXJzdCBjcmVhdGUgYXJndW1lbnRzIGZvciBwcm9jZWR1cmVcclxuICB2YXIgYXJnbGlzdCA9IFtcIlNTXCJdIC8vIFNTIGlzIHRoZSBvdmVyYWxsIHNoYXBlIG92ZXIgd2hpY2ggd2UgaXRlcmF0ZVxyXG4gIHZhciBjb2RlID0gW1wiJ3VzZSBzdHJpY3QnXCJdXHJcbiAgdmFyIHZhcnMgPSBbXVxyXG4gIFxyXG4gIGZvcih2YXIgaj0wOyBqPGRpbWVuc2lvbjsgKytqKSB7XHJcbiAgICB2YXJzLnB1c2goW1wic1wiLCBqLCBcIj1TU1tcIiwgaiwgXCJdXCJdLmpvaW4oXCJcIikpIC8vIFRoZSBsaW1pdHMgZm9yIGVhY2ggZGltZW5zaW9uLlxyXG4gIH1cclxuICBmb3IodmFyIGk9MDsgaTxwcm9jLmFycmF5QXJncy5sZW5ndGg7ICsraSkge1xyXG4gICAgYXJnbGlzdC5wdXNoKFwiYVwiK2kpIC8vIEFjdHVhbCBkYXRhIGFycmF5XHJcbiAgICBhcmdsaXN0LnB1c2goXCJ0XCIraSkgLy8gU3RyaWRlc1xyXG4gICAgYXJnbGlzdC5wdXNoKFwicFwiK2kpIC8vIE9mZnNldCBpbiB0aGUgYXJyYXkgYXQgd2hpY2ggdGhlIGRhdGEgc3RhcnRzIChhbHNvIHVzZWQgZm9yIGl0ZXJhdGluZyBvdmVyIHRoZSBkYXRhKVxyXG4gICAgXHJcbiAgICBmb3IodmFyIGo9MDsgajxkaW1lbnNpb247ICsraikgeyAvLyBVbnBhY2sgdGhlIHN0cmlkZXMgaW50byB2YXJzIGZvciBsb29waW5nXHJcbiAgICAgIHZhcnMucHVzaChbXCJ0XCIsaSxcInBcIixqLFwiPXRcIixpLFwiW1wiLGxvb3BCZWdpbltpXStqLFwiXVwiXS5qb2luKFwiXCIpKVxyXG4gICAgfVxyXG4gICAgXHJcbiAgICBmb3IodmFyIGo9MDsgajxNYXRoLmFicyhwcm9jLmFycmF5QmxvY2tJbmRpY2VzW2ldKTsgKytqKSB7IC8vIFVucGFjayB0aGUgc3RyaWRlcyBpbnRvIHZhcnMgZm9yIGJsb2NrIGl0ZXJhdGlvblxyXG4gICAgICB2YXJzLnB1c2goW1widFwiLGksXCJiXCIsaixcIj10XCIsaSxcIltcIixibG9ja0JlZ2luW2ldK2osXCJdXCJdLmpvaW4oXCJcIikpXHJcbiAgICB9XHJcbiAgfVxyXG4gIGZvcih2YXIgaT0wOyBpPHByb2Muc2NhbGFyQXJncy5sZW5ndGg7ICsraSkge1xyXG4gICAgYXJnbGlzdC5wdXNoKFwiWVwiICsgaSlcclxuICB9XHJcbiAgaWYocHJvYy5zaGFwZUFyZ3MubGVuZ3RoID4gMCkge1xyXG4gICAgdmFycy5wdXNoKFwic2hhcGU9U1Muc2xpY2UoMClcIikgLy8gTWFrZXMgdGhlIHNoYXBlIG92ZXIgd2hpY2ggd2UgaXRlcmF0ZSBhdmFpbGFibGUgdG8gdGhlIHVzZXIgZGVmaW5lZCBmdW5jdGlvbnMgKHNvIHlvdSBjYW4gdXNlIHdpZHRoL2hlaWdodCBmb3IgZXhhbXBsZSlcclxuICB9XHJcbiAgaWYocHJvYy5pbmRleEFyZ3MubGVuZ3RoID4gMCkge1xyXG4gICAgLy8gUHJlcGFyZSBhbiBhcnJheSB0byBrZWVwIHRyYWNrIG9mIHRoZSAobG9naWNhbCkgaW5kaWNlcywgaW5pdGlhbGl6ZWQgdG8gZGltZW5zaW9uIHplcm9lcy5cclxuICAgIHZhciB6ZXJvcyA9IG5ldyBBcnJheShkaW1lbnNpb24pXHJcbiAgICBmb3IodmFyIGk9MDsgaTxkaW1lbnNpb247ICsraSkge1xyXG4gICAgICB6ZXJvc1tpXSA9IFwiMFwiXHJcbiAgICB9XHJcbiAgICB2YXJzLnB1c2goW1wiaW5kZXg9W1wiLCB6ZXJvcy5qb2luKFwiLFwiKSwgXCJdXCJdLmpvaW4oXCJcIikpXHJcbiAgfVxyXG4gIGZvcih2YXIgaT0wOyBpPHByb2Mub2Zmc2V0QXJncy5sZW5ndGg7ICsraSkgeyAvLyBPZmZzZXQgYXJndW1lbnRzIHVzZWQgZm9yIHN0ZW5jaWwgb3BlcmF0aW9uc1xyXG4gICAgdmFyIG9mZl9hcmcgPSBwcm9jLm9mZnNldEFyZ3NbaV1cclxuICAgIHZhciBpbml0X3N0cmluZyA9IFtdXHJcbiAgICBmb3IodmFyIGo9MDsgajxvZmZfYXJnLm9mZnNldC5sZW5ndGg7ICsraikge1xyXG4gICAgICBpZihvZmZfYXJnLm9mZnNldFtqXSA9PT0gMCkge1xyXG4gICAgICAgIGNvbnRpbnVlXHJcbiAgICAgIH0gZWxzZSBpZihvZmZfYXJnLm9mZnNldFtqXSA9PT0gMSkge1xyXG4gICAgICAgIGluaXRfc3RyaW5nLnB1c2goW1widFwiLCBvZmZfYXJnLmFycmF5LCBcInBcIiwgal0uam9pbihcIlwiKSkgICAgICBcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBpbml0X3N0cmluZy5wdXNoKFtvZmZfYXJnLm9mZnNldFtqXSwgXCIqdFwiLCBvZmZfYXJnLmFycmF5LCBcInBcIiwgal0uam9pbihcIlwiKSlcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgaWYoaW5pdF9zdHJpbmcubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgIHZhcnMucHVzaChcInFcIiArIGkgKyBcIj0wXCIpXHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB2YXJzLnB1c2goW1wicVwiLCBpLCBcIj1cIiwgaW5pdF9zdHJpbmcuam9pbihcIitcIildLmpvaW4oXCJcIikpXHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvL1ByZXBhcmUgdGhpcyB2YXJpYWJsZXNcclxuICB2YXIgdGhpc1ZhcnMgPSB1bmlxKFtdLmNvbmNhdChwcm9jLnByZS50aGlzVmFycylcclxuICAgICAgICAgICAgICAgICAgICAgIC5jb25jYXQocHJvYy5ib2R5LnRoaXNWYXJzKVxyXG4gICAgICAgICAgICAgICAgICAgICAgLmNvbmNhdChwcm9jLnBvc3QudGhpc1ZhcnMpKVxyXG4gIHZhcnMgPSB2YXJzLmNvbmNhdCh0aGlzVmFycylcclxuICBjb2RlLnB1c2goXCJ2YXIgXCIgKyB2YXJzLmpvaW4oXCIsXCIpKVxyXG4gIGZvcih2YXIgaT0wOyBpPHByb2MuYXJyYXlBcmdzLmxlbmd0aDsgKytpKSB7XHJcbiAgICBjb2RlLnB1c2goXCJwXCIraStcInw9MFwiKVxyXG4gIH1cclxuICBcclxuICAvL0lubGluZSBwcmVsdWRlXHJcbiAgaWYocHJvYy5wcmUuYm9keS5sZW5ndGggPiAzKSB7XHJcbiAgICBjb2RlLnB1c2gocHJvY2Vzc0Jsb2NrKHByb2MucHJlLCBwcm9jLCBkdHlwZXMpKVxyXG4gIH1cclxuXHJcbiAgLy9Qcm9jZXNzIGJvZHlcclxuICB2YXIgYm9keSA9IHByb2Nlc3NCbG9jayhwcm9jLmJvZHksIHByb2MsIGR0eXBlcylcclxuICB2YXIgbWF0Y2hlZCA9IGNvdW50TWF0Y2hlcyhsb29wT3JkZXJzKVxyXG4gIGlmKG1hdGNoZWQgPCBkaW1lbnNpb24pIHtcclxuICAgIGNvZGUucHVzaChvdXRlckZpbGwobWF0Y2hlZCwgbG9vcE9yZGVyc1swXSwgcHJvYywgYm9keSkpIC8vIFRPRE86IFJhdGhlciB0aGFuIHBhc3NpbmcgbG9vcE9yZGVyc1swXSwgaXQgbWlnaHQgYmUgaW50ZXJlc3RpbmcgdG8gbG9vayBhdCBwYXNzaW5nIGFuIG9yZGVyIHRoYXQgcmVwcmVzZW50cyB0aGUgbWFqb3JpdHkgb2YgdGhlIGFyZ3VtZW50cyBmb3IgZXhhbXBsZS5cclxuICB9IGVsc2Uge1xyXG4gICAgY29kZS5wdXNoKGlubmVyRmlsbChsb29wT3JkZXJzWzBdLCBwcm9jLCBib2R5KSlcclxuICB9XHJcblxyXG4gIC8vSW5saW5lIGVwaWxvZ1xyXG4gIGlmKHByb2MucG9zdC5ib2R5Lmxlbmd0aCA+IDMpIHtcclxuICAgIGNvZGUucHVzaChwcm9jZXNzQmxvY2socHJvYy5wb3N0LCBwcm9jLCBkdHlwZXMpKVxyXG4gIH1cclxuICBcclxuICBpZihwcm9jLmRlYnVnKSB7XHJcbiAgICBjb25zb2xlLmxvZyhcIi0tLS0tR2VuZXJhdGVkIGN3aXNlIHJvdXRpbmUgZm9yIFwiLCB0eXBlc2lnLCBcIjpcXG5cIiArIGNvZGUuam9pbihcIlxcblwiKSArIFwiXFxuLS0tLS0tLS0tLVwiKVxyXG4gIH1cclxuICBcclxuICB2YXIgbG9vcE5hbWUgPSBbKHByb2MuZnVuY05hbWV8fFwidW5uYW1lZFwiKSwgXCJfY3dpc2VfbG9vcF9cIiwgb3JkZXJzWzBdLmpvaW4oXCJzXCIpLFwibVwiLG1hdGNoZWQsdHlwZVN1bW1hcnkoZHR5cGVzKV0uam9pbihcIlwiKVxyXG4gIHZhciBmID0gbmV3IEZ1bmN0aW9uKFtcImZ1bmN0aW9uIFwiLGxvb3BOYW1lLFwiKFwiLCBhcmdsaXN0LmpvaW4oXCIsXCIpLFwiKXtcIiwgY29kZS5qb2luKFwiXFxuXCIpLFwifSByZXR1cm4gXCIsIGxvb3BOYW1lXS5qb2luKFwiXCIpKVxyXG4gIHJldHVybiBmKClcclxufVxyXG5tb2R1bGUuZXhwb3J0cyA9IGdlbmVyYXRlQ1dpc2VPcFxyXG4iLCJcInVzZSBzdHJpY3RcIlxyXG5cclxuLy8gVGhlIGZ1bmN0aW9uIGJlbG93IGlzIGNhbGxlZCB3aGVuIGNvbnN0cnVjdGluZyBhIGN3aXNlIGZ1bmN0aW9uIG9iamVjdCwgYW5kIGRvZXMgdGhlIGZvbGxvd2luZzpcclxuLy8gQSBmdW5jdGlvbiBvYmplY3QgaXMgY29uc3RydWN0ZWQgd2hpY2ggYWNjZXB0cyBhcyBhcmd1bWVudCBhIGNvbXBpbGF0aW9uIGZ1bmN0aW9uIGFuZCByZXR1cm5zIGFub3RoZXIgZnVuY3Rpb24uXHJcbi8vIEl0IGlzIHRoaXMgb3RoZXIgZnVuY3Rpb24gdGhhdCBpcyBldmVudHVhbGx5IHJldHVybmVkIGJ5IGNyZWF0ZVRodW5rLCBhbmQgdGhpcyBmdW5jdGlvbiBpcyB0aGUgb25lIHRoYXQgYWN0dWFsbHlcclxuLy8gY2hlY2tzIHdoZXRoZXIgYSBjZXJ0YWluIHBhdHRlcm4gb2YgYXJndW1lbnRzIGhhcyBhbHJlYWR5IGJlZW4gdXNlZCBiZWZvcmUgYW5kIGNvbXBpbGVzIG5ldyBsb29wcyBhcyBuZWVkZWQuXHJcbi8vIFRoZSBjb21waWxhdGlvbiBwYXNzZWQgdG8gdGhlIGZpcnN0IGZ1bmN0aW9uIG9iamVjdCBpcyB1c2VkIGZvciBjb21waWxpbmcgbmV3IGZ1bmN0aW9ucy5cclxuLy8gT25jZSB0aGlzIGZ1bmN0aW9uIG9iamVjdCBpcyBjcmVhdGVkLCBpdCBpcyBjYWxsZWQgd2l0aCBjb21waWxlIGFzIGFyZ3VtZW50LCB3aGVyZSB0aGUgZmlyc3QgYXJndW1lbnQgb2YgY29tcGlsZVxyXG4vLyBpcyBib3VuZCB0byBcInByb2NcIiAoZXNzZW50aWFsbHkgY29udGFpbmluZyBhIHByZXByb2Nlc3NlZCB2ZXJzaW9uIG9mIHRoZSB1c2VyIGFyZ3VtZW50cyB0byBjd2lzZSkuXHJcbi8vIFNvIGNyZWF0ZVRodW5rIHJvdWdobHkgd29ya3MgbGlrZSB0aGlzOlxyXG4vLyBmdW5jdGlvbiBjcmVhdGVUaHVuayhwcm9jKSB7XHJcbi8vICAgdmFyIHRodW5rID0gZnVuY3Rpb24oY29tcGlsZUJvdW5kKSB7XHJcbi8vICAgICB2YXIgQ0FDSEVEID0ge31cclxuLy8gICAgIHJldHVybiBmdW5jdGlvbihhcnJheXMgYW5kIHNjYWxhcnMpIHtcclxuLy8gICAgICAgaWYgKGR0eXBlIGFuZCBvcmRlciBvZiBhcnJheXMgaW4gQ0FDSEVEKSB7XHJcbi8vICAgICAgICAgdmFyIGZ1bmMgPSBDQUNIRURbZHR5cGUgYW5kIG9yZGVyIG9mIGFycmF5c11cclxuLy8gICAgICAgfSBlbHNlIHtcclxuLy8gICAgICAgICB2YXIgZnVuYyA9IENBQ0hFRFtkdHlwZSBhbmQgb3JkZXIgb2YgYXJyYXlzXSA9IGNvbXBpbGVCb3VuZChkdHlwZSBhbmQgb3JkZXIgb2YgYXJyYXlzKVxyXG4vLyAgICAgICB9XHJcbi8vICAgICAgIHJldHVybiBmdW5jKGFycmF5cyBhbmQgc2NhbGFycylcclxuLy8gICAgIH1cclxuLy8gICB9XHJcbi8vICAgcmV0dXJuIHRodW5rKGNvbXBpbGUuYmluZDEocHJvYykpXHJcbi8vIH1cclxuXHJcbnZhciBjb21waWxlID0gcmVxdWlyZShcIi4vY29tcGlsZS5qc1wiKVxyXG5cclxuZnVuY3Rpb24gY3JlYXRlVGh1bmsocHJvYykge1xyXG4gIHZhciBjb2RlID0gW1wiJ3VzZSBzdHJpY3QnXCIsIFwidmFyIENBQ0hFRD17fVwiXVxyXG4gIHZhciB2YXJzID0gW11cclxuICB2YXIgdGh1bmtOYW1lID0gcHJvYy5mdW5jTmFtZSArIFwiX2N3aXNlX3RodW5rXCJcclxuICBcclxuICAvL0J1aWxkIHRodW5rXHJcbiAgY29kZS5wdXNoKFtcInJldHVybiBmdW5jdGlvbiBcIiwgdGh1bmtOYW1lLCBcIihcIiwgcHJvYy5zaGltQXJncy5qb2luKFwiLFwiKSwgXCIpe1wiXS5qb2luKFwiXCIpKVxyXG4gIHZhciB0eXBlc2lnID0gW11cclxuICB2YXIgc3RyaW5nX3R5cGVzaWcgPSBbXVxyXG4gIHZhciBwcm9jX2FyZ3MgPSBbW1wiYXJyYXlcIixwcm9jLmFycmF5QXJnc1swXSxcIi5zaGFwZS5zbGljZShcIiwgLy8gU2xpY2Ugc2hhcGUgc28gdGhhdCB3ZSBvbmx5IHJldGFpbiB0aGUgc2hhcGUgb3ZlciB3aGljaCB3ZSBpdGVyYXRlICh3aGljaCBnZXRzIHBhc3NlZCB0byB0aGUgY3dpc2Ugb3BlcmF0b3IgYXMgU1MpLlxyXG4gICAgICAgICAgICAgICAgICAgIE1hdGgubWF4KDAscHJvYy5hcnJheUJsb2NrSW5kaWNlc1swXSkscHJvYy5hcnJheUJsb2NrSW5kaWNlc1swXTwwPyhcIixcIitwcm9jLmFycmF5QmxvY2tJbmRpY2VzWzBdK1wiKVwiKTpcIilcIl0uam9pbihcIlwiKV1cclxuICB2YXIgc2hhcGVMZW5ndGhDb25kaXRpb25zID0gW10sIHNoYXBlQ29uZGl0aW9ucyA9IFtdXHJcbiAgLy8gUHJvY2VzcyBhcnJheSBhcmd1bWVudHNcclxuICBmb3IodmFyIGk9MDsgaTxwcm9jLmFycmF5QXJncy5sZW5ndGg7ICsraSkge1xyXG4gICAgdmFyIGogPSBwcm9jLmFycmF5QXJnc1tpXVxyXG4gICAgdmFycy5wdXNoKFtcInRcIiwgaiwgXCI9YXJyYXlcIiwgaiwgXCIuZHR5cGUsXCIsXHJcbiAgICAgICAgICAgICAgIFwiclwiLCBqLCBcIj1hcnJheVwiLCBqLCBcIi5vcmRlclwiXS5qb2luKFwiXCIpKVxyXG4gICAgdHlwZXNpZy5wdXNoKFwidFwiICsgailcclxuICAgIHR5cGVzaWcucHVzaChcInJcIiArIGopXHJcbiAgICBzdHJpbmdfdHlwZXNpZy5wdXNoKFwidFwiK2opXHJcbiAgICBzdHJpbmdfdHlwZXNpZy5wdXNoKFwiclwiK2orXCIuam9pbigpXCIpXHJcbiAgICBwcm9jX2FyZ3MucHVzaChcImFycmF5XCIgKyBqICsgXCIuZGF0YVwiKVxyXG4gICAgcHJvY19hcmdzLnB1c2goXCJhcnJheVwiICsgaiArIFwiLnN0cmlkZVwiKVxyXG4gICAgcHJvY19hcmdzLnB1c2goXCJhcnJheVwiICsgaiArIFwiLm9mZnNldHwwXCIpXHJcbiAgICBpZiAoaT4wKSB7IC8vIEdhdGhlciBjb25kaXRpb25zIHRvIGNoZWNrIGZvciBzaGFwZSBlcXVhbGl0eSAoaWdub3JpbmcgYmxvY2sgaW5kaWNlcylcclxuICAgICAgc2hhcGVMZW5ndGhDb25kaXRpb25zLnB1c2goXCJhcnJheVwiICsgcHJvYy5hcnJheUFyZ3NbMF0gKyBcIi5zaGFwZS5sZW5ndGg9PT1hcnJheVwiICsgaiArIFwiLnNoYXBlLmxlbmd0aCtcIiArIChNYXRoLmFicyhwcm9jLmFycmF5QmxvY2tJbmRpY2VzWzBdKS1NYXRoLmFicyhwcm9jLmFycmF5QmxvY2tJbmRpY2VzW2ldKSkpXHJcbiAgICAgIHNoYXBlQ29uZGl0aW9ucy5wdXNoKFwiYXJyYXlcIiArIHByb2MuYXJyYXlBcmdzWzBdICsgXCIuc2hhcGVbc2hhcGVJbmRleCtcIiArIE1hdGgubWF4KDAscHJvYy5hcnJheUJsb2NrSW5kaWNlc1swXSkgKyBcIl09PT1hcnJheVwiICsgaiArIFwiLnNoYXBlW3NoYXBlSW5kZXgrXCIgKyBNYXRoLm1heCgwLHByb2MuYXJyYXlCbG9ja0luZGljZXNbaV0pICsgXCJdXCIpXHJcbiAgICB9XHJcbiAgfVxyXG4gIC8vIENoZWNrIGZvciBzaGFwZSBlcXVhbGl0eVxyXG4gIGlmIChwcm9jLmFycmF5QXJncy5sZW5ndGggPiAxKSB7XHJcbiAgICBjb2RlLnB1c2goXCJpZiAoIShcIiArIHNoYXBlTGVuZ3RoQ29uZGl0aW9ucy5qb2luKFwiICYmIFwiKSArIFwiKSkgdGhyb3cgbmV3IEVycm9yKCdjd2lzZTogQXJyYXlzIGRvIG5vdCBhbGwgaGF2ZSB0aGUgc2FtZSBkaW1lbnNpb25hbGl0eSEnKVwiKVxyXG4gICAgY29kZS5wdXNoKFwiZm9yKHZhciBzaGFwZUluZGV4PWFycmF5XCIgKyBwcm9jLmFycmF5QXJnc1swXSArIFwiLnNoYXBlLmxlbmd0aC1cIiArIE1hdGguYWJzKHByb2MuYXJyYXlCbG9ja0luZGljZXNbMF0pICsgXCI7IHNoYXBlSW5kZXgtLT4wOykge1wiKVxyXG4gICAgY29kZS5wdXNoKFwiaWYgKCEoXCIgKyBzaGFwZUNvbmRpdGlvbnMuam9pbihcIiAmJiBcIikgKyBcIikpIHRocm93IG5ldyBFcnJvcignY3dpc2U6IEFycmF5cyBkbyBub3QgYWxsIGhhdmUgdGhlIHNhbWUgc2hhcGUhJylcIilcclxuICAgIGNvZGUucHVzaChcIn1cIilcclxuICB9XHJcbiAgLy8gUHJvY2VzcyBzY2FsYXIgYXJndW1lbnRzXHJcbiAgZm9yKHZhciBpPTA7IGk8cHJvYy5zY2FsYXJBcmdzLmxlbmd0aDsgKytpKSB7XHJcbiAgICBwcm9jX2FyZ3MucHVzaChcInNjYWxhclwiICsgcHJvYy5zY2FsYXJBcmdzW2ldKVxyXG4gIH1cclxuICAvLyBDaGVjayBmb3IgY2FjaGVkIGZ1bmN0aW9uIChhbmQgaWYgbm90IHByZXNlbnQsIGdlbmVyYXRlIGl0KVxyXG4gIHZhcnMucHVzaChbXCJ0eXBlPVtcIiwgc3RyaW5nX3R5cGVzaWcuam9pbihcIixcIiksIFwiXS5qb2luKClcIl0uam9pbihcIlwiKSlcclxuICB2YXJzLnB1c2goXCJwcm9jPUNBQ0hFRFt0eXBlXVwiKVxyXG4gIGNvZGUucHVzaChcInZhciBcIiArIHZhcnMuam9pbihcIixcIikpXHJcbiAgXHJcbiAgY29kZS5wdXNoKFtcImlmKCFwcm9jKXtcIixcclxuICAgICAgICAgICAgIFwiQ0FDSEVEW3R5cGVdPXByb2M9Y29tcGlsZShbXCIsIHR5cGVzaWcuam9pbihcIixcIiksIFwiXSl9XCIsXHJcbiAgICAgICAgICAgICBcInJldHVybiBwcm9jKFwiLCBwcm9jX2FyZ3Muam9pbihcIixcIiksIFwiKX1cIl0uam9pbihcIlwiKSlcclxuXHJcbiAgaWYocHJvYy5kZWJ1Zykge1xyXG4gICAgY29uc29sZS5sb2coXCItLS0tLUdlbmVyYXRlZCB0aHVuazpcXG5cIiArIGNvZGUuam9pbihcIlxcblwiKSArIFwiXFxuLS0tLS0tLS0tLVwiKVxyXG4gIH1cclxuICBcclxuICAvL0NvbXBpbGUgdGh1bmtcclxuICB2YXIgdGh1bmsgPSBuZXcgRnVuY3Rpb24oXCJjb21waWxlXCIsIGNvZGUuam9pbihcIlxcblwiKSlcclxuICByZXR1cm4gdGh1bmsoY29tcGlsZS5iaW5kKHVuZGVmaW5lZCwgcHJvYykpXHJcbn1cclxuXHJcbm1vZHVsZS5leHBvcnRzID0gY3JlYXRlVGh1bmtcclxuIiwiXCJ1c2Ugc3RyaWN0XCJcblxuZnVuY3Rpb24gdW5pcXVlX3ByZWQobGlzdCwgY29tcGFyZSkge1xuICB2YXIgcHRyID0gMVxuICAgICwgbGVuID0gbGlzdC5sZW5ndGhcbiAgICAsIGE9bGlzdFswXSwgYj1saXN0WzBdXG4gIGZvcih2YXIgaT0xOyBpPGxlbjsgKytpKSB7XG4gICAgYiA9IGFcbiAgICBhID0gbGlzdFtpXVxuICAgIGlmKGNvbXBhcmUoYSwgYikpIHtcbiAgICAgIGlmKGkgPT09IHB0cikge1xuICAgICAgICBwdHIrK1xuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuICAgICAgbGlzdFtwdHIrK10gPSBhXG4gICAgfVxuICB9XG4gIGxpc3QubGVuZ3RoID0gcHRyXG4gIHJldHVybiBsaXN0XG59XG5cbmZ1bmN0aW9uIHVuaXF1ZV9lcShsaXN0KSB7XG4gIHZhciBwdHIgPSAxXG4gICAgLCBsZW4gPSBsaXN0Lmxlbmd0aFxuICAgICwgYT1saXN0WzBdLCBiID0gbGlzdFswXVxuICBmb3IodmFyIGk9MTsgaTxsZW47ICsraSwgYj1hKSB7XG4gICAgYiA9IGFcbiAgICBhID0gbGlzdFtpXVxuICAgIGlmKGEgIT09IGIpIHtcbiAgICAgIGlmKGkgPT09IHB0cikge1xuICAgICAgICBwdHIrK1xuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuICAgICAgbGlzdFtwdHIrK10gPSBhXG4gICAgfVxuICB9XG4gIGxpc3QubGVuZ3RoID0gcHRyXG4gIHJldHVybiBsaXN0XG59XG5cbmZ1bmN0aW9uIHVuaXF1ZShsaXN0LCBjb21wYXJlLCBzb3J0ZWQpIHtcbiAgaWYobGlzdC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbGlzdFxuICB9XG4gIGlmKGNvbXBhcmUpIHtcbiAgICBpZighc29ydGVkKSB7XG4gICAgICBsaXN0LnNvcnQoY29tcGFyZSlcbiAgICB9XG4gICAgcmV0dXJuIHVuaXF1ZV9wcmVkKGxpc3QsIGNvbXBhcmUpXG4gIH1cbiAgaWYoIXNvcnRlZCkge1xuICAgIGxpc3Quc29ydCgpXG4gIH1cbiAgcmV0dXJuIHVuaXF1ZV9lcShsaXN0KVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHVuaXF1ZVxuIiwiXCJ1c2Ugc3RyaWN0XCJcblxudmFyIG5kYXJyYXkgPSByZXF1aXJlKFwibmRhcnJheVwiKVxudmFyIGRvX2NvbnZlcnQgPSByZXF1aXJlKFwiLi9kb0NvbnZlcnQuanNcIilcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBjb252ZXJ0KGFyciwgcmVzdWx0KSB7XG4gIHZhciBzaGFwZSA9IFtdLCBjID0gYXJyLCBzeiA9IDFcbiAgd2hpbGUoQXJyYXkuaXNBcnJheShjKSkge1xuICAgIHNoYXBlLnB1c2goYy5sZW5ndGgpXG4gICAgc3ogKj0gYy5sZW5ndGhcbiAgICBjID0gY1swXVxuICB9XG4gIGlmKHNoYXBlLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBuZGFycmF5KClcbiAgfVxuICBpZighcmVzdWx0KSB7XG4gICAgcmVzdWx0ID0gbmRhcnJheShuZXcgRmxvYXQ2NEFycmF5KHN6KSwgc2hhcGUpXG4gIH1cbiAgZG9fY29udmVydChyZXN1bHQsIGFycilcbiAgcmV0dXJuIHJlc3VsdFxufVxuIiwibW9kdWxlLmV4cG9ydHM9cmVxdWlyZSgnY3dpc2UtY29tcGlsZXInKSh7XCJhcmdzXCI6W1wiYXJyYXlcIixcInNjYWxhclwiLFwiaW5kZXhcIl0sXCJwcmVcIjp7XCJib2R5XCI6XCJ7fVwiLFwiYXJnc1wiOltdLFwidGhpc1ZhcnNcIjpbXSxcImxvY2FsVmFyc1wiOltdfSxcImJvZHlcIjp7XCJib2R5XCI6XCJ7XFxudmFyIF9pbmxpbmVfMV92PV9pbmxpbmVfMV9hcmcxXyxfaW5saW5lXzFfaVxcbmZvcihfaW5saW5lXzFfaT0wO19pbmxpbmVfMV9pPF9pbmxpbmVfMV9hcmcyXy5sZW5ndGgtMTsrK19pbmxpbmVfMV9pKSB7XFxuX2lubGluZV8xX3Y9X2lubGluZV8xX3ZbX2lubGluZV8xX2FyZzJfW19pbmxpbmVfMV9pXV1cXG59XFxuX2lubGluZV8xX2FyZzBfPV9pbmxpbmVfMV92W19pbmxpbmVfMV9hcmcyX1tfaW5saW5lXzFfYXJnMl8ubGVuZ3RoLTFdXVxcbn1cIixcImFyZ3NcIjpbe1wibmFtZVwiOlwiX2lubGluZV8xX2FyZzBfXCIsXCJsdmFsdWVcIjp0cnVlLFwicnZhbHVlXCI6ZmFsc2UsXCJjb3VudFwiOjF9LHtcIm5hbWVcIjpcIl9pbmxpbmVfMV9hcmcxX1wiLFwibHZhbHVlXCI6ZmFsc2UsXCJydmFsdWVcIjp0cnVlLFwiY291bnRcIjoxfSx7XCJuYW1lXCI6XCJfaW5saW5lXzFfYXJnMl9cIixcImx2YWx1ZVwiOmZhbHNlLFwicnZhbHVlXCI6dHJ1ZSxcImNvdW50XCI6NH1dLFwidGhpc1ZhcnNcIjpbXSxcImxvY2FsVmFyc1wiOltcIl9pbmxpbmVfMV9pXCIsXCJfaW5saW5lXzFfdlwiXX0sXCJwb3N0XCI6e1wiYm9keVwiOlwie31cIixcImFyZ3NcIjpbXSxcInRoaXNWYXJzXCI6W10sXCJsb2NhbFZhcnNcIjpbXX0sXCJmdW5jTmFtZVwiOlwiY29udmVydFwiLFwiYmxvY2tTaXplXCI6NjR9KVxuIiwiXCJ1c2Ugc3RyaWN0XCJcblxudmFyIG5kYXJyYXkgPSByZXF1aXJlKFwibmRhcnJheVwiKVxudmFyIG9wcyA9IHJlcXVpcmUoXCJuZGFycmF5LW9wc1wiKVxudmFyIHBvb2wgPSByZXF1aXJlKFwidHlwZWRhcnJheS1wb29sXCIpXG5cbmZ1bmN0aW9uIGNsb25lKGFycmF5KSB7XG4gIHZhciBkdHlwZSA9IGFycmF5LmR0eXBlXG4gIGlmKGR0eXBlID09PSBcImdlbmVyaWNcIiB8fCBkdHlwZSA9PT0gXCJhcnJheVwiKSB7XG4gICAgZHR5cGUgPSBcImRvdWJsZVwiXG4gIH1cbiAgdmFyIGRhdGEgPSBwb29sLm1hbGxvYyhhcnJheS5zaXplLCBkdHlwZSlcbiAgdmFyIHJlc3VsdCA9IG5kYXJyYXkoZGF0YSwgYXJyYXkuc2hhcGUpXG4gIG9wcy5hc3NpZ24ocmVzdWx0LCBhcnJheSlcbiAgcmV0dXJuIHJlc3VsdFxufVxuZXhwb3J0cy5jbG9uZSA9IGNsb25lXG5cbmZ1bmN0aW9uIG1hbGxvYyhzaGFwZSwgZHR5cGUpIHtcbiAgaWYoIWR0eXBlKSB7XG4gICAgZHR5cGUgPSBcImRvdWJsZVwiXG4gIH1cbiAgdmFyIHN6ID0gMVxuICB2YXIgc3RyaWRlID0gbmV3IEFycmF5KHNoYXBlLmxlbmd0aClcbiAgZm9yKHZhciBpPXNoYXBlLmxlbmd0aC0xOyBpPj0wOyAtLWkpIHtcbiAgICBzdHJpZGVbaV0gPSBzelxuICAgIHN6ICo9IHNoYXBlW2ldXG4gIH1cbiAgcmV0dXJuIG5kYXJyYXkocG9vbC5tYWxsb2Moc3osIGR0eXBlKSwgc2hhcGUsIHN0cmlkZSwgMClcbn1cbmV4cG9ydHMubWFsbG9jID0gbWFsbG9jXG5cbmZ1bmN0aW9uIGZyZWUoYXJyYXkpIHtcbiAgaWYoYXJyYXkuZHR5cGUgPT09IFwiZ2VuZXJpY1wiIHx8IGFycmF5LmR0eXBlID09PSBcImFycmF5XCIpIHtcbiAgICByZXR1cm5cbiAgfVxuICBwb29sLmZyZWUoYXJyYXkuZGF0YSlcbn1cbmV4cG9ydHMuZnJlZSA9IGZyZWVcblxuZnVuY3Rpb24gemVyb3Moc2hhcGUsIGR0eXBlKSB7XG4gIGlmKCFkdHlwZSkge1xuICAgIGR0eXBlID0gXCJkb3VibGVcIlxuICB9XG5cbiAgdmFyIHN6ID0gMVxuICB2YXIgc3RyaWRlID0gbmV3IEFycmF5KHNoYXBlLmxlbmd0aClcbiAgZm9yKHZhciBpPXNoYXBlLmxlbmd0aC0xOyBpPj0wOyAtLWkpIHtcbiAgICBzdHJpZGVbaV0gPSBzelxuICAgIHN6ICo9IHNoYXBlW2ldXG4gIH1cbiAgdmFyIGJ1ZiA9IHBvb2wubWFsbG9jKHN6LCBkdHlwZSlcbiAgZm9yKHZhciBpPTA7IGk8c3o7ICsraSkge1xuICAgIGJ1ZltpXSA9IDBcbiAgfVxuICByZXR1cm4gbmRhcnJheShidWYsIHNoYXBlLCBzdHJpZGUsIDApXG59XG5leHBvcnRzLnplcm9zID0gemVyb3NcblxuZnVuY3Rpb24gb25lcyhzaGFwZSwgZHR5cGUpIHtcbiAgaWYoIWR0eXBlKSB7XG4gICAgZHR5cGUgPSBcImRvdWJsZVwiXG4gIH1cblxuICB2YXIgc3ogPSAxXG4gIHZhciBzdHJpZGUgPSBuZXcgQXJyYXkoc2hhcGUubGVuZ3RoKVxuICBmb3IodmFyIGk9c2hhcGUubGVuZ3RoLTE7IGk+PTA7IC0taSkge1xuICAgIHN0cmlkZVtpXSA9IHN6XG4gICAgc3ogKj0gc2hhcGVbaV1cbiAgfVxuICB2YXIgYnVmID0gcG9vbC5tYWxsb2Moc3osIGR0eXBlKVxuICBmb3IodmFyIGk9MDsgaTxzejsgKytpKSB7XG4gICAgYnVmW2ldID0gMVxuICB9XG4gIHJldHVybiBuZGFycmF5KGJ1Ziwgc2hhcGUsIHN0cmlkZSwgMClcbn1cbmV4cG9ydHMub25lcyA9IG9uZXNcblxuZnVuY3Rpb24gZXllKHNoYXBlLCBkdHlwZSkge1xuICB2YXIgaSwgb2Zmc2V0XG4gIGlmKCFkdHlwZSkge1xuICAgIGR0eXBlID0gXCJkb3VibGVcIlxuICB9XG5cbiAgdmFyIHN6ID0gMVxuICB2YXIgc3RyaWRlID0gbmV3IEFycmF5KHNoYXBlLmxlbmd0aClcbiAgZm9yKGk9c2hhcGUubGVuZ3RoLTE7IGk+PTA7IC0taSkge1xuICAgIHN0cmlkZVtpXSA9IHN6XG4gICAgc3ogKj0gc2hhcGVbaV1cbiAgfVxuICB2YXIgYnVmID0gcG9vbC5tYWxsb2Moc3osIGR0eXBlKVxuICBmb3IoaT0wOyBpPHN6OyArK2kpIHtcbiAgICBidWZbaV0gPSAwXG4gIH1cbiAgdmFyIG1pbmRpbSA9IEluZmluaXR5XG4gIHZhciBvZmZzdW0gPSAwXG4gIGZvciggaT1zaGFwZS5sZW5ndGgtMTsgaT49MDsgaS0tKSB7XG4gICAgb2Zmc3VtICs9IHN0cmlkZVtpXVxuICAgIG1pbmRpbSA9IE1hdGgubWluKG1pbmRpbSxzaGFwZVtpXSlcbiAgfVxuICBmb3IoaT0wLG9mZnNldD0wOyBpPG1pbmRpbTsgaSsrLG9mZnNldCs9b2Zmc3VtKSB7XG4gICAgYnVmW29mZnNldF0gPSAxXG4gIH1cbiAgcmV0dXJuIG5kYXJyYXkoYnVmLCBzaGFwZSwgc3RyaWRlLCAwKVxufVxuZXhwb3J0cy5leWUgPSBleWVcbiIsIlwidXNlIHN0cmljdFwiXG5cbm1vZHVsZS5leHBvcnRzID0gbmRTZWxlY3Rcbm1vZHVsZS5leHBvcnRzLmNvbXBpbGUgPSBsb29rdXBDYWNoZVxuXG4vL01hY3Jvc1xudmFyIEFSUkFZID0gXCJhXCJcbnZhciBSQU5LID0gXCJLXCJcbnZhciBDTVAgPSBcIkNcIlxudmFyIERBVEEgPSBcImRcIlxudmFyIE9GRlNFVCA9IFwib1wiXG52YXIgUk5EID0gXCJSXCJcbnZhciBUTVAgPSBcIlRcIlxudmFyIExPID0gXCJMXCJcbnZhciBISSA9IFwiSFwiXG52YXIgUElWT1QgPSBcIlhcIlxuZnVuY3Rpb24gU0hBUEUoaSkge1xuICByZXR1cm4gXCJzXCIgKyBpXG59XG5mdW5jdGlvbiBTVFJJREUoaSkge1xuICByZXR1cm4gXCJ0XCIgKyBpXG59XG5mdW5jdGlvbiBTVEVQKGkpIHtcbiAgcmV0dXJuIFwidVwiICsgaVxufVxuZnVuY3Rpb24gU1RFUF9DTVAoaSkge1xuICByZXR1cm4gXCJ2XCIgKyBpXG59XG5mdW5jdGlvbiBJTkRFWChpKSB7XG4gIHJldHVybiBcImlcIiArIGlcbn1cbmZ1bmN0aW9uIFBJQ0soaSkge1xuICByZXR1cm4gXCJwXCIgKyBpXG59XG5mdW5jdGlvbiBQVFIoaSkge1xuICByZXR1cm4gXCJ4XCIgKyBpXG59XG5cbi8vQ3JlYXRlIG5ldyBvcmRlciB3aGVyZSBpbmRleCAwIGlzIHNsb3dlc3QgaW5kZXhcbmZ1bmN0aW9uIHBlcm11dGVPcmRlcihvcmRlcikge1xuICB2YXIgbm9yZGVyID0gb3JkZXIuc2xpY2UoKVxuICBub3JkZXIuc3BsaWNlKG9yZGVyLmluZGV4T2YoMCksIDEpXG4gIG5vcmRlci51bnNoaWZ0KDApXG4gIHJldHVybiBub3JkZXJcbn1cblxuLy9HZW5lcmF0ZSBxdWljayBzZWxlY3QgcHJvY2VkdXJlXG5mdW5jdGlvbiBjb21waWxlUXVpY2tTZWxlY3Qob3JkZXIsIHVzZUNvbXBhcmUsIGR0eXBlKSB7XG4gIG9yZGVyID0gcGVybXV0ZU9yZGVyKG9yZGVyKVxuXG4gIHZhciBkaW1lbnNpb24gPSBvcmRlci5sZW5ndGhcbiAgdmFyIHVzZUdldHRlciA9IChkdHlwZSA9PT0gXCJnZW5lcmljXCIpXG4gIHZhciBmdW5jTmFtZSA9IFwibmRTZWxlY3RcIiArIGR0eXBlICsgb3JkZXIuam9pbihcIl9cIikgKyBcIl9cIiArICh1c2VDb21wYXJlID8gXCJjbXBcIiA6IFwibGV4XCIpXG5cbiAgdmFyIGNvZGUgPSBbXVxuXG4gIC8vR2V0IGFyZ3VtZW50cyBmb3IgY29kZVxuICB2YXIgYXJncyA9IFtBUlJBWSwgUkFOS11cbiAgaWYodXNlQ29tcGFyZSkge1xuICAgIGFyZ3MucHVzaChDTVApXG4gIH1cblxuICAvL1VucGFjayBuZGFycmF5IHZhcmlhYmxlc1xuICB2YXIgdmFycyA9IFtcbiAgICBEQVRBICsgXCI9XCIgKyBBUlJBWSArIFwiLmRhdGFcIixcbiAgICBPRkZTRVQgKyBcIj1cIiArIEFSUkFZICsgXCIub2Zmc2V0fDBcIixcbiAgICBSTkQgKyBcIj1NYXRoLnJhbmRvbVwiLFxuICAgIFRNUF1cbiAgZm9yKHZhciBpPTA7IGk8MjsgKytpKSB7XG4gICAgdmFycy5wdXNoKFBUUihpKSArIFwiPTBcIilcbiAgfVxuICBmb3IodmFyIGk9MDsgaTxkaW1lbnNpb247ICsraSkge1xuICAgIHZhcnMucHVzaChcbiAgICAgIFNIQVBFKGkpICsgXCI9XCIgKyBBUlJBWSArIFwiLnNoYXBlW1wiICsgaSArIFwiXXwwXCIsXG4gICAgICBTVFJJREUoaSkgKyBcIj1cIiArIEFSUkFZICsgXCIuc3RyaWRlW1wiICsgaSArIFwiXXwwXCIsXG4gICAgICBJTkRFWChpKSArIFwiPTBcIilcbiAgfVxuICBmb3IodmFyIGk9MTsgaTxkaW1lbnNpb247ICsraSkge1xuICAgIGlmKGkgPiAxKSB7XG4gICAgICB2YXJzLnB1c2goU1RFUF9DTVAoaSkgKyBcIj0oXCIgKyBTVFJJREUoaSkgKyBcIi1cIiArIFNIQVBFKGktMSkgKyBcIipcIiArIFNUUklERShpLTEpICsgXCIpfDBcIixcbiAgICAgICAgICAgICAgICBTVEVQKG9yZGVyW2ldKSArIFwiPShcIiArIFNUUklERShvcmRlcltpXSkgKyBcIi1cIiArIFNIQVBFKG9yZGVyW2ktMV0pICsgXCIqXCIgKyBTVFJJREUob3JkZXJbaS0xXSkgKyBcIil8MFwiKVxuICAgIH0gZWxzZSB7XG4gICAgICB2YXJzLnB1c2goU1RFUF9DTVAoaSkgKyBcIj1cIiArIFNUUklERShpKSxcbiAgICAgICAgICAgICAgICBTVEVQKG9yZGVyW2ldKSArIFwiPVwiICsgU1RSSURFKG9yZGVyW2ldKSlcbiAgICB9XG4gIH1cbiAgaWYodXNlQ29tcGFyZSkge1xuICAgIGZvcih2YXIgaT0wOyBpPDI7ICsraSkge1xuICAgICAgdmFycy5wdXNoKFBJQ0soaSkgKyBcIj1cIiArIEFSUkFZICsgXCIucGljaygwKVwiKVxuICAgIH1cbiAgfVxuICB2YXJzLnB1c2goXG4gICAgUElWT1QgKyBcIj0wXCIsXG4gICAgTE8gKyBcIj0wXCIsXG4gICAgSEkgKyBcIj1cIiArIFNIQVBFKG9yZGVyWzBdKSArIFwiLTFcIilcblxuICBmdW5jdGlvbiBjb21wYXJlKG91dCwgaTAsIGkxKSB7XG4gICAgaWYodXNlQ29tcGFyZSkge1xuICAgICAgY29kZS5wdXNoKFxuICAgICAgICBQSUNLKDApLCBcIi5vZmZzZXQ9XCIsIE9GRlNFVCwgXCIrXCIsIFNUUklERShvcmRlclswXSksIFwiKihcIiwgaTAsIFwiKTtcIixcbiAgICAgICAgUElDSygxKSwgXCIub2Zmc2V0PVwiLCBPRkZTRVQsIFwiK1wiLCBTVFJJREUob3JkZXJbMF0pLCBcIiooXCIsIGkxLCBcIik7XCIsXG4gICAgICAgIG91dCwgXCI9XCIsIENNUCwgXCIoXCIsIFBJQ0soMCksIFwiLFwiLCBQSUNLKDEpLCBcIik7XCIpXG4gICAgfSBlbHNlIHtcbiAgICAgIGNvZGUucHVzaChcbiAgICAgICAgUFRSKDApLCBcIj1cIiwgT0ZGU0VULCBcIitcIiwgU1RSSURFKDApLCBcIiooXCIsIGkwLCBcIik7XCIsXG4gICAgICAgIFBUUigxKSwgXCI9XCIsIE9GRlNFVCwgXCIrXCIsIFNUUklERSgwKSwgXCIqKFwiLCBpMSwgXCIpO1wiKVxuICAgICAgaWYoZGltZW5zaW9uID4gMSkge1xuICAgICAgICBjb2RlLnB1c2goXCJfY21wOlwiKVxuICAgICAgfVxuICAgICAgZm9yKHZhciBpPWRpbWVuc2lvbi0xOyBpPjA7IC0taSkge1xuICAgICAgICBjb2RlLnB1c2goXCJmb3IoXCIsIElOREVYKGkpLCBcIj0wO1wiLCBcbiAgICAgICAgICBJTkRFWChpKSwgXCI8XCIsIFNIQVBFKGkpLCBcIjtcIixcbiAgICAgICAgICBJTkRFWChpKSwgXCIrKyl7XCIpXG4gICAgICB9XG4gICAgICBpZih1c2VHZXR0ZXIpIHtcbiAgICAgICAgY29kZS5wdXNoKG91dCwgXCI9XCIsIERBVEEsIFwiLmdldChcIiwgUFRSKDApLCBcIiktXCIsIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIERBVEEsIFwiLmdldChcIiwgUFRSKDEpLCBcIik7XCIpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb2RlLnB1c2gob3V0LCBcIj1cIiwgREFUQSwgXCJbXCIsIFBUUigwKSwgXCJdLVwiLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEQVRBLCBcIltcIiwgUFRSKDEpLCBcIl07XCIpXG4gICAgICB9XG4gICAgICBpZihkaW1lbnNpb24gPiAxKSB7XG4gICAgICAgIGNvZGUucHVzaChcImlmKFwiLCBvdXQsIFwiKWJyZWFrIF9jbXA7XCIpXG4gICAgICB9XG4gICAgICBmb3IodmFyIGk9MTsgaTxkaW1lbnNpb247ICsraSkge1xuICAgICAgICBjb2RlLnB1c2goXG4gICAgICAgICAgUFRSKDApLCBcIis9XCIsIFNURVBfQ01QKGkpLCBcIjtcIixcbiAgICAgICAgICBQVFIoMSksIFwiKz1cIiwgU1RFUF9DTVAoaSksXG4gICAgICAgICAgXCJ9XCIpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gc3dhcChpMCwgaTEpIHtcbiAgICBjb2RlLnB1c2goXG4gICAgICBQVFIoMCksIFwiPVwiLCBPRkZTRVQsIFwiK1wiLCBTVFJJREUob3JkZXJbMF0pLCBcIiooXCIsIGkwLCBcIik7XCIsXG4gICAgICBQVFIoMSksIFwiPVwiLCBPRkZTRVQsIFwiK1wiLCBTVFJJREUob3JkZXJbMF0pLCBcIiooXCIsIGkxLCBcIik7XCIpXG4gICAgZm9yKHZhciBpPWRpbWVuc2lvbi0xOyBpPjA7IC0taSkge1xuICAgICAgY29kZS5wdXNoKFwiZm9yKFwiLCBJTkRFWChvcmRlcltpXSksIFwiPTA7XCIsIFxuICAgICAgICBJTkRFWChvcmRlcltpXSksIFwiPFwiLCBTSEFQRShvcmRlcltpXSksIFwiO1wiLFxuICAgICAgICBJTkRFWChvcmRlcltpXSksIFwiKyspe1wiKVxuICAgIH1cbiAgICBpZih1c2VHZXR0ZXIpIHtcbiAgICAgIGNvZGUucHVzaChUTVAsIFwiPVwiLCBEQVRBLCBcIi5nZXQoXCIsIFBUUigwKSwgXCIpO1wiLCBcbiAgICAgICAgICAgICAgICBEQVRBLCBcIi5zZXQoXCIsIFBUUigwKSwgXCIsXCIsIERBVEEsIFwiLmdldChcIiwgUFRSKDEpLCBcIikpO1wiLFxuICAgICAgICAgICAgICAgIERBVEEsIFwiLnNldChcIiwgUFRSKDEpLCBcIixcIiwgVE1QLCBcIik7XCIpXG4gICAgfSBlbHNlIHtcbiAgICAgIGNvZGUucHVzaChUTVAsIFwiPVwiLCBEQVRBLCBcIltcIiwgUFRSKDApLCBcIl07XCIsIFxuICAgICAgICAgICAgICAgIERBVEEsIFwiW1wiLCBQVFIoMCksIFwiXT1cIiwgREFUQSwgXCJbXCIsIFBUUigxKSwgXCJdO1wiLFxuICAgICAgICAgICAgICAgIERBVEEsIFwiW1wiLCBQVFIoMSksIFwiXT1cIiwgVE1QLCBcIjtcIilcbiAgICB9XG4gICAgZm9yKHZhciBpPTE7IGk8ZGltZW5zaW9uOyArK2kpIHtcbiAgICAgIGNvZGUucHVzaChcbiAgICAgICAgUFRSKDApLCBcIis9XCIsIFNURVAob3JkZXJbaV0pLCBcIjtcIixcbiAgICAgICAgUFRSKDEpLCBcIis9XCIsIFNURVAob3JkZXJbaV0pLFxuICAgICAgICBcIn1cIilcbiAgICB9XG4gIH1cblxuICBjb2RlLnB1c2goXG4gICAgXCJ3aGlsZShcIiwgTE8sIFwiPFwiLCBISSwgXCIpe1wiLFxuICAgICAgUElWT1QsIFwiPShcIiwgUk5ELCBcIigpKihcIiwgSEksIFwiLVwiLCBMTywgXCIrMSkrXCIsIExPLCBcIil8MDtcIilcblxuICAvL1BhcnRpdGlvbiBhcnJheSBieSBwaXZvdFxuICBzd2FwKFBJVk9ULCBISSkgLy8gU3RvcmUgcGl2b3QgdGVtcG9yYXJpbHkgYXQgdGhlIGVuZCBvZiB0aGUgYXJyYXlcblxuICBjb2RlLnB1c2goXG4gICAgUElWT1QsIFwiPVwiLCBMTywgXCI7XCIsIC8vIFBJVk9UIHdpbGwgbm93IGJlIHVzZWQgdG8ga2VlcCB0cmFjayBvZiB0aGUgZW5kIG9mIHRoZSBpbnRlcnZhbCBvZiBlbGVtZW50cyBsZXNzIHRoYW4gdGhlIHBpdm90XG4gICAgXCJmb3IoXCIsIElOREVYKDApLCBcIj1cIiwgTE8sIFwiO1wiLFxuICAgICAgSU5ERVgoMCksIFwiPFwiLCBISSwgXCI7XCIsXG4gICAgICBJTkRFWCgwKSwgXCIrKyl7XCIpIC8vIExvb3Agb3ZlciBvdGhlciBlbGVtZW50cyAodW5lcXVhbCB0byB0aGUgcGl2b3QpLCBub3RlIHRoYXQgSEkgbm93IHBvaW50cyB0byB0aGUgcGl2b3RcbiAgY29tcGFyZShUTVAsIElOREVYKDApLCBISSkgLy8gTGV4aWNvZ3JhcGhpY2FsIGNvbXBhcmUgb2YgZWxlbWVudCB3aXRoIHBpdm90XG4gIGNvZGUucHVzaChcImlmKFwiLCBUTVAsIFwiPDApe1wiKVxuICBzd2FwKFBJVk9ULCBJTkRFWCgwKSkgLy8gU3dhcCBjdXJyZW50IGVsZW1lbnQgd2l0aCBlbGVtZW50IGF0IGluZGV4IFBJVk9UIGlmIGl0IGlzIGxlc3MgdGhhbiB0aGUgcGl2b3RcbiAgY29kZS5wdXNoKFBJVk9ULCBcIisrO1wiKVxuICBjb2RlLnB1c2goXCJ9fVwiKVxuICBzd2FwKFBJVk9ULCBISSkgLy8gU3RvcmUgcGl2b3QgcmlnaHQgYWZ0ZXIgYWxsIGVsZW1lbnRzIHRoYXQgYXJlIGxlc3MgdGhhbiB0aGUgcGl2b3QgKGltcGx5aW5nIHRoYXQgYWxsIGVsZW1lbnRzID49IHRoZSBwaXZvdCBhcmUgYmVoaW5kIHRoZSBwaXZvdClcblxuICAvL0NoZWNrIHBpdm90IGJvdW5kc1xuICBjb2RlLnB1c2goXG4gICAgXCJpZihcIiwgUElWT1QsIFwiPT09XCIsIFJBTkssIFwiKXtcIixcbiAgICAgIExPLCBcIj1cIiwgUElWT1QsIFwiO1wiLFxuICAgICAgXCJicmVhaztcIixcbiAgICBcIn1lbHNlIGlmKFwiLCBSQU5LLCBcIjxcIiwgUElWT1QsIFwiKXtcIixcbiAgICAgIEhJLCBcIj1cIiwgUElWT1QsIFwiLTE7XCIsXG4gICAgXCJ9ZWxzZXtcIixcbiAgICAgIExPLCBcIj1cIiwgUElWT1QsIFwiKzE7XCIsXG4gICAgXCJ9XCIsXG4gIFwifVwiKVxuXG4gIGlmKHVzZUNvbXBhcmUpIHtcbiAgICBjb2RlLnB1c2goUElDSygwKSwgXCIub2Zmc2V0PVwiLCBPRkZTRVQsIFwiK1wiLCBMTywgXCIqXCIsIFNUUklERSgwKSwgXCI7XCIsXG4gICAgICBcInJldHVybiBcIiwgUElDSygwKSwgXCI7XCIpXG4gIH0gZWxzZSB7XG4gICAgY29kZS5wdXNoKFwicmV0dXJuIFwiLCBBUlJBWSwgXCIucGljayhcIiwgTE8sIFwiKTtcIilcbiAgfVxuXG4gIC8vQ29tcGlsZSBhbmQgbGluayBqcyB0b2dldGhlclxuICB2YXIgcHJvY0NvZGUgPSBbXG4gICAgXCIndXNlIHN0cmljdCc7ZnVuY3Rpb24gXCIsIGZ1bmNOYW1lLCBcIihcIiwgYXJncywgXCIpe1wiLFxuICAgICAgXCJ2YXIgXCIsIHZhcnMuam9pbigpLCBcIjtcIixcbiAgICAgIGNvZGUuam9pbihcIlwiKSxcbiAgICBcIn07cmV0dXJuIFwiLCBmdW5jTmFtZVxuICBdLmpvaW4oXCJcIilcblxuICB2YXIgcHJvYyA9IG5ldyBGdW5jdGlvbihwcm9jQ29kZSlcbiAgcmV0dXJuIHByb2MoKVxufVxuXG52YXIgQ0FDSEUgPSB7fVxuXG5mdW5jdGlvbiBsb29rdXBDYWNoZShvcmRlciwgdXNlQ29tcGFyZSwgZHR5cGUpIHtcbiAgdmFyIHR5cGVzaWcgPSBvcmRlci5qb2luKCkgKyB1c2VDb21wYXJlICsgZHR5cGVcbiAgdmFyIHByb2MgPSBDQUNIRVt0eXBlc2lnXVxuICBpZihwcm9jKSB7XG4gICAgcmV0dXJuIHByb2NcbiAgfVxuICByZXR1cm4gQ0FDSEVbdHlwZXNpZ10gPSBjb21waWxlUXVpY2tTZWxlY3Qob3JkZXIsIHVzZUNvbXBhcmUsIGR0eXBlKVxufVxuXG5mdW5jdGlvbiBuZFNlbGVjdChhcnJheSwgaywgY29tcGFyZSkge1xuICBrIHw9IDBcbiAgaWYoKGFycmF5LmRpbWVuc2lvbiA9PT0gMCkgfHwgXG4gICAgKGFycmF5LnNoYXBlWzBdIDw9IGspIHx8XG4gICAgKGsgPCAwKSkge1xuICAgIHJldHVybiBudWxsXG4gIH1cbiAgdmFyIHVzZUNvbXBhcmUgPSAhIWNvbXBhcmVcbiAgdmFyIHByb2MgPSBsb29rdXBDYWNoZShhcnJheS5vcmRlciwgdXNlQ29tcGFyZSwgYXJyYXkuZHR5cGUpXG4gIGlmKHVzZUNvbXBhcmUpIHtcbiAgICByZXR1cm4gcHJvYyhhcnJheSwgaywgY29tcGFyZSlcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gcHJvYyhhcnJheSwgaylcbiAgfVxufSIsInZhciBpb3RhID0gcmVxdWlyZShcImlvdGEtYXJyYXlcIilcbnZhciBpc0J1ZmZlciA9IHJlcXVpcmUoXCJpcy1idWZmZXJcIilcblxudmFyIGhhc1R5cGVkQXJyYXlzICA9ICgodHlwZW9mIEZsb2F0NjRBcnJheSkgIT09IFwidW5kZWZpbmVkXCIpXG5cbmZ1bmN0aW9uIGNvbXBhcmUxc3QoYSwgYikge1xuICByZXR1cm4gYVswXSAtIGJbMF1cbn1cblxuZnVuY3Rpb24gb3JkZXIoKSB7XG4gIHZhciBzdHJpZGUgPSB0aGlzLnN0cmlkZVxuICB2YXIgdGVybXMgPSBuZXcgQXJyYXkoc3RyaWRlLmxlbmd0aClcbiAgdmFyIGlcbiAgZm9yKGk9MDsgaTx0ZXJtcy5sZW5ndGg7ICsraSkge1xuICAgIHRlcm1zW2ldID0gW01hdGguYWJzKHN0cmlkZVtpXSksIGldXG4gIH1cbiAgdGVybXMuc29ydChjb21wYXJlMXN0KVxuICB2YXIgcmVzdWx0ID0gbmV3IEFycmF5KHRlcm1zLmxlbmd0aClcbiAgZm9yKGk9MDsgaTxyZXN1bHQubGVuZ3RoOyArK2kpIHtcbiAgICByZXN1bHRbaV0gPSB0ZXJtc1tpXVsxXVxuICB9XG4gIHJldHVybiByZXN1bHRcbn1cblxuZnVuY3Rpb24gY29tcGlsZUNvbnN0cnVjdG9yKGR0eXBlLCBkaW1lbnNpb24pIHtcbiAgdmFyIGNsYXNzTmFtZSA9IFtcIlZpZXdcIiwgZGltZW5zaW9uLCBcImRcIiwgZHR5cGVdLmpvaW4oXCJcIilcbiAgaWYoZGltZW5zaW9uIDwgMCkge1xuICAgIGNsYXNzTmFtZSA9IFwiVmlld19OaWxcIiArIGR0eXBlXG4gIH1cbiAgdmFyIHVzZUdldHRlcnMgPSAoZHR5cGUgPT09IFwiZ2VuZXJpY1wiKVxuXG4gIGlmKGRpbWVuc2lvbiA9PT0gLTEpIHtcbiAgICAvL1NwZWNpYWwgY2FzZSBmb3IgdHJpdmlhbCBhcnJheXNcbiAgICB2YXIgY29kZSA9XG4gICAgICBcImZ1bmN0aW9uIFwiK2NsYXNzTmFtZStcIihhKXt0aGlzLmRhdGE9YTt9O1xcXG52YXIgcHJvdG89XCIrY2xhc3NOYW1lK1wiLnByb3RvdHlwZTtcXFxucHJvdG8uZHR5cGU9J1wiK2R0eXBlK1wiJztcXFxucHJvdG8uaW5kZXg9ZnVuY3Rpb24oKXtyZXR1cm4gLTF9O1xcXG5wcm90by5zaXplPTA7XFxcbnByb3RvLmRpbWVuc2lvbj0tMTtcXFxucHJvdG8uc2hhcGU9cHJvdG8uc3RyaWRlPXByb3RvLm9yZGVyPVtdO1xcXG5wcm90by5sbz1wcm90by5oaT1wcm90by50cmFuc3Bvc2U9cHJvdG8uc3RlcD1cXFxuZnVuY3Rpb24oKXtyZXR1cm4gbmV3IFwiK2NsYXNzTmFtZStcIih0aGlzLmRhdGEpO307XFxcbnByb3RvLmdldD1wcm90by5zZXQ9ZnVuY3Rpb24oKXt9O1xcXG5wcm90by5waWNrPWZ1bmN0aW9uKCl7cmV0dXJuIG51bGx9O1xcXG5yZXR1cm4gZnVuY3Rpb24gY29uc3RydWN0X1wiK2NsYXNzTmFtZStcIihhKXtyZXR1cm4gbmV3IFwiK2NsYXNzTmFtZStcIihhKTt9XCJcbiAgICB2YXIgcHJvY2VkdXJlID0gbmV3IEZ1bmN0aW9uKGNvZGUpXG4gICAgcmV0dXJuIHByb2NlZHVyZSgpXG4gIH0gZWxzZSBpZihkaW1lbnNpb24gPT09IDApIHtcbiAgICAvL1NwZWNpYWwgY2FzZSBmb3IgMGQgYXJyYXlzXG4gICAgdmFyIGNvZGUgPVxuICAgICAgXCJmdW5jdGlvbiBcIitjbGFzc05hbWUrXCIoYSxkKSB7XFxcbnRoaXMuZGF0YSA9IGE7XFxcbnRoaXMub2Zmc2V0ID0gZFxcXG59O1xcXG52YXIgcHJvdG89XCIrY2xhc3NOYW1lK1wiLnByb3RvdHlwZTtcXFxucHJvdG8uZHR5cGU9J1wiK2R0eXBlK1wiJztcXFxucHJvdG8uaW5kZXg9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5vZmZzZXR9O1xcXG5wcm90by5kaW1lbnNpb249MDtcXFxucHJvdG8uc2l6ZT0xO1xcXG5wcm90by5zaGFwZT1cXFxucHJvdG8uc3RyaWRlPVxcXG5wcm90by5vcmRlcj1bXTtcXFxucHJvdG8ubG89XFxcbnByb3RvLmhpPVxcXG5wcm90by50cmFuc3Bvc2U9XFxcbnByb3RvLnN0ZXA9ZnVuY3Rpb24gXCIrY2xhc3NOYW1lK1wiX2NvcHkoKSB7XFxcbnJldHVybiBuZXcgXCIrY2xhc3NOYW1lK1wiKHRoaXMuZGF0YSx0aGlzLm9mZnNldClcXFxufTtcXFxucHJvdG8ucGljaz1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfcGljaygpe1xcXG5yZXR1cm4gVHJpdmlhbEFycmF5KHRoaXMuZGF0YSk7XFxcbn07XFxcbnByb3RvLnZhbHVlT2Y9cHJvdG8uZ2V0PWZ1bmN0aW9uIFwiK2NsYXNzTmFtZStcIl9nZXQoKXtcXFxucmV0dXJuIFwiKyh1c2VHZXR0ZXJzID8gXCJ0aGlzLmRhdGEuZ2V0KHRoaXMub2Zmc2V0KVwiIDogXCJ0aGlzLmRhdGFbdGhpcy5vZmZzZXRdXCIpK1xuXCJ9O1xcXG5wcm90by5zZXQ9ZnVuY3Rpb24gXCIrY2xhc3NOYW1lK1wiX3NldCh2KXtcXFxucmV0dXJuIFwiKyh1c2VHZXR0ZXJzID8gXCJ0aGlzLmRhdGEuc2V0KHRoaXMub2Zmc2V0LHYpXCIgOiBcInRoaXMuZGF0YVt0aGlzLm9mZnNldF09dlwiKStcIlxcXG59O1xcXG5yZXR1cm4gZnVuY3Rpb24gY29uc3RydWN0X1wiK2NsYXNzTmFtZStcIihhLGIsYyxkKXtyZXR1cm4gbmV3IFwiK2NsYXNzTmFtZStcIihhLGQpfVwiXG4gICAgdmFyIHByb2NlZHVyZSA9IG5ldyBGdW5jdGlvbihcIlRyaXZpYWxBcnJheVwiLCBjb2RlKVxuICAgIHJldHVybiBwcm9jZWR1cmUoQ0FDSEVEX0NPTlNUUlVDVE9SU1tkdHlwZV1bMF0pXG4gIH1cblxuICB2YXIgY29kZSA9IFtcIid1c2Ugc3RyaWN0J1wiXVxuXG4gIC8vQ3JlYXRlIGNvbnN0cnVjdG9yIGZvciB2aWV3XG4gIHZhciBpbmRpY2VzID0gaW90YShkaW1lbnNpb24pXG4gIHZhciBhcmdzID0gaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgeyByZXR1cm4gXCJpXCIraSB9KVxuICB2YXIgaW5kZXhfc3RyID0gXCJ0aGlzLm9mZnNldCtcIiArIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgICAgcmV0dXJuIFwidGhpcy5zdHJpZGVbXCIgKyBpICsgXCJdKmlcIiArIGlcbiAgICAgIH0pLmpvaW4oXCIrXCIpXG4gIHZhciBzaGFwZUFyZyA9IGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgIHJldHVybiBcImJcIitpXG4gICAgfSkuam9pbihcIixcIilcbiAgdmFyIHN0cmlkZUFyZyA9IGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgIHJldHVybiBcImNcIitpXG4gICAgfSkuam9pbihcIixcIilcbiAgY29kZS5wdXNoKFxuICAgIFwiZnVuY3Rpb24gXCIrY2xhc3NOYW1lK1wiKGEsXCIgKyBzaGFwZUFyZyArIFwiLFwiICsgc3RyaWRlQXJnICsgXCIsZCl7dGhpcy5kYXRhPWFcIixcbiAgICAgIFwidGhpcy5zaGFwZT1bXCIgKyBzaGFwZUFyZyArIFwiXVwiLFxuICAgICAgXCJ0aGlzLnN0cmlkZT1bXCIgKyBzdHJpZGVBcmcgKyBcIl1cIixcbiAgICAgIFwidGhpcy5vZmZzZXQ9ZHwwfVwiLFxuICAgIFwidmFyIHByb3RvPVwiK2NsYXNzTmFtZStcIi5wcm90b3R5cGVcIixcbiAgICBcInByb3RvLmR0eXBlPSdcIitkdHlwZStcIidcIixcbiAgICBcInByb3RvLmRpbWVuc2lvbj1cIitkaW1lbnNpb24pXG5cbiAgLy92aWV3LnNpemU6XG4gIGNvZGUucHVzaChcIk9iamVjdC5kZWZpbmVQcm9wZXJ0eShwcm90bywnc2l6ZScse2dldDpmdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfc2l6ZSgpe1xcXG5yZXR1cm4gXCIraW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgeyByZXR1cm4gXCJ0aGlzLnNoYXBlW1wiK2krXCJdXCIgfSkuam9pbihcIipcIiksXG5cIn19KVwiKVxuXG4gIC8vdmlldy5vcmRlcjpcbiAgaWYoZGltZW5zaW9uID09PSAxKSB7XG4gICAgY29kZS5wdXNoKFwicHJvdG8ub3JkZXI9WzBdXCIpXG4gIH0gZWxzZSB7XG4gICAgY29kZS5wdXNoKFwiT2JqZWN0LmRlZmluZVByb3BlcnR5KHByb3RvLCdvcmRlcicse2dldDpcIilcbiAgICBpZihkaW1lbnNpb24gPCA0KSB7XG4gICAgICBjb2RlLnB1c2goXCJmdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfb3JkZXIoKXtcIilcbiAgICAgIGlmKGRpbWVuc2lvbiA9PT0gMikge1xuICAgICAgICBjb2RlLnB1c2goXCJyZXR1cm4gKE1hdGguYWJzKHRoaXMuc3RyaWRlWzBdKT5NYXRoLmFicyh0aGlzLnN0cmlkZVsxXSkpP1sxLDBdOlswLDFdfX0pXCIpXG4gICAgICB9IGVsc2UgaWYoZGltZW5zaW9uID09PSAzKSB7XG4gICAgICAgIGNvZGUucHVzaChcblwidmFyIHMwPU1hdGguYWJzKHRoaXMuc3RyaWRlWzBdKSxzMT1NYXRoLmFicyh0aGlzLnN0cmlkZVsxXSksczI9TWF0aC5hYnModGhpcy5zdHJpZGVbMl0pO1xcXG5pZihzMD5zMSl7XFxcbmlmKHMxPnMyKXtcXFxucmV0dXJuIFsyLDEsMF07XFxcbn1lbHNlIGlmKHMwPnMyKXtcXFxucmV0dXJuIFsxLDIsMF07XFxcbn1lbHNle1xcXG5yZXR1cm4gWzEsMCwyXTtcXFxufVxcXG59ZWxzZSBpZihzMD5zMil7XFxcbnJldHVybiBbMiwwLDFdO1xcXG59ZWxzZSBpZihzMj5zMSl7XFxcbnJldHVybiBbMCwxLDJdO1xcXG59ZWxzZXtcXFxucmV0dXJuIFswLDIsMV07XFxcbn19fSlcIilcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY29kZS5wdXNoKFwiT1JERVJ9KVwiKVxuICAgIH1cbiAgfVxuXG4gIC8vdmlldy5zZXQoaTAsIC4uLiwgdik6XG4gIGNvZGUucHVzaChcblwicHJvdG8uc2V0PWZ1bmN0aW9uIFwiK2NsYXNzTmFtZStcIl9zZXQoXCIrYXJncy5qb2luKFwiLFwiKStcIix2KXtcIilcbiAgaWYodXNlR2V0dGVycykge1xuICAgIGNvZGUucHVzaChcInJldHVybiB0aGlzLmRhdGEuc2V0KFwiK2luZGV4X3N0citcIix2KX1cIilcbiAgfSBlbHNlIHtcbiAgICBjb2RlLnB1c2goXCJyZXR1cm4gdGhpcy5kYXRhW1wiK2luZGV4X3N0citcIl09dn1cIilcbiAgfVxuXG4gIC8vdmlldy5nZXQoaTAsIC4uLik6XG4gIGNvZGUucHVzaChcInByb3RvLmdldD1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfZ2V0KFwiK2FyZ3Muam9pbihcIixcIikrXCIpe1wiKVxuICBpZih1c2VHZXR0ZXJzKSB7XG4gICAgY29kZS5wdXNoKFwicmV0dXJuIHRoaXMuZGF0YS5nZXQoXCIraW5kZXhfc3RyK1wiKX1cIilcbiAgfSBlbHNlIHtcbiAgICBjb2RlLnB1c2goXCJyZXR1cm4gdGhpcy5kYXRhW1wiK2luZGV4X3N0citcIl19XCIpXG4gIH1cblxuICAvL3ZpZXcuaW5kZXg6XG4gIGNvZGUucHVzaChcbiAgICBcInByb3RvLmluZGV4PWZ1bmN0aW9uIFwiK2NsYXNzTmFtZStcIl9pbmRleChcIiwgYXJncy5qb2luKCksIFwiKXtyZXR1cm4gXCIraW5kZXhfc3RyK1wifVwiKVxuXG4gIC8vdmlldy5oaSgpOlxuICBjb2RlLnB1c2goXCJwcm90by5oaT1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfaGkoXCIrYXJncy5qb2luKFwiLFwiKStcIil7cmV0dXJuIG5ldyBcIitjbGFzc05hbWUrXCIodGhpcy5kYXRhLFwiK1xuICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgIHJldHVybiBbXCIodHlwZW9mIGlcIixpLFwiIT09J251bWJlcid8fGlcIixpLFwiPDApP3RoaXMuc2hhcGVbXCIsIGksIFwiXTppXCIsIGksXCJ8MFwiXS5qb2luKFwiXCIpXG4gICAgfSkuam9pbihcIixcIikrXCIsXCIrXG4gICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkge1xuICAgICAgcmV0dXJuIFwidGhpcy5zdHJpZGVbXCIraSArIFwiXVwiXG4gICAgfSkuam9pbihcIixcIikrXCIsdGhpcy5vZmZzZXQpfVwiKVxuXG4gIC8vdmlldy5sbygpOlxuICB2YXIgYV92YXJzID0gaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgeyByZXR1cm4gXCJhXCIraStcIj10aGlzLnNoYXBlW1wiK2krXCJdXCIgfSlcbiAgdmFyIGNfdmFycyA9IGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsgcmV0dXJuIFwiY1wiK2krXCI9dGhpcy5zdHJpZGVbXCIraStcIl1cIiB9KVxuICBjb2RlLnB1c2goXCJwcm90by5sbz1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfbG8oXCIrYXJncy5qb2luKFwiLFwiKStcIil7dmFyIGI9dGhpcy5vZmZzZXQsZD0wLFwiK2FfdmFycy5qb2luKFwiLFwiKStcIixcIitjX3ZhcnMuam9pbihcIixcIikpXG4gIGZvcih2YXIgaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7XG4gICAgY29kZS5wdXNoKFxuXCJpZih0eXBlb2YgaVwiK2krXCI9PT0nbnVtYmVyJyYmaVwiK2krXCI+PTApe1xcXG5kPWlcIitpK1wifDA7XFxcbmIrPWNcIitpK1wiKmQ7XFxcbmFcIitpK1wiLT1kfVwiKVxuICB9XG4gIGNvZGUucHVzaChcInJldHVybiBuZXcgXCIrY2xhc3NOYW1lK1wiKHRoaXMuZGF0YSxcIitcbiAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7XG4gICAgICByZXR1cm4gXCJhXCIraVxuICAgIH0pLmpvaW4oXCIsXCIpK1wiLFwiK1xuICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgIHJldHVybiBcImNcIitpXG4gICAgfSkuam9pbihcIixcIikrXCIsYil9XCIpXG5cbiAgLy92aWV3LnN0ZXAoKTpcbiAgY29kZS5wdXNoKFwicHJvdG8uc3RlcD1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfc3RlcChcIithcmdzLmpvaW4oXCIsXCIpK1wiKXt2YXIgXCIrXG4gICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkge1xuICAgICAgcmV0dXJuIFwiYVwiK2krXCI9dGhpcy5zaGFwZVtcIitpK1wiXVwiXG4gICAgfSkuam9pbihcIixcIikrXCIsXCIrXG4gICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkge1xuICAgICAgcmV0dXJuIFwiYlwiK2krXCI9dGhpcy5zdHJpZGVbXCIraStcIl1cIlxuICAgIH0pLmpvaW4oXCIsXCIpK1wiLGM9dGhpcy5vZmZzZXQsZD0wLGNlaWw9TWF0aC5jZWlsXCIpXG4gIGZvcih2YXIgaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7XG4gICAgY29kZS5wdXNoKFxuXCJpZih0eXBlb2YgaVwiK2krXCI9PT0nbnVtYmVyJyl7XFxcbmQ9aVwiK2krXCJ8MDtcXFxuaWYoZDwwKXtcXFxuYys9YlwiK2krXCIqKGFcIitpK1wiLTEpO1xcXG5hXCIraStcIj1jZWlsKC1hXCIraStcIi9kKVxcXG59ZWxzZXtcXFxuYVwiK2krXCI9Y2VpbChhXCIraStcIi9kKVxcXG59XFxcbmJcIitpK1wiKj1kXFxcbn1cIilcbiAgfVxuICBjb2RlLnB1c2goXCJyZXR1cm4gbmV3IFwiK2NsYXNzTmFtZStcIih0aGlzLmRhdGEsXCIrXG4gICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkge1xuICAgICAgcmV0dXJuIFwiYVwiICsgaVxuICAgIH0pLmpvaW4oXCIsXCIpK1wiLFwiK1xuICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgIHJldHVybiBcImJcIiArIGlcbiAgICB9KS5qb2luKFwiLFwiKStcIixjKX1cIilcblxuICAvL3ZpZXcudHJhbnNwb3NlKCk6XG4gIHZhciB0U2hhcGUgPSBuZXcgQXJyYXkoZGltZW5zaW9uKVxuICB2YXIgdFN0cmlkZSA9IG5ldyBBcnJheShkaW1lbnNpb24pXG4gIGZvcih2YXIgaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7XG4gICAgdFNoYXBlW2ldID0gXCJhW2lcIitpK1wiXVwiXG4gICAgdFN0cmlkZVtpXSA9IFwiYltpXCIraStcIl1cIlxuICB9XG4gIGNvZGUucHVzaChcInByb3RvLnRyYW5zcG9zZT1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfdHJhbnNwb3NlKFwiK2FyZ3MrXCIpe1wiK1xuICAgIGFyZ3MubWFwKGZ1bmN0aW9uKG4saWR4KSB7IHJldHVybiBuICsgXCI9KFwiICsgbiArIFwiPT09dW5kZWZpbmVkP1wiICsgaWR4ICsgXCI6XCIgKyBuICsgXCJ8MClcIn0pLmpvaW4oXCI7XCIpLFxuICAgIFwidmFyIGE9dGhpcy5zaGFwZSxiPXRoaXMuc3RyaWRlO3JldHVybiBuZXcgXCIrY2xhc3NOYW1lK1wiKHRoaXMuZGF0YSxcIit0U2hhcGUuam9pbihcIixcIikrXCIsXCIrdFN0cmlkZS5qb2luKFwiLFwiKStcIix0aGlzLm9mZnNldCl9XCIpXG5cbiAgLy92aWV3LnBpY2soKTpcbiAgY29kZS5wdXNoKFwicHJvdG8ucGljaz1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfcGljayhcIithcmdzK1wiKXt2YXIgYT1bXSxiPVtdLGM9dGhpcy5vZmZzZXRcIilcbiAgZm9yKHZhciBpPTA7IGk8ZGltZW5zaW9uOyArK2kpIHtcbiAgICBjb2RlLnB1c2goXCJpZih0eXBlb2YgaVwiK2krXCI9PT0nbnVtYmVyJyYmaVwiK2krXCI+PTApe2M9KGMrdGhpcy5zdHJpZGVbXCIraStcIl0qaVwiK2krXCIpfDB9ZWxzZXthLnB1c2godGhpcy5zaGFwZVtcIitpK1wiXSk7Yi5wdXNoKHRoaXMuc3RyaWRlW1wiK2krXCJdKX1cIilcbiAgfVxuICBjb2RlLnB1c2goXCJ2YXIgY3Rvcj1DVE9SX0xJU1RbYS5sZW5ndGgrMV07cmV0dXJuIGN0b3IodGhpcy5kYXRhLGEsYixjKX1cIilcblxuICAvL0FkZCByZXR1cm4gc3RhdGVtZW50XG4gIGNvZGUucHVzaChcInJldHVybiBmdW5jdGlvbiBjb25zdHJ1Y3RfXCIrY2xhc3NOYW1lK1wiKGRhdGEsc2hhcGUsc3RyaWRlLG9mZnNldCl7cmV0dXJuIG5ldyBcIitjbGFzc05hbWUrXCIoZGF0YSxcIitcbiAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7XG4gICAgICByZXR1cm4gXCJzaGFwZVtcIitpK1wiXVwiXG4gICAgfSkuam9pbihcIixcIikrXCIsXCIrXG4gICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkge1xuICAgICAgcmV0dXJuIFwic3RyaWRlW1wiK2krXCJdXCJcbiAgICB9KS5qb2luKFwiLFwiKStcIixvZmZzZXQpfVwiKVxuXG4gIC8vQ29tcGlsZSBwcm9jZWR1cmVcbiAgdmFyIHByb2NlZHVyZSA9IG5ldyBGdW5jdGlvbihcIkNUT1JfTElTVFwiLCBcIk9SREVSXCIsIGNvZGUuam9pbihcIlxcblwiKSlcbiAgcmV0dXJuIHByb2NlZHVyZShDQUNIRURfQ09OU1RSVUNUT1JTW2R0eXBlXSwgb3JkZXIpXG59XG5cbmZ1bmN0aW9uIGFycmF5RFR5cGUoZGF0YSkge1xuICBpZihpc0J1ZmZlcihkYXRhKSkge1xuICAgIHJldHVybiBcImJ1ZmZlclwiXG4gIH1cbiAgaWYoaGFzVHlwZWRBcnJheXMpIHtcbiAgICBzd2l0Y2goT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGRhdGEpKSB7XG4gICAgICBjYXNlIFwiW29iamVjdCBGbG9hdDY0QXJyYXldXCI6XG4gICAgICAgIHJldHVybiBcImZsb2F0NjRcIlxuICAgICAgY2FzZSBcIltvYmplY3QgRmxvYXQzMkFycmF5XVwiOlxuICAgICAgICByZXR1cm4gXCJmbG9hdDMyXCJcbiAgICAgIGNhc2UgXCJbb2JqZWN0IEludDhBcnJheV1cIjpcbiAgICAgICAgcmV0dXJuIFwiaW50OFwiXG4gICAgICBjYXNlIFwiW29iamVjdCBJbnQxNkFycmF5XVwiOlxuICAgICAgICByZXR1cm4gXCJpbnQxNlwiXG4gICAgICBjYXNlIFwiW29iamVjdCBJbnQzMkFycmF5XVwiOlxuICAgICAgICByZXR1cm4gXCJpbnQzMlwiXG4gICAgICBjYXNlIFwiW29iamVjdCBVaW50OEFycmF5XVwiOlxuICAgICAgICByZXR1cm4gXCJ1aW50OFwiXG4gICAgICBjYXNlIFwiW29iamVjdCBVaW50MTZBcnJheV1cIjpcbiAgICAgICAgcmV0dXJuIFwidWludDE2XCJcbiAgICAgIGNhc2UgXCJbb2JqZWN0IFVpbnQzMkFycmF5XVwiOlxuICAgICAgICByZXR1cm4gXCJ1aW50MzJcIlxuICAgICAgY2FzZSBcIltvYmplY3QgVWludDhDbGFtcGVkQXJyYXldXCI6XG4gICAgICAgIHJldHVybiBcInVpbnQ4X2NsYW1wZWRcIlxuICAgIH1cbiAgfVxuICBpZihBcnJheS5pc0FycmF5KGRhdGEpKSB7XG4gICAgcmV0dXJuIFwiYXJyYXlcIlxuICB9XG4gIHJldHVybiBcImdlbmVyaWNcIlxufVxuXG52YXIgQ0FDSEVEX0NPTlNUUlVDVE9SUyA9IHtcbiAgXCJmbG9hdDMyXCI6W10sXG4gIFwiZmxvYXQ2NFwiOltdLFxuICBcImludDhcIjpbXSxcbiAgXCJpbnQxNlwiOltdLFxuICBcImludDMyXCI6W10sXG4gIFwidWludDhcIjpbXSxcbiAgXCJ1aW50MTZcIjpbXSxcbiAgXCJ1aW50MzJcIjpbXSxcbiAgXCJhcnJheVwiOltdLFxuICBcInVpbnQ4X2NsYW1wZWRcIjpbXSxcbiAgXCJidWZmZXJcIjpbXSxcbiAgXCJnZW5lcmljXCI6W11cbn1cblxuOyhmdW5jdGlvbigpIHtcbiAgZm9yKHZhciBpZCBpbiBDQUNIRURfQ09OU1RSVUNUT1JTKSB7XG4gICAgQ0FDSEVEX0NPTlNUUlVDVE9SU1tpZF0ucHVzaChjb21waWxlQ29uc3RydWN0b3IoaWQsIC0xKSlcbiAgfVxufSk7XG5cbmZ1bmN0aW9uIHdyYXBwZWROREFycmF5Q3RvcihkYXRhLCBzaGFwZSwgc3RyaWRlLCBvZmZzZXQpIHtcbiAgaWYoZGF0YSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgdmFyIGN0b3IgPSBDQUNIRURfQ09OU1RSVUNUT1JTLmFycmF5WzBdXG4gICAgcmV0dXJuIGN0b3IoW10pXG4gIH0gZWxzZSBpZih0eXBlb2YgZGF0YSA9PT0gXCJudW1iZXJcIikge1xuICAgIGRhdGEgPSBbZGF0YV1cbiAgfVxuICBpZihzaGFwZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgc2hhcGUgPSBbIGRhdGEubGVuZ3RoIF1cbiAgfVxuICB2YXIgZCA9IHNoYXBlLmxlbmd0aFxuICBpZihzdHJpZGUgPT09IHVuZGVmaW5lZCkge1xuICAgIHN0cmlkZSA9IG5ldyBBcnJheShkKVxuICAgIGZvcih2YXIgaT1kLTEsIHN6PTE7IGk+PTA7IC0taSkge1xuICAgICAgc3RyaWRlW2ldID0gc3pcbiAgICAgIHN6ICo9IHNoYXBlW2ldXG4gICAgfVxuICB9XG4gIGlmKG9mZnNldCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgb2Zmc2V0ID0gMFxuICAgIGZvcih2YXIgaT0wOyBpPGQ7ICsraSkge1xuICAgICAgaWYoc3RyaWRlW2ldIDwgMCkge1xuICAgICAgICBvZmZzZXQgLT0gKHNoYXBlW2ldLTEpKnN0cmlkZVtpXVxuICAgICAgfVxuICAgIH1cbiAgfVxuICB2YXIgZHR5cGUgPSBhcnJheURUeXBlKGRhdGEpXG4gIHZhciBjdG9yX2xpc3QgPSBDQUNIRURfQ09OU1RSVUNUT1JTW2R0eXBlXVxuICB3aGlsZShjdG9yX2xpc3QubGVuZ3RoIDw9IGQrMSkge1xuICAgIGN0b3JfbGlzdC5wdXNoKGNvbXBpbGVDb25zdHJ1Y3RvcihkdHlwZSwgY3Rvcl9saXN0Lmxlbmd0aC0xKSlcbiAgfVxuICB2YXIgY3RvciA9IGN0b3JfbGlzdFtkKzFdXG4gIHJldHVybiBjdG9yKGRhdGEsIHNoYXBlLCBzdHJpZGUsIG9mZnNldClcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB3cmFwcGVkTkRBcnJheUN0b3JcbiIsIlwidXNlIHN0cmljdFwiXG5cbmZ1bmN0aW9uIGlvdGEobikge1xuICB2YXIgcmVzdWx0ID0gbmV3IEFycmF5KG4pXG4gIGZvcih2YXIgaT0wOyBpPG47ICsraSkge1xuICAgIHJlc3VsdFtpXSA9IGlcbiAgfVxuICByZXR1cm4gcmVzdWx0XG59XG5cbm1vZHVsZS5leHBvcnRzID0gaW90YSIsIi8qIVxuICogRGV0ZXJtaW5lIGlmIGFuIG9iamVjdCBpcyBhIEJ1ZmZlclxuICpcbiAqIEBhdXRob3IgICBGZXJvc3MgQWJvdWtoYWRpamVoIDxmZXJvc3NAZmVyb3NzLm9yZz4gPGh0dHA6Ly9mZXJvc3Mub3JnPlxuICogQGxpY2Vuc2UgIE1JVFxuICovXG5cbi8vIFRoZSBfaXNCdWZmZXIgY2hlY2sgaXMgZm9yIFNhZmFyaSA1LTcgc3VwcG9ydCwgYmVjYXVzZSBpdCdzIG1pc3Npbmdcbi8vIE9iamVjdC5wcm90b3R5cGUuY29uc3RydWN0b3IuIFJlbW92ZSB0aGlzIGV2ZW50dWFsbHlcbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG9iaikge1xuICByZXR1cm4gb2JqICE9IG51bGwgJiYgKGlzQnVmZmVyKG9iaikgfHwgaXNTbG93QnVmZmVyKG9iaikgfHwgISFvYmouX2lzQnVmZmVyKVxufVxuXG5mdW5jdGlvbiBpc0J1ZmZlciAob2JqKSB7XG4gIHJldHVybiAhIW9iai5jb25zdHJ1Y3RvciAmJiB0eXBlb2Ygb2JqLmNvbnN0cnVjdG9yLmlzQnVmZmVyID09PSAnZnVuY3Rpb24nICYmIG9iai5jb25zdHJ1Y3Rvci5pc0J1ZmZlcihvYmopXG59XG5cbi8vIEZvciBOb2RlIHYwLjEwIHN1cHBvcnQuIFJlbW92ZSB0aGlzIGV2ZW50dWFsbHkuXG5mdW5jdGlvbiBpc1Nsb3dCdWZmZXIgKG9iaikge1xuICByZXR1cm4gdHlwZW9mIG9iai5yZWFkRmxvYXRMRSA9PT0gJ2Z1bmN0aW9uJyAmJiB0eXBlb2Ygb2JqLnNsaWNlID09PSAnZnVuY3Rpb24nICYmIGlzQnVmZmVyKG9iai5zbGljZSgwLCAwKSlcbn1cbiIsIlwidXNlIHN0cmljdFwiXG5cbmZ1bmN0aW9uIGR1cGVfYXJyYXkoY291bnQsIHZhbHVlLCBpKSB7XG4gIHZhciBjID0gY291bnRbaV18MFxuICBpZihjIDw9IDApIHtcbiAgICByZXR1cm4gW11cbiAgfVxuICB2YXIgcmVzdWx0ID0gbmV3IEFycmF5KGMpLCBqXG4gIGlmKGkgPT09IGNvdW50Lmxlbmd0aC0xKSB7XG4gICAgZm9yKGo9MDsgajxjOyArK2opIHtcbiAgICAgIHJlc3VsdFtqXSA9IHZhbHVlXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGZvcihqPTA7IGo8YzsgKytqKSB7XG4gICAgICByZXN1bHRbal0gPSBkdXBlX2FycmF5KGNvdW50LCB2YWx1ZSwgaSsxKVxuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0XG59XG5cbmZ1bmN0aW9uIGR1cGVfbnVtYmVyKGNvdW50LCB2YWx1ZSkge1xuICB2YXIgcmVzdWx0LCBpXG4gIHJlc3VsdCA9IG5ldyBBcnJheShjb3VudClcbiAgZm9yKGk9MDsgaTxjb3VudDsgKytpKSB7XG4gICAgcmVzdWx0W2ldID0gdmFsdWVcbiAgfVxuICByZXR1cm4gcmVzdWx0XG59XG5cbmZ1bmN0aW9uIGR1cGUoY291bnQsIHZhbHVlKSB7XG4gIGlmKHR5cGVvZiB2YWx1ZSA9PT0gXCJ1bmRlZmluZWRcIikge1xuICAgIHZhbHVlID0gMFxuICB9XG4gIHN3aXRjaCh0eXBlb2YgY291bnQpIHtcbiAgICBjYXNlIFwibnVtYmVyXCI6XG4gICAgICBpZihjb3VudCA+IDApIHtcbiAgICAgICAgcmV0dXJuIGR1cGVfbnVtYmVyKGNvdW50fDAsIHZhbHVlKVxuICAgICAgfVxuICAgIGJyZWFrXG4gICAgY2FzZSBcIm9iamVjdFwiOlxuICAgICAgaWYodHlwZW9mIChjb3VudC5sZW5ndGgpID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgIHJldHVybiBkdXBlX2FycmF5KGNvdW50LCB2YWx1ZSwgMClcbiAgICAgIH1cbiAgICBicmVha1xuICB9XG4gIHJldHVybiBbXVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGR1cGUiLCIoZnVuY3Rpb24gKGdsb2JhbCxCdWZmZXIpe1xuJ3VzZSBzdHJpY3QnXG5cbnZhciBiaXRzID0gcmVxdWlyZSgnYml0LXR3aWRkbGUnKVxudmFyIGR1cCA9IHJlcXVpcmUoJ2R1cCcpXG5cbi8vTGVnYWN5IHBvb2wgc3VwcG9ydFxuaWYoIWdsb2JhbC5fX1RZUEVEQVJSQVlfUE9PTCkge1xuICBnbG9iYWwuX19UWVBFREFSUkFZX1BPT0wgPSB7XG4gICAgICBVSU5UOCAgIDogZHVwKFszMiwgMF0pXG4gICAgLCBVSU5UMTYgIDogZHVwKFszMiwgMF0pXG4gICAgLCBVSU5UMzIgIDogZHVwKFszMiwgMF0pXG4gICAgLCBJTlQ4ICAgIDogZHVwKFszMiwgMF0pXG4gICAgLCBJTlQxNiAgIDogZHVwKFszMiwgMF0pXG4gICAgLCBJTlQzMiAgIDogZHVwKFszMiwgMF0pXG4gICAgLCBGTE9BVCAgIDogZHVwKFszMiwgMF0pXG4gICAgLCBET1VCTEUgIDogZHVwKFszMiwgMF0pXG4gICAgLCBEQVRBICAgIDogZHVwKFszMiwgMF0pXG4gICAgLCBVSU5UOEMgIDogZHVwKFszMiwgMF0pXG4gICAgLCBCVUZGRVIgIDogZHVwKFszMiwgMF0pXG4gIH1cbn1cblxudmFyIGhhc1VpbnQ4QyA9ICh0eXBlb2YgVWludDhDbGFtcGVkQXJyYXkpICE9PSAndW5kZWZpbmVkJ1xudmFyIFBPT0wgPSBnbG9iYWwuX19UWVBFREFSUkFZX1BPT0xcblxuLy9VcGdyYWRlIHBvb2xcbmlmKCFQT09MLlVJTlQ4Qykge1xuICBQT09MLlVJTlQ4QyA9IGR1cChbMzIsIDBdKVxufVxuaWYoIVBPT0wuQlVGRkVSKSB7XG4gIFBPT0wuQlVGRkVSID0gZHVwKFszMiwgMF0pXG59XG5cbi8vTmV3IHRlY2huaXF1ZTogT25seSBhbGxvY2F0ZSBmcm9tIEFycmF5QnVmZmVyVmlldyBhbmQgQnVmZmVyXG52YXIgREFUQSAgICA9IFBPT0wuREFUQVxuICAsIEJVRkZFUiAgPSBQT09MLkJVRkZFUlxuXG5leHBvcnRzLmZyZWUgPSBmdW5jdGlvbiBmcmVlKGFycmF5KSB7XG4gIGlmKEJ1ZmZlci5pc0J1ZmZlcihhcnJheSkpIHtcbiAgICBCVUZGRVJbYml0cy5sb2cyKGFycmF5Lmxlbmd0aCldLnB1c2goYXJyYXkpXG4gIH0gZWxzZSB7XG4gICAgaWYoT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGFycmF5KSAhPT0gJ1tvYmplY3QgQXJyYXlCdWZmZXJdJykge1xuICAgICAgYXJyYXkgPSBhcnJheS5idWZmZXJcbiAgICB9XG4gICAgaWYoIWFycmF5KSB7XG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgdmFyIG4gPSBhcnJheS5sZW5ndGggfHwgYXJyYXkuYnl0ZUxlbmd0aFxuICAgIHZhciBsb2dfbiA9IGJpdHMubG9nMihuKXwwXG4gICAgREFUQVtsb2dfbl0ucHVzaChhcnJheSlcbiAgfVxufVxuXG5mdW5jdGlvbiBmcmVlQXJyYXlCdWZmZXIoYnVmZmVyKSB7XG4gIGlmKCFidWZmZXIpIHtcbiAgICByZXR1cm5cbiAgfVxuICB2YXIgbiA9IGJ1ZmZlci5sZW5ndGggfHwgYnVmZmVyLmJ5dGVMZW5ndGhcbiAgdmFyIGxvZ19uID0gYml0cy5sb2cyKG4pXG4gIERBVEFbbG9nX25dLnB1c2goYnVmZmVyKVxufVxuXG5mdW5jdGlvbiBmcmVlVHlwZWRBcnJheShhcnJheSkge1xuICBmcmVlQXJyYXlCdWZmZXIoYXJyYXkuYnVmZmVyKVxufVxuXG5leHBvcnRzLmZyZWVVaW50OCA9XG5leHBvcnRzLmZyZWVVaW50MTYgPVxuZXhwb3J0cy5mcmVlVWludDMyID1cbmV4cG9ydHMuZnJlZUludDggPVxuZXhwb3J0cy5mcmVlSW50MTYgPVxuZXhwb3J0cy5mcmVlSW50MzIgPVxuZXhwb3J0cy5mcmVlRmxvYXQzMiA9IFxuZXhwb3J0cy5mcmVlRmxvYXQgPVxuZXhwb3J0cy5mcmVlRmxvYXQ2NCA9IFxuZXhwb3J0cy5mcmVlRG91YmxlID0gXG5leHBvcnRzLmZyZWVVaW50OENsYW1wZWQgPSBcbmV4cG9ydHMuZnJlZURhdGFWaWV3ID0gZnJlZVR5cGVkQXJyYXlcblxuZXhwb3J0cy5mcmVlQXJyYXlCdWZmZXIgPSBmcmVlQXJyYXlCdWZmZXJcblxuZXhwb3J0cy5mcmVlQnVmZmVyID0gZnVuY3Rpb24gZnJlZUJ1ZmZlcihhcnJheSkge1xuICBCVUZGRVJbYml0cy5sb2cyKGFycmF5Lmxlbmd0aCldLnB1c2goYXJyYXkpXG59XG5cbmV4cG9ydHMubWFsbG9jID0gZnVuY3Rpb24gbWFsbG9jKG4sIGR0eXBlKSB7XG4gIGlmKGR0eXBlID09PSB1bmRlZmluZWQgfHwgZHR5cGUgPT09ICdhcnJheWJ1ZmZlcicpIHtcbiAgICByZXR1cm4gbWFsbG9jQXJyYXlCdWZmZXIobilcbiAgfSBlbHNlIHtcbiAgICBzd2l0Y2goZHR5cGUpIHtcbiAgICAgIGNhc2UgJ3VpbnQ4JzpcbiAgICAgICAgcmV0dXJuIG1hbGxvY1VpbnQ4KG4pXG4gICAgICBjYXNlICd1aW50MTYnOlxuICAgICAgICByZXR1cm4gbWFsbG9jVWludDE2KG4pXG4gICAgICBjYXNlICd1aW50MzInOlxuICAgICAgICByZXR1cm4gbWFsbG9jVWludDMyKG4pXG4gICAgICBjYXNlICdpbnQ4JzpcbiAgICAgICAgcmV0dXJuIG1hbGxvY0ludDgobilcbiAgICAgIGNhc2UgJ2ludDE2JzpcbiAgICAgICAgcmV0dXJuIG1hbGxvY0ludDE2KG4pXG4gICAgICBjYXNlICdpbnQzMic6XG4gICAgICAgIHJldHVybiBtYWxsb2NJbnQzMihuKVxuICAgICAgY2FzZSAnZmxvYXQnOlxuICAgICAgY2FzZSAnZmxvYXQzMic6XG4gICAgICAgIHJldHVybiBtYWxsb2NGbG9hdChuKVxuICAgICAgY2FzZSAnZG91YmxlJzpcbiAgICAgIGNhc2UgJ2Zsb2F0NjQnOlxuICAgICAgICByZXR1cm4gbWFsbG9jRG91YmxlKG4pXG4gICAgICBjYXNlICd1aW50OF9jbGFtcGVkJzpcbiAgICAgICAgcmV0dXJuIG1hbGxvY1VpbnQ4Q2xhbXBlZChuKVxuICAgICAgY2FzZSAnYnVmZmVyJzpcbiAgICAgICAgcmV0dXJuIG1hbGxvY0J1ZmZlcihuKVxuICAgICAgY2FzZSAnZGF0YSc6XG4gICAgICBjYXNlICdkYXRhdmlldyc6XG4gICAgICAgIHJldHVybiBtYWxsb2NEYXRhVmlldyhuKVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gbnVsbFxuICAgIH1cbiAgfVxuICByZXR1cm4gbnVsbFxufVxuXG5mdW5jdGlvbiBtYWxsb2NBcnJheUJ1ZmZlcihuKSB7XG4gIHZhciBuID0gYml0cy5uZXh0UG93MihuKVxuICB2YXIgbG9nX24gPSBiaXRzLmxvZzIobilcbiAgdmFyIGQgPSBEQVRBW2xvZ19uXVxuICBpZihkLmxlbmd0aCA+IDApIHtcbiAgICByZXR1cm4gZC5wb3AoKVxuICB9XG4gIHJldHVybiBuZXcgQXJyYXlCdWZmZXIobilcbn1cbmV4cG9ydHMubWFsbG9jQXJyYXlCdWZmZXIgPSBtYWxsb2NBcnJheUJ1ZmZlclxuXG5mdW5jdGlvbiBtYWxsb2NVaW50OChuKSB7XG4gIHJldHVybiBuZXcgVWludDhBcnJheShtYWxsb2NBcnJheUJ1ZmZlcihuKSwgMCwgbilcbn1cbmV4cG9ydHMubWFsbG9jVWludDggPSBtYWxsb2NVaW50OFxuXG5mdW5jdGlvbiBtYWxsb2NVaW50MTYobikge1xuICByZXR1cm4gbmV3IFVpbnQxNkFycmF5KG1hbGxvY0FycmF5QnVmZmVyKDIqbiksIDAsIG4pXG59XG5leHBvcnRzLm1hbGxvY1VpbnQxNiA9IG1hbGxvY1VpbnQxNlxuXG5mdW5jdGlvbiBtYWxsb2NVaW50MzIobikge1xuICByZXR1cm4gbmV3IFVpbnQzMkFycmF5KG1hbGxvY0FycmF5QnVmZmVyKDQqbiksIDAsIG4pXG59XG5leHBvcnRzLm1hbGxvY1VpbnQzMiA9IG1hbGxvY1VpbnQzMlxuXG5mdW5jdGlvbiBtYWxsb2NJbnQ4KG4pIHtcbiAgcmV0dXJuIG5ldyBJbnQ4QXJyYXkobWFsbG9jQXJyYXlCdWZmZXIobiksIDAsIG4pXG59XG5leHBvcnRzLm1hbGxvY0ludDggPSBtYWxsb2NJbnQ4XG5cbmZ1bmN0aW9uIG1hbGxvY0ludDE2KG4pIHtcbiAgcmV0dXJuIG5ldyBJbnQxNkFycmF5KG1hbGxvY0FycmF5QnVmZmVyKDIqbiksIDAsIG4pXG59XG5leHBvcnRzLm1hbGxvY0ludDE2ID0gbWFsbG9jSW50MTZcblxuZnVuY3Rpb24gbWFsbG9jSW50MzIobikge1xuICByZXR1cm4gbmV3IEludDMyQXJyYXkobWFsbG9jQXJyYXlCdWZmZXIoNCpuKSwgMCwgbilcbn1cbmV4cG9ydHMubWFsbG9jSW50MzIgPSBtYWxsb2NJbnQzMlxuXG5mdW5jdGlvbiBtYWxsb2NGbG9hdChuKSB7XG4gIHJldHVybiBuZXcgRmxvYXQzMkFycmF5KG1hbGxvY0FycmF5QnVmZmVyKDQqbiksIDAsIG4pXG59XG5leHBvcnRzLm1hbGxvY0Zsb2F0MzIgPSBleHBvcnRzLm1hbGxvY0Zsb2F0ID0gbWFsbG9jRmxvYXRcblxuZnVuY3Rpb24gbWFsbG9jRG91YmxlKG4pIHtcbiAgcmV0dXJuIG5ldyBGbG9hdDY0QXJyYXkobWFsbG9jQXJyYXlCdWZmZXIoOCpuKSwgMCwgbilcbn1cbmV4cG9ydHMubWFsbG9jRmxvYXQ2NCA9IGV4cG9ydHMubWFsbG9jRG91YmxlID0gbWFsbG9jRG91YmxlXG5cbmZ1bmN0aW9uIG1hbGxvY1VpbnQ4Q2xhbXBlZChuKSB7XG4gIGlmKGhhc1VpbnQ4Qykge1xuICAgIHJldHVybiBuZXcgVWludDhDbGFtcGVkQXJyYXkobWFsbG9jQXJyYXlCdWZmZXIobiksIDAsIG4pXG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIG1hbGxvY1VpbnQ4KG4pXG4gIH1cbn1cbmV4cG9ydHMubWFsbG9jVWludDhDbGFtcGVkID0gbWFsbG9jVWludDhDbGFtcGVkXG5cbmZ1bmN0aW9uIG1hbGxvY0RhdGFWaWV3KG4pIHtcbiAgcmV0dXJuIG5ldyBEYXRhVmlldyhtYWxsb2NBcnJheUJ1ZmZlcihuKSwgMCwgbilcbn1cbmV4cG9ydHMubWFsbG9jRGF0YVZpZXcgPSBtYWxsb2NEYXRhVmlld1xuXG5mdW5jdGlvbiBtYWxsb2NCdWZmZXIobikge1xuICBuID0gYml0cy5uZXh0UG93MihuKVxuICB2YXIgbG9nX24gPSBiaXRzLmxvZzIobilcbiAgdmFyIGNhY2hlID0gQlVGRkVSW2xvZ19uXVxuICBpZihjYWNoZS5sZW5ndGggPiAwKSB7XG4gICAgcmV0dXJuIGNhY2hlLnBvcCgpXG4gIH1cbiAgcmV0dXJuIG5ldyBCdWZmZXIobilcbn1cbmV4cG9ydHMubWFsbG9jQnVmZmVyID0gbWFsbG9jQnVmZmVyXG5cbmV4cG9ydHMuY2xlYXJDYWNoZSA9IGZ1bmN0aW9uIGNsZWFyQ2FjaGUoKSB7XG4gIGZvcih2YXIgaT0wOyBpPDMyOyArK2kpIHtcbiAgICBQT09MLlVJTlQ4W2ldLmxlbmd0aCA9IDBcbiAgICBQT09MLlVJTlQxNltpXS5sZW5ndGggPSAwXG4gICAgUE9PTC5VSU5UMzJbaV0ubGVuZ3RoID0gMFxuICAgIFBPT0wuSU5UOFtpXS5sZW5ndGggPSAwXG4gICAgUE9PTC5JTlQxNltpXS5sZW5ndGggPSAwXG4gICAgUE9PTC5JTlQzMltpXS5sZW5ndGggPSAwXG4gICAgUE9PTC5GTE9BVFtpXS5sZW5ndGggPSAwXG4gICAgUE9PTC5ET1VCTEVbaV0ubGVuZ3RoID0gMFxuICAgIFBPT0wuVUlOVDhDW2ldLmxlbmd0aCA9IDBcbiAgICBEQVRBW2ldLmxlbmd0aCA9IDBcbiAgICBCVUZGRVJbaV0ubGVuZ3RoID0gMFxuICB9XG59XG59KS5jYWxsKHRoaXMsdHlwZW9mIGdsb2JhbCAhPT0gXCJ1bmRlZmluZWRcIiA/IGdsb2JhbCA6IHR5cGVvZiBzZWxmICE9PSBcInVuZGVmaW5lZFwiID8gc2VsZiA6IHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIgPyB3aW5kb3cgOiB7fSxyZXF1aXJlKFwiYnVmZmVyXCIpLkJ1ZmZlcilcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPWRhdGE6YXBwbGljYXRpb24vanNvbjtjaGFyc2V0OnV0Zi04O2Jhc2U2NCxleUoyWlhKemFXOXVJam96TENKemIzVnlZMlZ6SWpwYkltNXZaR1ZmYlc5a2RXeGxjeTkwZVhCbFpHRnljbUY1TFhCdmIyd3ZjRzl2YkM1cWN5SmRMQ0p1WVcxbGN5STZXMTBzSW0xaGNIQnBibWR6SWpvaU8wRkJRVUU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFN1FVRkRRVHRCUVVOQk8wRkJRMEU3UVVGRFFUdEJRVU5CTzBGQlEwRTdRVUZEUVR0QlFVTkJPMEZCUTBFaUxDSm1hV3hsSWpvaVoyVnVaWEpoZEdWa0xtcHpJaXdpYzI5MWNtTmxVbTl2ZENJNklpSXNJbk52ZFhKalpYTkRiMjUwWlc1MElqcGJJaWQxYzJVZ2MzUnlhV04wSjF4dVhHNTJZWElnWW1sMGN5QTlJSEpsY1hWcGNtVW9KMkpwZEMxMGQybGtaR3hsSnlsY2JuWmhjaUJrZFhBZ1BTQnlaWEYxYVhKbEtDZGtkWEFuS1Z4dVhHNHZMMHhsWjJGamVTQndiMjlzSUhOMWNIQnZjblJjYm1sbUtDRm5iRzlpWVd3dVgxOVVXVkJGUkVGU1VrRlpYMUJQVDB3cElIdGNiaUFnWjJ4dlltRnNMbDlmVkZsUVJVUkJVbEpCV1Y5UVQwOU1JRDBnZTF4dUlDQWdJQ0FnVlVsT1ZEZ2dJQ0E2SUdSMWNDaGJNeklzSURCZEtWeHVJQ0FnSUN3Z1ZVbE9WREUySUNBNklHUjFjQ2hiTXpJc0lEQmRLVnh1SUNBZ0lDd2dWVWxPVkRNeUlDQTZJR1IxY0NoYk16SXNJREJkS1Z4dUlDQWdJQ3dnU1U1VU9DQWdJQ0E2SUdSMWNDaGJNeklzSURCZEtWeHVJQ0FnSUN3Z1NVNVVNVFlnSUNBNklHUjFjQ2hiTXpJc0lEQmRLVnh1SUNBZ0lDd2dTVTVVTXpJZ0lDQTZJR1IxY0NoYk16SXNJREJkS1Z4dUlDQWdJQ3dnUmt4UFFWUWdJQ0E2SUdSMWNDaGJNeklzSURCZEtWeHVJQ0FnSUN3Z1JFOVZRa3hGSUNBNklHUjFjQ2hiTXpJc0lEQmRLVnh1SUNBZ0lDd2dSRUZVUVNBZ0lDQTZJR1IxY0NoYk16SXNJREJkS1Z4dUlDQWdJQ3dnVlVsT1ZEaERJQ0E2SUdSMWNDaGJNeklzSURCZEtWeHVJQ0FnSUN3Z1FsVkdSa1ZTSUNBNklHUjFjQ2hiTXpJc0lEQmRLVnh1SUNCOVhHNTlYRzVjYm5aaGNpQm9ZWE5WYVc1ME9FTWdQU0FvZEhsd1pXOW1JRlZwYm5RNFEyeGhiWEJsWkVGeWNtRjVLU0FoUFQwZ0ozVnVaR1ZtYVc1bFpDZGNiblpoY2lCUVQwOU1JRDBnWjJ4dlltRnNMbDlmVkZsUVJVUkJVbEpCV1Y5UVQwOU1YRzVjYmk4dlZYQm5jbUZrWlNCd2IyOXNYRzVwWmlnaFVFOVBUQzVWU1U1VU9FTXBJSHRjYmlBZ1VFOVBUQzVWU1U1VU9FTWdQU0JrZFhBb1d6TXlMQ0F3WFNsY2JuMWNibWxtS0NGUVQwOU1Ma0pWUmtaRlVpa2dlMXh1SUNCUVQwOU1Ma0pWUmtaRlVpQTlJR1IxY0NoYk16SXNJREJkS1Z4dWZWeHVYRzR2TDA1bGR5QjBaV05vYm1seGRXVTZJRTl1YkhrZ1lXeHNiMk5oZEdVZ1puSnZiU0JCY25KaGVVSjFabVpsY2xacFpYY2dZVzVrSUVKMVptWmxjbHh1ZG1GeUlFUkJWRUVnSUNBZ1BTQlFUMDlNTGtSQlZFRmNiaUFnTENCQ1ZVWkdSVklnSUQwZ1VFOVBUQzVDVlVaR1JWSmNibHh1Wlhod2IzSjBjeTVtY21WbElEMGdablZ1WTNScGIyNGdabkpsWlNoaGNuSmhlU2tnZTF4dUlDQnBaaWhDZFdabVpYSXVhWE5DZFdabVpYSW9ZWEp5WVhrcEtTQjdYRzRnSUNBZ1FsVkdSa1ZTVzJKcGRITXViRzluTWloaGNuSmhlUzVzWlc1bmRHZ3BYUzV3ZFhOb0tHRnljbUY1S1Z4dUlDQjlJR1ZzYzJVZ2UxeHVJQ0FnSUdsbUtFOWlhbVZqZEM1d2NtOTBiM1I1Y0dVdWRHOVRkSEpwYm1jdVkyRnNiQ2hoY25KaGVTa2dJVDA5SUNkYmIySnFaV04wSUVGeWNtRjVRblZtWm1WeVhTY3BJSHRjYmlBZ0lDQWdJR0Z5Y21GNUlEMGdZWEp5WVhrdVluVm1abVZ5WEc0Z0lDQWdmVnh1SUNBZ0lHbG1LQ0ZoY25KaGVTa2dlMXh1SUNBZ0lDQWdjbVYwZFhKdVhHNGdJQ0FnZlZ4dUlDQWdJSFpoY2lCdUlEMGdZWEp5WVhrdWJHVnVaM1JvSUh4OElHRnljbUY1TG1KNWRHVk1aVzVuZEdoY2JpQWdJQ0IyWVhJZ2JHOW5YMjRnUFNCaWFYUnpMbXh2WnpJb2JpbDhNRnh1SUNBZ0lFUkJWRUZiYkc5blgyNWRMbkIxYzJnb1lYSnlZWGtwWEc0Z0lIMWNibjFjYmx4dVpuVnVZM1JwYjI0Z1puSmxaVUZ5Y21GNVFuVm1abVZ5S0dKMVptWmxjaWtnZTF4dUlDQnBaaWdoWW5WbVptVnlLU0I3WEc0Z0lDQWdjbVYwZFhKdVhHNGdJSDFjYmlBZ2RtRnlJRzRnUFNCaWRXWm1aWEl1YkdWdVozUm9JSHg4SUdKMVptWmxjaTVpZVhSbFRHVnVaM1JvWEc0Z0lIWmhjaUJzYjJkZmJpQTlJR0pwZEhNdWJHOW5NaWh1S1Z4dUlDQkVRVlJCVzJ4dloxOXVYUzV3ZFhOb0tHSjFabVpsY2lsY2JuMWNibHh1Wm5WdVkzUnBiMjRnWm5KbFpWUjVjR1ZrUVhKeVlYa29ZWEp5WVhrcElIdGNiaUFnWm5KbFpVRnljbUY1UW5WbVptVnlLR0Z5Y21GNUxtSjFabVpsY2lsY2JuMWNibHh1Wlhod2IzSjBjeTVtY21WbFZXbHVkRGdnUFZ4dVpYaHdiM0owY3k1bWNtVmxWV2x1ZERFMklEMWNibVY0Y0c5eWRITXVabkpsWlZWcGJuUXpNaUE5WEc1bGVIQnZjblJ6TG1aeVpXVkpiblE0SUQxY2JtVjRjRzl5ZEhNdVpuSmxaVWx1ZERFMklEMWNibVY0Y0c5eWRITXVabkpsWlVsdWRETXlJRDFjYm1WNGNHOXlkSE11Wm5KbFpVWnNiMkYwTXpJZ1BTQmNibVY0Y0c5eWRITXVabkpsWlVac2IyRjBJRDFjYm1WNGNHOXlkSE11Wm5KbFpVWnNiMkYwTmpRZ1BTQmNibVY0Y0c5eWRITXVabkpsWlVSdmRXSnNaU0E5SUZ4dVpYaHdiM0owY3k1bWNtVmxWV2x1ZERoRGJHRnRjR1ZrSUQwZ1hHNWxlSEJ2Y25SekxtWnlaV1ZFWVhSaFZtbGxkeUE5SUdaeVpXVlVlWEJsWkVGeWNtRjVYRzVjYm1WNGNHOXlkSE11Wm5KbFpVRnljbUY1UW5WbVptVnlJRDBnWm5KbFpVRnljbUY1UW5WbVptVnlYRzVjYm1WNGNHOXlkSE11Wm5KbFpVSjFabVpsY2lBOUlHWjFibU4wYVc5dUlHWnlaV1ZDZFdabVpYSW9ZWEp5WVhrcElIdGNiaUFnUWxWR1JrVlNXMkpwZEhNdWJHOW5NaWhoY25KaGVTNXNaVzVuZEdncFhTNXdkWE5vS0dGeWNtRjVLVnh1ZlZ4dVhHNWxlSEJ2Y25SekxtMWhiR3h2WXlBOUlHWjFibU4wYVc5dUlHMWhiR3h2WXlodUxDQmtkSGx3WlNrZ2UxeHVJQ0JwWmloa2RIbHdaU0E5UFQwZ2RXNWtaV1pwYm1Wa0lIeDhJR1IwZVhCbElEMDlQU0FuWVhKeVlYbGlkV1ptWlhJbktTQjdYRzRnSUNBZ2NtVjBkWEp1SUcxaGJHeHZZMEZ5Y21GNVFuVm1abVZ5S0c0cFhHNGdJSDBnWld4elpTQjdYRzRnSUNBZ2MzZHBkR05vS0dSMGVYQmxLU0I3WEc0Z0lDQWdJQ0JqWVhObElDZDFhVzUwT0NjNlhHNGdJQ0FnSUNBZ0lISmxkSFZ5YmlCdFlXeHNiMk5WYVc1ME9DaHVLVnh1SUNBZ0lDQWdZMkZ6WlNBbmRXbHVkREUySnpwY2JpQWdJQ0FnSUNBZ2NtVjBkWEp1SUcxaGJHeHZZMVZwYm5ReE5paHVLVnh1SUNBZ0lDQWdZMkZ6WlNBbmRXbHVkRE15SnpwY2JpQWdJQ0FnSUNBZ2NtVjBkWEp1SUcxaGJHeHZZMVZwYm5Rek1paHVLVnh1SUNBZ0lDQWdZMkZ6WlNBbmFXNTBPQ2M2WEc0Z0lDQWdJQ0FnSUhKbGRIVnliaUJ0WVd4c2IyTkpiblE0S0c0cFhHNGdJQ0FnSUNCallYTmxJQ2RwYm5ReE5pYzZYRzRnSUNBZ0lDQWdJSEpsZEhWeWJpQnRZV3hzYjJOSmJuUXhOaWh1S1Z4dUlDQWdJQ0FnWTJGelpTQW5hVzUwTXpJbk9seHVJQ0FnSUNBZ0lDQnlaWFIxY200Z2JXRnNiRzlqU1c1ME16SW9iaWxjYmlBZ0lDQWdJR05oYzJVZ0oyWnNiMkYwSnpwY2JpQWdJQ0FnSUdOaGMyVWdKMlpzYjJGME16SW5PbHh1SUNBZ0lDQWdJQ0J5WlhSMWNtNGdiV0ZzYkc5alJteHZZWFFvYmlsY2JpQWdJQ0FnSUdOaGMyVWdKMlJ2ZFdKc1pTYzZYRzRnSUNBZ0lDQmpZWE5sSUNkbWJHOWhkRFkwSnpwY2JpQWdJQ0FnSUNBZ2NtVjBkWEp1SUcxaGJHeHZZMFJ2ZFdKc1pTaHVLVnh1SUNBZ0lDQWdZMkZ6WlNBbmRXbHVkRGhmWTJ4aGJYQmxaQ2M2WEc0Z0lDQWdJQ0FnSUhKbGRIVnliaUJ0WVd4c2IyTlZhVzUwT0VOc1lXMXdaV1FvYmlsY2JpQWdJQ0FnSUdOaGMyVWdKMkoxWm1abGNpYzZYRzRnSUNBZ0lDQWdJSEpsZEhWeWJpQnRZV3hzYjJOQ2RXWm1aWElvYmlsY2JpQWdJQ0FnSUdOaGMyVWdKMlJoZEdFbk9seHVJQ0FnSUNBZ1kyRnpaU0FuWkdGMFlYWnBaWGNuT2x4dUlDQWdJQ0FnSUNCeVpYUjFjbTRnYldGc2JHOWpSR0YwWVZacFpYY29iaWxjYmx4dUlDQWdJQ0FnWkdWbVlYVnNkRHBjYmlBZ0lDQWdJQ0FnY21WMGRYSnVJRzUxYkd4Y2JpQWdJQ0I5WEc0Z0lIMWNiaUFnY21WMGRYSnVJRzUxYkd4Y2JuMWNibHh1Wm5WdVkzUnBiMjRnYldGc2JHOWpRWEp5WVhsQ2RXWm1aWElvYmlrZ2UxeHVJQ0IyWVhJZ2JpQTlJR0pwZEhNdWJtVjRkRkJ2ZHpJb2JpbGNiaUFnZG1GeUlHeHZaMTl1SUQwZ1ltbDBjeTVzYjJjeUtHNHBYRzRnSUhaaGNpQmtJRDBnUkVGVVFWdHNiMmRmYmwxY2JpQWdhV1lvWkM1c1pXNW5kR2dnUGlBd0tTQjdYRzRnSUNBZ2NtVjBkWEp1SUdRdWNHOXdLQ2xjYmlBZ2ZWeHVJQ0J5WlhSMWNtNGdibVYzSUVGeWNtRjVRblZtWm1WeUtHNHBYRzU5WEc1bGVIQnZjblJ6TG0xaGJHeHZZMEZ5Y21GNVFuVm1abVZ5SUQwZ2JXRnNiRzlqUVhKeVlYbENkV1ptWlhKY2JseHVablZ1WTNScGIyNGdiV0ZzYkc5alZXbHVkRGdvYmlrZ2UxeHVJQ0J5WlhSMWNtNGdibVYzSUZWcGJuUTRRWEp5WVhrb2JXRnNiRzlqUVhKeVlYbENkV1ptWlhJb2Jpa3NJREFzSUc0cFhHNTlYRzVsZUhCdmNuUnpMbTFoYkd4dlkxVnBiblE0SUQwZ2JXRnNiRzlqVldsdWREaGNibHh1Wm5WdVkzUnBiMjRnYldGc2JHOWpWV2x1ZERFMktHNHBJSHRjYmlBZ2NtVjBkWEp1SUc1bGR5QlZhVzUwTVRaQmNuSmhlU2h0WVd4c2IyTkJjbkpoZVVKMVptWmxjaWd5S200cExDQXdMQ0J1S1Z4dWZWeHVaWGh3YjNKMGN5NXRZV3hzYjJOVmFXNTBNVFlnUFNCdFlXeHNiMk5WYVc1ME1UWmNibHh1Wm5WdVkzUnBiMjRnYldGc2JHOWpWV2x1ZERNeUtHNHBJSHRjYmlBZ2NtVjBkWEp1SUc1bGR5QlZhVzUwTXpKQmNuSmhlU2h0WVd4c2IyTkJjbkpoZVVKMVptWmxjaWcwS200cExDQXdMQ0J1S1Z4dWZWeHVaWGh3YjNKMGN5NXRZV3hzYjJOVmFXNTBNeklnUFNCdFlXeHNiMk5WYVc1ME16SmNibHh1Wm5WdVkzUnBiMjRnYldGc2JHOWpTVzUwT0NodUtTQjdYRzRnSUhKbGRIVnliaUJ1WlhjZ1NXNTBPRUZ5Y21GNUtHMWhiR3h2WTBGeWNtRjVRblZtWm1WeUtHNHBMQ0F3TENCdUtWeHVmVnh1Wlhod2IzSjBjeTV0WVd4c2IyTkpiblE0SUQwZ2JXRnNiRzlqU1c1ME9GeHVYRzVtZFc1amRHbHZiaUJ0WVd4c2IyTkpiblF4TmlodUtTQjdYRzRnSUhKbGRIVnliaUJ1WlhjZ1NXNTBNVFpCY25KaGVTaHRZV3hzYjJOQmNuSmhlVUoxWm1abGNpZ3lLbTRwTENBd0xDQnVLVnh1ZlZ4dVpYaHdiM0owY3k1dFlXeHNiMk5KYm5ReE5pQTlJRzFoYkd4dlkwbHVkREUyWEc1Y2JtWjFibU4wYVc5dUlHMWhiR3h2WTBsdWRETXlLRzRwSUh0Y2JpQWdjbVYwZFhKdUlHNWxkeUJKYm5Rek1rRnljbUY1S0cxaGJHeHZZMEZ5Y21GNVFuVm1abVZ5S0RRcWJpa3NJREFzSUc0cFhHNTlYRzVsZUhCdmNuUnpMbTFoYkd4dlkwbHVkRE15SUQwZ2JXRnNiRzlqU1c1ME16SmNibHh1Wm5WdVkzUnBiMjRnYldGc2JHOWpSbXh2WVhRb2Jpa2dlMXh1SUNCeVpYUjFjbTRnYm1WM0lFWnNiMkYwTXpKQmNuSmhlU2h0WVd4c2IyTkJjbkpoZVVKMVptWmxjaWcwS200cExDQXdMQ0J1S1Z4dWZWeHVaWGh3YjNKMGN5NXRZV3hzYjJOR2JHOWhkRE15SUQwZ1pYaHdiM0owY3k1dFlXeHNiMk5HYkc5aGRDQTlJRzFoYkd4dlkwWnNiMkYwWEc1Y2JtWjFibU4wYVc5dUlHMWhiR3h2WTBSdmRXSnNaU2h1S1NCN1hHNGdJSEpsZEhWeWJpQnVaWGNnUm14dllYUTJORUZ5Y21GNUtHMWhiR3h2WTBGeWNtRjVRblZtWm1WeUtEZ3FiaWtzSURBc0lHNHBYRzU5WEc1bGVIQnZjblJ6TG0xaGJHeHZZMFpzYjJGME5qUWdQU0JsZUhCdmNuUnpMbTFoYkd4dlkwUnZkV0pzWlNBOUlHMWhiR3h2WTBSdmRXSnNaVnh1WEc1bWRXNWpkR2x2YmlCdFlXeHNiMk5WYVc1ME9FTnNZVzF3WldRb2Jpa2dlMXh1SUNCcFppaG9ZWE5WYVc1ME9FTXBJSHRjYmlBZ0lDQnlaWFIxY200Z2JtVjNJRlZwYm5RNFEyeGhiWEJsWkVGeWNtRjVLRzFoYkd4dlkwRnljbUY1UW5WbVptVnlLRzRwTENBd0xDQnVLVnh1SUNCOUlHVnNjMlVnZTF4dUlDQWdJSEpsZEhWeWJpQnRZV3hzYjJOVmFXNTBPQ2h1S1Z4dUlDQjlYRzU5WEc1bGVIQnZjblJ6TG0xaGJHeHZZMVZwYm5RNFEyeGhiWEJsWkNBOUlHMWhiR3h2WTFWcGJuUTRRMnhoYlhCbFpGeHVYRzVtZFc1amRHbHZiaUJ0WVd4c2IyTkVZWFJoVm1sbGR5aHVLU0I3WEc0Z0lISmxkSFZ5YmlCdVpYY2dSR0YwWVZacFpYY29iV0ZzYkc5alFYSnlZWGxDZFdabVpYSW9iaWtzSURBc0lHNHBYRzU5WEc1bGVIQnZjblJ6TG0xaGJHeHZZMFJoZEdGV2FXVjNJRDBnYldGc2JHOWpSR0YwWVZacFpYZGNibHh1Wm5WdVkzUnBiMjRnYldGc2JHOWpRblZtWm1WeUtHNHBJSHRjYmlBZ2JpQTlJR0pwZEhNdWJtVjRkRkJ2ZHpJb2JpbGNiaUFnZG1GeUlHeHZaMTl1SUQwZ1ltbDBjeTVzYjJjeUtHNHBYRzRnSUhaaGNpQmpZV05vWlNBOUlFSlZSa1pGVWx0c2IyZGZibDFjYmlBZ2FXWW9ZMkZqYUdVdWJHVnVaM1JvSUQ0Z01Da2dlMXh1SUNBZ0lISmxkSFZ5YmlCallXTm9aUzV3YjNBb0tWeHVJQ0I5WEc0Z0lISmxkSFZ5YmlCdVpYY2dRblZtWm1WeUtHNHBYRzU5WEc1bGVIQnZjblJ6TG0xaGJHeHZZMEoxWm1abGNpQTlJRzFoYkd4dlkwSjFabVpsY2x4dVhHNWxlSEJ2Y25SekxtTnNaV0Z5UTJGamFHVWdQU0JtZFc1amRHbHZiaUJqYkdWaGNrTmhZMmhsS0NrZ2UxeHVJQ0JtYjNJb2RtRnlJR2s5TURzZ2FUd3pNanNnS3l0cEtTQjdYRzRnSUNBZ1VFOVBUQzVWU1U1VU9GdHBYUzVzWlc1bmRHZ2dQU0F3WEc0Z0lDQWdVRTlQVEM1VlNVNVVNVFpiYVYwdWJHVnVaM1JvSUQwZ01GeHVJQ0FnSUZCUFQwd3VWVWxPVkRNeVcybGRMbXhsYm1kMGFDQTlJREJjYmlBZ0lDQlFUMDlNTGtsT1ZEaGJhVjB1YkdWdVozUm9JRDBnTUZ4dUlDQWdJRkJQVDB3dVNVNVVNVFpiYVYwdWJHVnVaM1JvSUQwZ01GeHVJQ0FnSUZCUFQwd3VTVTVVTXpKYmFWMHViR1Z1WjNSb0lEMGdNRnh1SUNBZ0lGQlBUMHd1Umt4UFFWUmJhVjB1YkdWdVozUm9JRDBnTUZ4dUlDQWdJRkJQVDB3dVJFOVZRa3hGVzJsZExteGxibWQwYUNBOUlEQmNiaUFnSUNCUVQwOU1MbFZKVGxRNFExdHBYUzVzWlc1bmRHZ2dQU0F3WEc0Z0lDQWdSRUZVUVZ0cFhTNXNaVzVuZEdnZ1BTQXdYRzRnSUNBZ1FsVkdSa1ZTVzJsZExteGxibWQwYUNBOUlEQmNiaUFnZlZ4dWZTSmRmUT09IiwiXCJ1c2Ugc3RyaWN0XCJcblxubW9kdWxlLmV4cG9ydHMgPSBjcmVhdGVLRFRyZWVcbm1vZHVsZS5leHBvcnRzLmRlc2VyaWFsaXplID0gZGVzZXJpYWxpemVLRFRyZWVcblxudmFyIG5kYXJyYXkgPSByZXF1aXJlKFwibmRhcnJheVwiKVxudmFyIG5kc2VsZWN0ID0gcmVxdWlyZShcIm5kYXJyYXktc2VsZWN0XCIpXG52YXIgcGFjayA9IHJlcXVpcmUoXCJuZGFycmF5LXBhY2tcIilcbnZhciBvcHMgPSByZXF1aXJlKFwibmRhcnJheS1vcHNcIilcbnZhciBuZHNjcmF0Y2ggPSByZXF1aXJlKFwibmRhcnJheS1zY3JhdGNoXCIpXG52YXIgcG9vbCA9IHJlcXVpcmUoXCJ0eXBlZGFycmF5LXBvb2xcIilcbnZhciBpbm9yZGVyVHJlZSA9IHJlcXVpcmUoXCJpbm9yZGVyLXRyZWUtbGF5b3V0XCIpXG52YXIgYml0cyA9IHJlcXVpcmUoXCJiaXQtdHdpZGRsZVwiKVxudmFyIEtEVEhlYXAgPSByZXF1aXJlKFwiLi9saWIvaGVhcC5qc1wiKVxuXG5mdW5jdGlvbiBLRFRyZWUocG9pbnRzLCBpZHMsIG4sIGQpIHtcbiAgdGhpcy5wb2ludHMgPSBwb2ludHNcbiAgdGhpcy5pZHMgPSBpZHNcbiAgdGhpcy5kaW1lbnNpb24gPSBkXG4gIHRoaXMubGVuZ3RoID0gblxufVxuXG52YXIgcHJvdG8gPSBLRFRyZWUucHJvdG90eXBlXG5cbnByb3RvLnNlcmlhbGl6ZSA9IGZ1bmN0aW9uKCkge1xuICBpZih0aGlzLmxlbmd0aCA+IDApIHtcbiAgICByZXR1cm4ge1xuICAgICAgcDogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodGhpcy5wb2ludHMuZGF0YSwgMCwgdGhpcy5sZW5ndGgqdGhpcy5kaW1lbnNpb24pLFxuICAgICAgaTogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodGhpcy5pZHMsIDAsIHRoaXMubGVuZ3RoKVxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICByZXR1cm4geyBkOiB0aGlzLmRpbWVuc2lvbiB9XG4gIH1cbn1cblxuLy9SYW5nZSBxdWVyeVxucHJvdG8ucmFuZ2UgPSBmdW5jdGlvbiBrZHRSYW5nZVF1ZXJ5KGxvLCBoaSwgdmlzaXQpIHtcbiAgdmFyIG4gPSB0aGlzLmxlbmd0aFxuICBpZihuIDwgMSkge1xuICAgIHJldHVyblxuICB9XG5cbiAgLy9DaGVjayBkZWdlbmVyYXRlIGNhc2VcbiAgdmFyIGQgPSB0aGlzLmRpbWVuc2lvblxuICBmb3IodmFyIGk9MDsgaTxkOyArK2kpIHtcbiAgICBpZihoaVtpXSA8IGxvW2ldKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG4gIH1cblxuICB2YXIgcG9pbnRzID0gdGhpcy5wb2ludHNcbiAgdmFyIGlkcyA9IHRoaXMuaWRzXG5cbiAgLy9XYWxrIHRyZWUgaW4gbGV2ZWwgb3JkZXIsIHNraXBwaW5nIHN1YnRyZWVzIHdoaWNoIGRvIG5vdCBpbnRlcnNlY3QgcmFuZ2VcbiAgdmFyIHZpc2l0UmFuZ2UgPSBuZHNjcmF0Y2gubWFsbG9jKFtuLCAyLCBkXSlcbiAgdmFyIHZpc2l0SW5kZXggPSBwb29sLm1hbGxvY0ludDMyKG4pXG4gIHZhciByYW5nZURhdGEgPSB2aXNpdFJhbmdlLmRhdGFcbiAgdmFyIHBvaW50RGF0YSA9IHBvaW50cy5kYXRhXG4gIHZhciB2aXNpdENvdW50ID0gMVxuICB2YXIgdmlzaXRUb3AgPSAwXG4gIHZhciByZXR2YWxcblxuICB2aXNpdEluZGV4WzBdID0gMFxuICBwYWNrKGxvLCB2aXNpdFJhbmdlLnBpY2soMCwwKSlcbiAgcGFjayhoaSwgdmlzaXRSYW5nZS5waWNrKDAsMSkpXG4gIFxuICB3aGlsZSh2aXNpdFRvcCA8IHZpc2l0Q291bnQpIHtcbiAgICB2YXIgaWR4ID0gdmlzaXRJbmRleFt2aXNpdFRvcF1cbiAgICB2YXIgayA9IGJpdHMubG9nMihpZHgrMSklZFxuICAgIHZhciBsb2lkeCA9IHZpc2l0UmFuZ2UuaW5kZXgodmlzaXRUb3AsIDAsIDApXG4gICAgdmFyIGhpaWR4ID0gdmlzaXRSYW5nZS5pbmRleCh2aXNpdFRvcCwgMSwgMClcbiAgICB2YXIgcGlkeCA9IHBvaW50cy5pbmRleChpZHgsIDApXG5cbiAgICB2YXIgdmlzaXRQb2ludCA9IHRydWVcbiAgICBmb3IodmFyIGk9MDsgaTxkOyArK2kpIHtcbiAgICAgIHZhciBwYyA9IHBvaW50RGF0YVtwaWR4K2ldXG4gICAgICBpZigocGMgPCByYW5nZURhdGFbbG9pZHggKyBpXSkgfHwgXG4gICAgICAgICAocmFuZ2VEYXRhW2hpaWR4ICsgaV0gPCBwYykpIHtcbiAgICAgICAgdmlzaXRQb2ludCA9IGZhbHNlXG4gICAgICAgIGJyZWFrXG4gICAgICB9XG4gICAgfVxuICAgIGlmKHZpc2l0UG9pbnQpIHtcbiAgICAgIHJldHZhbCA9IHZpc2l0KGlkc1tpZHhdKVxuICAgICAgaWYocmV0dmFsICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgYnJlYWtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvL1Zpc2l0IGNoaWxkcmVuXG4gICAgdmFyIHBrID0gcG9pbnREYXRhW3BpZHgra11cbiAgICB2YXIgaGsgPSByYW5nZURhdGFbaGlpZHgra11cbiAgICB2YXIgbGsgPSByYW5nZURhdGFbbG9pZHgra11cbiAgICBpZihsayA8PSBwaykge1xuICAgICAgdmFyIGxlZnQgPSAyICogaWR4ICsgMVxuICAgICAgaWYobGVmdCA8IG4pIHtcbiAgICAgICAgdmlzaXRJbmRleFt2aXNpdENvdW50XSA9IGxlZnRcbiAgICAgICAgdmFyIHkgPSB2aXNpdFJhbmdlLmluZGV4KHZpc2l0Q291bnQsIDAsIDApXG4gICAgICAgIGZvcih2YXIgaT0wOyBpPGQ7ICsraSkge1xuICAgICAgICAgIHJhbmdlRGF0YVt5K2ldID0gcmFuZ2VEYXRhW2xvaWR4K2ldXG4gICAgICAgIH1cbiAgICAgICAgdmFyIHogPSB2aXNpdFJhbmdlLmluZGV4KHZpc2l0Q291bnQsIDEsIDApXG4gICAgICAgIGZvcih2YXIgaT0wOyBpPGQ7ICsraSkge1xuICAgICAgICAgIHJhbmdlRGF0YVt6K2ldID0gcmFuZ2VEYXRhW2hpaWR4K2ldXG4gICAgICAgIH1cbiAgICAgICAgcmFuZ2VEYXRhW3ora10gPSBNYXRoLm1pbihoaywgcGspXG4gICAgICAgIHZpc2l0Q291bnQgKz0gMVxuICAgICAgfVxuICAgIH1cbiAgICBpZihwayA8PSBoaykge1xuICAgICAgdmFyIHJpZ2h0ID0gMiAqIChpZHggKyAxKVxuICAgICAgaWYocmlnaHQgPCBuKSB7XG4gICAgICAgIHZpc2l0SW5kZXhbdmlzaXRDb3VudF0gPSByaWdodFxuICAgICAgICB2YXIgeSA9IHZpc2l0UmFuZ2UuaW5kZXgodmlzaXRDb3VudCwgMCwgMClcbiAgICAgICAgZm9yKHZhciBpPTA7IGk8ZDsgKytpKSB7XG4gICAgICAgICAgcmFuZ2VEYXRhW3kraV0gPSByYW5nZURhdGFbbG9pZHgraV1cbiAgICAgICAgfVxuICAgICAgICB2YXIgeiA9IHZpc2l0UmFuZ2UuaW5kZXgodmlzaXRDb3VudCwgMSwgMClcbiAgICAgICAgZm9yKHZhciBpPTA7IGk8ZDsgKytpKSB7XG4gICAgICAgICAgcmFuZ2VEYXRhW3oraV0gPSByYW5nZURhdGFbaGlpZHgraV1cbiAgICAgICAgfVxuICAgICAgICByYW5nZURhdGFbeStrXSA9IE1hdGgubWF4KGxrLCBwaylcbiAgICAgICAgdmlzaXRDb3VudCArPSAxXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy9JbmNyZW1lbnQgcG9pbnRlclxuICAgIHZpc2l0VG9wICs9IDFcbiAgfVxuICBuZHNjcmF0Y2guZnJlZSh2aXNpdFJhbmdlKVxuICBwb29sLmZyZWUodmlzaXRJbmRleClcbiAgcmV0dXJuIHJldHZhbFxufVxuXG5wcm90by5ybm4gPSBmdW5jdGlvbihwb2ludCwgcmFkaXVzLCB2aXNpdCkge1xuICBpZihyYWRpdXMgPCAwKSB7XG4gICAgcmV0dXJuXG4gIH1cbiAgdmFyIG4gPSB0aGlzLmxlbmd0aFxuICBpZihuIDwgMSkge1xuICAgIHJldHVyblxuICB9XG4gIHZhciBkID0gdGhpcy5kaW1lbnNpb25cbiAgdmFyIHBvaW50cyA9IHRoaXMucG9pbnRzXG4gIHZhciBpZHMgPSB0aGlzLmlkc1xuXG4gIC8vV2FsayB0cmVlIGluIGxldmVsIG9yZGVyLCBza2lwcGluZyBzdWJ0cmVlcyB3aGljaCBkbyBub3QgaW50ZXJzZWN0IHNwaGVyZVxuICB2YXIgdmlzaXREaXN0YW5jZSA9IG5kc2NyYXRjaC5tYWxsb2MoW24sIGRdKVxuICB2YXIgdmlzaXRJbmRleCA9IHBvb2wubWFsbG9jSW50MzIobilcbiAgdmFyIGRpc3RhbmNlRGF0YSA9IHZpc2l0RGlzdGFuY2UuZGF0YVxuICB2YXIgcG9pbnREYXRhID0gcG9pbnRzLmRhdGFcbiAgdmFyIHZpc2l0Q291bnQgPSAxXG4gIHZhciB2aXNpdFRvcCA9IDBcbiAgdmFyIHIyID0gcmFkaXVzKnJhZGl1c1xuICB2YXIgcmV0dmFsXG5cbiAgLy9Jbml0aWFsaXplIHRvcCBvZiBxdWV1ZVxuICB2aXNpdEluZGV4WzBdID0gMFxuICBmb3IodmFyIGk9MDsgaTxkOyArK2kpIHtcbiAgICB2aXNpdERpc3RhbmNlLnNldCgwLCBpLCAwKVxuICB9XG5cbiAgLy9XYWxrIG92ZXIgcXVldWVcbiAgd2hpbGUodmlzaXRUb3AgPCB2aXNpdENvdW50KSB7XG4gICAgdmFyIGlkeCA9IHZpc2l0SW5kZXhbdmlzaXRUb3BdXG4gICAgdmFyIHBpZHggPSBwb2ludHMuaW5kZXgoaWR4LCAwKVxuXG4gICAgLy9DaGVjayBpZiBwb2ludCBpbiBzcGhlcmVcbiAgICB2YXIgZDIgPSAwLjBcbiAgICBmb3IodmFyIGk9MDsgaTxkOyArK2kpIHtcbiAgICAgIGQyICs9IE1hdGgucG93KHBvaW50W2ldIC0gcG9pbnREYXRhW3BpZHgraV0sIDIpXG4gICAgfVxuICAgIGlmKGQyIDw9IHIyKSB7XG4gICAgICByZXR2YWwgPSB2aXNpdChpZHNbaWR4XSlcbiAgICAgIGlmKHJldHZhbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGJyZWFrXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy9WaXNpdCBjaGlsZHJlblxuICAgIHZhciBrID0gYml0cy5sb2cyKGlkeCsxKSVkXG4gICAgdmFyIGRzID0gMC4wXG4gICAgdmFyIGRpZHggPSB2aXNpdERpc3RhbmNlLmluZGV4KHZpc2l0VG9wLCAwKVxuICAgIGZvcih2YXIgaT0wOyBpPGQ7ICsraSkge1xuICAgICAgaWYoaSAhPT0gaykge1xuICAgICAgICBkcyArPSBkaXN0YW5jZURhdGFbZGlkeCArIGldXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy9IYW5kbGUgc3BsaXQgYXhpc1xuICAgIHZhciBxayA9IHBvaW50W2tdXG4gICAgdmFyIHBrID0gcG9pbnREYXRhW3BpZHgra11cbiAgICB2YXIgZGsgPSBkaXN0YW5jZURhdGFbZGlkeCtrXVxuICAgIHZhciBsayA9IGRrXG4gICAgdmFyIGhrID0gZGtcbiAgICBpZihxayA8IHBrKSB7XG4gICAgICBoayA9IE1hdGgubWF4KGRrLCBNYXRoLnBvdyhwayAtIHFrLCAyKSlcbiAgICB9IGVsc2Uge1xuICAgICAgbGsgPSBNYXRoLm1heChkaywgTWF0aC5wb3cocGsgLSBxaywgMikpXG4gICAgfVxuXG4gICAgdmFyIGQybCA9IGxrICsgZHNcbiAgICB2YXIgZDJoID0gaGsgKyBkc1xuXG4gICAgaWYoZDJsIDw9IHIyKSB7XG4gICAgICB2YXIgbGVmdCA9IDIgKiBpZHggKyAxXG4gICAgICBpZihsZWZ0IDwgbikge1xuICAgICAgICB2aXNpdEluZGV4W3Zpc2l0Q291bnRdID0gbGVmdFxuICAgICAgICB2YXIgeSA9IHZpc2l0RGlzdGFuY2UuaW5kZXgodmlzaXRDb3VudCwgMClcbiAgICAgICAgZm9yKHZhciBpPTA7IGk8ZDsgKytpKSB7XG4gICAgICAgICAgZGlzdGFuY2VEYXRhW3kraV0gPSBkaXN0YW5jZURhdGFbZGlkeCtpXVxuICAgICAgICB9XG4gICAgICAgIGRpc3RhbmNlRGF0YVt5K2tdID0gbGtcbiAgICAgICAgdmlzaXRDb3VudCArPSAxXG4gICAgICB9XG4gICAgfVxuICAgIGlmKGQyaCA8PSByMikge1xuICAgICAgdmFyIHJpZ2h0ID0gMiAqIChpZHggKyAxKVxuICAgICAgaWYocmlnaHQgPCBuKSB7XG4gICAgICAgIHZpc2l0SW5kZXhbdmlzaXRDb3VudF0gPSByaWdodFxuICAgICAgICB2YXIgeSA9IHZpc2l0RGlzdGFuY2UuaW5kZXgodmlzaXRDb3VudCwgMClcbiAgICAgICAgZm9yKHZhciBpPTA7IGk8ZDsgKytpKSB7XG4gICAgICAgICAgZGlzdGFuY2VEYXRhW3kraV0gPSBkaXN0YW5jZURhdGFbZGlkeCtpXVxuICAgICAgICB9XG4gICAgICAgIGRpc3RhbmNlRGF0YVt5K2tdID0gaGtcbiAgICAgICAgdmlzaXRDb3VudCArPSAxXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy9JbmNyZW1lbnQgcG9pbnRlclxuICAgIHZpc2l0VG9wICs9IDFcbiAgfVxuXG4gIG5kc2NyYXRjaC5mcmVlKHZpc2l0RGlzdGFuY2UpXG4gIHBvb2wuZnJlZSh2aXNpdEluZGV4KVxuICByZXR1cm4gcmV0dmFsXG59XG5cbnByb3RvLm5uID0gZnVuY3Rpb24ocG9pbnQsIG1heERpc3RhbmNlKSB7XG4gIHZhciBuID0gdGhpcy5sZW5ndGhcbiAgaWYobiA8IDEpIHtcbiAgICByZXR1cm4gLTFcbiAgfVxuICBpZih0eXBlb2YgbWF4RGlzdGFuY2UgPT09IFwibnVtYmVyXCIpIHtcbiAgICBpZihtYXhEaXN0YW5jZSA8IDApIHtcbiAgICAgIHJldHVybiAtMVxuICAgIH0gXG4gIH0gZWxzZSB7XG4gICAgbWF4RGlzdGFuY2UgPSBJbmZpbml0eVxuICB9XG4gIHZhciBkID0gdGhpcy5kaW1lbnNpb25cbiAgdmFyIHBvaW50cyA9IHRoaXMucG9pbnRzXG4gIHZhciBwb2ludERhdGEgPSBwb2ludHMuZGF0YVxuICB2YXIgZGF0YVZlY3RvciA9IHBvb2wubWFsbG9jRmxvYXQ2NChkKVxuXG4gIHZhciB0b1Zpc2l0ID0gbmV3IEtEVEhlYXAobiwgZCsxKVxuICB2YXIgaW5kZXggPSB0b1Zpc2l0LmluZGV4XG4gIHZhciBkYXRhID0gdG9WaXNpdC5kYXRhXG4gIGluZGV4WzBdID0gMFxuICBmb3IodmFyIGk9MDsgaTw9ZDsgKytpKSB7XG4gICAgZGF0YVtpXSA9IDBcbiAgfVxuICB0b1Zpc2l0LmNvdW50ICs9IDFcblxuICB2YXIgbmVhcmVzdCA9IC0xXG4gIHZhciBuZWFyZXN0RCA9IG1heERpc3RhbmNlXG5cbiAgd2hpbGUodG9WaXNpdC5jb3VudCA+IDApIHtcbiAgICBpZihkYXRhWzBdID49IG5lYXJlc3REKSB7XG4gICAgICBicmVha1xuICAgIH1cblxuICAgIHZhciBpZHggPSBpbmRleFswXVxuICAgIHZhciBwaWR4ID0gcG9pbnRzLmluZGV4KGlkeCwgMClcbiAgICB2YXIgZDIgPSAwLjBcbiAgICBmb3IodmFyIGk9MDsgaTxkOyArK2kpIHtcbiAgICAgIGQyICs9IE1hdGgucG93KHBvaW50W2ldLXBvaW50RGF0YVtwaWR4K2ldLCAyKVxuICAgIH1cbiAgICBpZihkMiA8IG5lYXJlc3REKSB7XG4gICAgICBuZWFyZXN0RCA9IGQyXG4gICAgICBuZWFyZXN0ID0gaWR4XG4gICAgfVxuXG4gICAgLy9Db21wdXRlIGRpc3RhbmNlIGJvdW5kcyBmb3IgY2hpbGRyZW5cbiAgICB2YXIgayA9IGJpdHMubG9nMihpZHgrMSklZFxuICAgIHZhciBkcyA9IDBcbiAgICBmb3IodmFyIGk9MDsgaTxkOyArK2kpIHtcbiAgICAgIHZhciBkZCA9IGRhdGFbaSsxXVxuICAgICAgaWYoaSAhPT0gaykge1xuICAgICAgICBkcyArPSBkZFxuICAgICAgfVxuICAgICAgZGF0YVZlY3RvcltpXSA9IGRkXG4gICAgfVxuICAgIHZhciBxayA9IHBvaW50W2tdXG4gICAgdmFyIHBrID0gcG9pbnREYXRhW3BpZHgra11cbiAgICB2YXIgZGsgPSBkYXRhVmVjdG9yW2tdXG4gICAgdmFyIGxrID0gZGtcbiAgICB2YXIgaGsgPSBka1xuICAgIGlmKHFrIDwgcGspIHtcbiAgICAgIGhrID0gTWF0aC5tYXgoZGssIE1hdGgucG93KHBrIC0gcWssIDIpKVxuICAgIH0gZWxzZSB7XG4gICAgICBsayA9IE1hdGgubWF4KGRrLCBNYXRoLnBvdyhwayAtIHFrLCAyKSlcbiAgICB9XG4gICAgdmFyIGQybCA9IGxrICsgZHNcbiAgICB2YXIgZDJoID0gaGsgKyBkc1xuXG4gICAgdG9WaXNpdC5wb3AoKVxuICAgIFxuICAgIGlmKGQybCA8IG5lYXJlc3REKSB7XG4gICAgICB2YXIgbGVmdCA9IDIgKiBpZHggKyAxXG4gICAgICBpZihsZWZ0IDwgbikge1xuICAgICAgICB2YXIgdmNvdW50ID0gdG9WaXNpdC5jb3VudFxuICAgICAgICBpbmRleFt2Y291bnRdID0gbGVmdFxuICAgICAgICB2YXIgdnB0ciA9IHZjb3VudCAqIChkKzEpXG4gICAgICAgIGRhdGFbdnB0cl0gPSBkMmxcbiAgICAgICAgZm9yKHZhciBpPTE7IGk8PWQ7ICsraSkge1xuICAgICAgICAgIGRhdGFbdnB0citpXSA9IGRhdGFWZWN0b3JbaS0xXVxuICAgICAgICB9XG4gICAgICAgIGRhdGFbdnB0citrKzFdID0gbGtcbiAgICAgICAgdG9WaXNpdC5wdXNoKClcbiAgICAgIH1cbiAgICB9XG4gICAgaWYoZDJoIDwgbmVhcmVzdEQpIHtcbiAgICAgIHZhciByaWdodCA9IDIgKiAoaWR4ICsgMSlcbiAgICAgIGlmKHJpZ2h0IDwgbikge1xuICAgICAgICB2YXIgdmNvdW50ID0gdG9WaXNpdC5jb3VudFxuICAgICAgICBpbmRleFt2Y291bnRdID0gcmlnaHRcbiAgICAgICAgdmFyIHZwdHIgPSB2Y291bnQgKiAoZCsxKVxuICAgICAgICBkYXRhW3ZwdHJdID0gZDJoXG4gICAgICAgIGZvcih2YXIgaT0xOyBpPD1kOyArK2kpIHtcbiAgICAgICAgICBkYXRhW3ZwdHIraV0gPSBkYXRhVmVjdG9yW2ktMV1cbiAgICAgICAgfVxuICAgICAgICBkYXRhW3ZwdHIraysxXSA9IGhrXG4gICAgICAgIHRvVmlzaXQucHVzaCgpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcG9vbC5mcmVlRmxvYXQ2NChkYXRhVmVjdG9yKVxuICB0b1Zpc2l0LmRpc3Bvc2UoKVxuICBcbiAgaWYobmVhcmVzdCA8IDApIHtcbiAgICByZXR1cm4gLTFcbiAgfVxuICByZXR1cm4gdGhpcy5pZHNbbmVhcmVzdF1cbn1cblxucHJvdG8ua25uID0gZnVuY3Rpb24ocG9pbnQsIG1heFBvaW50cywgbWF4RGlzdGFuY2UpIHtcbiAgLy9DaGVjayBkZWdlbmVyYXRlIGNhc2VzXG4gIGlmKHR5cGVvZiBtYXhEaXN0YW5jZSA9PT0gXCJudW1iZXJcIikge1xuICAgIGlmKG1heERpc3RhbmNlIDwgMCkge1xuICAgICAgcmV0dXJuIFtdXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIG1heERpc3RhbmNlID0gSW5maW5pdHlcbiAgfVxuICB2YXIgbiA9IHRoaXMubGVuZ3RoXG4gIGlmKG4gPCAxKSB7XG4gICAgcmV0dXJuIFtdXG4gIH1cbiAgaWYodHlwZW9mIG1heFBvaW50cyA9PT0gXCJudW1iZXJcIikge1xuICAgIGlmKG1heFBvaW50cyA8PSAwKSB7XG4gICAgICByZXR1cm4gW11cbiAgICB9XG4gICAgbWF4UG9pbnRzID0gTWF0aC5taW4obWF4UG9pbnRzLCBuKXwwXG4gIH0gZWxzZSB7XG4gICAgbWF4UG9pbnRzID0gblxuICB9XG4gIHZhciBpZHMgPSB0aGlzLmlkc1xuXG4gIHZhciBkID0gdGhpcy5kaW1lbnNpb25cbiAgdmFyIHBvaW50cyA9IHRoaXMucG9pbnRzXG4gIHZhciBwb2ludERhdGEgPSBwb2ludHMuZGF0YVxuICB2YXIgZGF0YVZlY3RvciA9IHBvb2wubWFsbG9jRmxvYXQ2NChkKVxuICBcbiAgLy9MaXN0IG9mIGNsb3Nlc3QgcG9pbnRzXG4gIHZhciBjbG9zZXN0UG9pbnRzID0gbmV3IEtEVEhlYXAobWF4UG9pbnRzLCAxKVxuICB2YXIgY2xfaW5kZXggPSBjbG9zZXN0UG9pbnRzLmluZGV4XG4gIHZhciBjbF9kYXRhID0gY2xvc2VzdFBvaW50cy5kYXRhXG5cbiAgdmFyIHRvVmlzaXQgPSBuZXcgS0RUSGVhcChuLCBkKzEpXG4gIHZhciBpbmRleCA9IHRvVmlzaXQuaW5kZXhcbiAgdmFyIGRhdGEgPSB0b1Zpc2l0LmRhdGFcbiAgaW5kZXhbMF0gPSAwXG4gIGZvcih2YXIgaT0wOyBpPD1kOyArK2kpIHtcbiAgICBkYXRhW2ldID0gMFxuICB9XG4gIHRvVmlzaXQuY291bnQgKz0gMVxuXG4gIHZhciBuZWFyZXN0ID0gLTFcbiAgdmFyIG5lYXJlc3REID0gbWF4RGlzdGFuY2VcblxuICB3aGlsZSh0b1Zpc2l0LmNvdW50ID4gMCkge1xuICAgIGlmKGRhdGFbMF0gPj0gbmVhcmVzdEQpIHtcbiAgICAgIGJyZWFrXG4gICAgfVxuXG4gICAgdmFyIGlkeCA9IGluZGV4WzBdXG4gICAgdmFyIHBpZHggPSBwb2ludHMuaW5kZXgoaWR4LCAwKVxuICAgIHZhciBkMiA9IDAuMFxuICAgIGZvcih2YXIgaT0wOyBpPGQ7ICsraSkge1xuICAgICAgZDIgKz0gTWF0aC5wb3cocG9pbnRbaV0tcG9pbnREYXRhW3BpZHgraV0sIDIpXG4gICAgfVxuICAgIGlmKGQyIDwgbmVhcmVzdEQpIHtcbiAgICAgIGlmKGNsb3Nlc3RQb2ludHMuY291bnQgPj0gbWF4UG9pbnRzKSB7XG4gICAgICAgIGNsb3Nlc3RQb2ludHMucG9wKClcbiAgICAgIH1cbiAgICAgIHZhciBwY291bnQgPSBjbG9zZXN0UG9pbnRzLmNvdW50XG4gICAgICBjbF9pbmRleFtwY291bnRdID0gaWR4XG4gICAgICBjbF9kYXRhW3Bjb3VudF0gPSAtZDJcbiAgICAgIGNsb3Nlc3RQb2ludHMucHVzaCgpXG4gICAgICBpZihjbG9zZXN0UG9pbnRzLmNvdW50ID49IG1heFBvaW50cykge1xuICAgICAgICBuZWFyZXN0RCA9IC1jbF9kYXRhWzBdXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy9Db21wdXRlIGRpc3RhbmNlIGJvdW5kcyBmb3IgY2hpbGRyZW5cbiAgICB2YXIgayA9IGJpdHMubG9nMihpZHgrMSklZFxuICAgIHZhciBkcyA9IDBcbiAgICBmb3IodmFyIGk9MDsgaTxkOyArK2kpIHtcbiAgICAgIHZhciBkZCA9IGRhdGFbaSsxXVxuICAgICAgaWYoaSAhPT0gaykge1xuICAgICAgICBkcyArPSBkZFxuICAgICAgfVxuICAgICAgZGF0YVZlY3RvcltpXSA9IGRkXG4gICAgfVxuICAgIHZhciBxayA9IHBvaW50W2tdXG4gICAgdmFyIHBrID0gcG9pbnREYXRhW3BpZHgra11cbiAgICB2YXIgZGsgPSBkYXRhVmVjdG9yW2tdXG4gICAgdmFyIGxrID0gZGtcbiAgICB2YXIgaGsgPSBka1xuICAgIGlmKHFrIDwgcGspIHtcbiAgICAgIGhrID0gTWF0aC5tYXgoZGssIE1hdGgucG93KHBrIC0gcWssIDIpKVxuICAgIH0gZWxzZSB7XG4gICAgICBsayA9IE1hdGgubWF4KGRrLCBNYXRoLnBvdyhwayAtIHFrLCAyKSlcbiAgICB9XG4gICAgdmFyIGQybCA9IGxrICsgZHNcbiAgICB2YXIgZDJoID0gaGsgKyBkc1xuXG4gICAgdG9WaXNpdC5wb3AoKVxuICAgIGlmKGQybCA8IG5lYXJlc3REKSB7XG4gICAgICB2YXIgbGVmdCA9IDIgKiBpZHggKyAxXG4gICAgICBpZihsZWZ0IDwgbikge1xuICAgICAgICB2YXIgdmNvdW50ID0gdG9WaXNpdC5jb3VudFxuICAgICAgICBpbmRleFt2Y291bnRdID0gbGVmdFxuICAgICAgICB2YXIgdnB0ciA9IHZjb3VudCAqIChkKzEpXG4gICAgICAgIGRhdGFbdnB0cl0gPSBkMmxcbiAgICAgICAgZm9yKHZhciBpPTE7IGk8PWQ7ICsraSkge1xuICAgICAgICAgIGRhdGFbdnB0citpXSA9IGRhdGFWZWN0b3JbaS0xXVxuICAgICAgICB9XG4gICAgICAgIGRhdGFbdnB0citrKzFdID0gbGtcbiAgICAgICAgdG9WaXNpdC5wdXNoKClcbiAgICAgIH1cbiAgICB9XG4gICAgaWYoZDJoIDwgbmVhcmVzdEQpIHtcbiAgICAgIHZhciByaWdodCA9IDIgKiAoaWR4ICsgMSlcbiAgICAgIGlmKHJpZ2h0IDwgbikge1xuICAgICAgICB2YXIgdmNvdW50ID0gdG9WaXNpdC5jb3VudFxuICAgICAgICBpbmRleFt2Y291bnRdID0gcmlnaHRcbiAgICAgICAgdmFyIHZwdHIgPSB2Y291bnQgKiAoZCsxKVxuICAgICAgICBkYXRhW3ZwdHJdID0gZDJoXG4gICAgICAgIGZvcih2YXIgaT0xOyBpPD1kOyArK2kpIHtcbiAgICAgICAgICBkYXRhW3ZwdHIraV0gPSBkYXRhVmVjdG9yW2ktMV1cbiAgICAgICAgfVxuICAgICAgICBkYXRhW3ZwdHIraysxXSA9IGhrXG4gICAgICAgIHRvVmlzaXQucHVzaCgpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcG9vbC5mcmVlRmxvYXQ2NChkYXRhVmVjdG9yKVxuICB0b1Zpc2l0LmRpc3Bvc2UoKVxuXG4gIC8vU29ydCByZXN1bHRcbiAgdmFyIHJlc3VsdCA9IG5ldyBBcnJheShjbG9zZXN0UG9pbnRzLmNvdW50KVxuICB2YXIgaWRzID0gdGhpcy5pZHNcbiAgZm9yKHZhciBpPWNsb3Nlc3RQb2ludHMuY291bnQtMTsgaT49MDsgLS1pKSB7XG4gICAgcmVzdWx0W2ldID0gaWRzW2NsX2luZGV4WzBdXVxuICAgIGNsb3Nlc3RQb2ludHMucG9wKClcbiAgfVxuICBjbG9zZXN0UG9pbnRzLmRpc3Bvc2UoKVxuXG4gIHJldHVybiByZXN1bHRcbn1cblxucHJvdG8uZGlzcG9zZSA9IGZ1bmN0aW9uIGtkdERpc3Bvc2UoKSB7XG4gIHBvb2wuZnJlZSh0aGlzLnBvaW50cy5kYXRhKVxuICBwb29sLmZyZWVJbnQzMih0aGlzLmlkcylcbiAgdGhpcy5wb2ludHMgPSBudWxsXG4gIHRoaXMuaWRzID0gbnVsbFxuICB0aGlzLmxlbmd0aCA9IDBcbn1cblxuZnVuY3Rpb24gY3JlYXRlS0RUcmVlKHBvaW50cykge1xuICB2YXIgbiwgZCwgaW5kZXhlZFxuICBpZihBcnJheS5pc0FycmF5KHBvaW50cykpIHtcbiAgICBuID0gcG9pbnRzLmxlbmd0aFxuICAgIGlmKG4gPT09IDApIHtcbiAgICAgIHJldHVybiBuZXcgS0RUcmVlKG51bGwsIG51bGwsIDAsIDApXG4gICAgfVxuICAgIGQgPSBwb2ludHNbMF0ubGVuZ3RoXG4gICAgaW5kZXhlZCA9IG5kYXJyYXkocG9vbC5tYWxsb2NEb3VibGUobiooZCsxKSksIFtuLCBkKzFdKVxuICAgIHBhY2socG9pbnRzLCBpbmRleGVkLmhpKG4sIGQpKVxuICB9IGVsc2Uge1xuICAgIG4gPSBwb2ludHMuc2hhcGVbMF1cbiAgICBkID0gcG9pbnRzLnNoYXBlWzFdXG5cbiAgICAvL1JvdW5kIHVwIGRhdGEgdHlwZSBzaXplXG4gICAgdmFyIHR5cGUgPSBwb2ludHMuZHR5cGVcbiAgICBpZih0eXBlID09PSBcImludDhcIiB8fFxuICAgICAgIHR5cGUgPT09IFwiaW50MTZcIiB8fFxuICAgICAgIHR5cGUgPT09IFwiaW50MzJcIiApIHtcbiAgICAgIHR5cGUgPSBcImludDMyXCJcbiAgICB9IGVsc2UgaWYodHlwZSA9PT0gXCJ1aW50OFwiIHx8XG4gICAgICB0eXBlID09PSBcInVpbnQ4X2NsYW1wZWRcIiB8fFxuICAgICAgdHlwZSA9PT0gXCJidWZmZXJcIiB8fFxuICAgICAgdHlwZSA9PT0gXCJ1aW50MTZcIiB8fFxuICAgICAgdHlwZSA9PT0gXCJ1aW50MzJcIikge1xuICAgICAgdHlwZSA9IFwidWludDMyXCJcbiAgICB9IGVsc2UgaWYodHlwZSA9PT0gXCJmbG9hdDMyXCIpIHtcbiAgICAgIHR5cGUgPSBcImZsb2F0MzJcIlxuICAgIH0gZWxzZSB7XG4gICAgICB0eXBlID0gXCJmbG9hdDY0XCJcbiAgICB9XG4gICAgaW5kZXhlZCA9IG5kYXJyYXkocG9vbC5tYWxsb2MobiooZCsxKSksIFtuLCBkKzFdKVxuICAgIG9wcy5hc3NpZ24oaW5kZXhlZC5oaShuLGQpLCBwb2ludHMpXG4gIH1cbiAgZm9yKHZhciBpPTA7IGk8bjsgKytpKSB7XG4gICAgaW5kZXhlZC5zZXQoaSwgZCwgaSlcbiAgfVxuXG4gIHZhciBwb2ludEFycmF5ID0gbmRzY3JhdGNoLm1hbGxvYyhbbiwgZF0sIHBvaW50cy5kdHlwZSlcbiAgdmFyIGluZGV4QXJyYXkgPSBwb29sLm1hbGxvY0ludDMyKG4pXG4gIHZhciBwb2ludGVyID0gMFxuICB2YXIgcG9pbnREYXRhID0gcG9pbnRBcnJheS5kYXRhXG4gIHZhciBhcnJheURhdGEgPSBpbmRleGVkLmRhdGFcbiAgdmFyIGwyX24gPSBiaXRzLmxvZzIoYml0cy5uZXh0UG93MihuKSlcblxuICB2YXIgc2VsX2NtcCA9IG5kc2VsZWN0LmNvbXBpbGUoaW5kZXhlZC5vcmRlciwgdHJ1ZSwgaW5kZXhlZC5kdHlwZSlcblxuICAvL1dhbGsgdHJlZSBpbiBsZXZlbCBvcmRlclxuICB2YXIgdG9WaXNpdCA9IFtpbmRleGVkXVxuICB3aGlsZShwb2ludGVyIDwgbikge1xuICAgIHZhciBoZWFkID0gdG9WaXNpdC5zaGlmdCgpXG4gICAgdmFyIGFycmF5ID0gaGVhZFxuICAgIHZhciBubiA9IGFycmF5LnNoYXBlWzBdfDBcbiAgICBcbiAgICAvL0ZpbmQgbWVkaWFuXG4gICAgaWYobm4gPiAxKSB7XG4gICAgICB2YXIgayA9IGJpdHMubG9nMihwb2ludGVyKzEpJWRcbiAgICAgIHZhciBtZWRpYW5cbiAgICAgIHZhciBuXzIgPSBpbm9yZGVyVHJlZS5yb290KG5uKVxuICAgICAgbWVkaWFuID0gc2VsX2NtcChhcnJheSwgbl8yLCBmdW5jdGlvbihhLGIpIHtcbiAgICAgICAgcmV0dXJuIGEuZ2V0KGspIC0gYi5nZXQoaylcbiAgICAgIH0pXG5cbiAgICAgIC8vQ29weSBpbnRvIG5ldyBhcnJheVxuICAgICAgdmFyIHBwdHIgPSBwb2ludEFycmF5LmluZGV4KHBvaW50ZXIsIDApXG4gICAgICB2YXIgbXB0ciA9IG1lZGlhbi5vZmZzZXRcbiAgICAgIGZvcih2YXIgaT0wOyBpPGQ7ICsraSkge1xuICAgICAgICBwb2ludERhdGFbcHB0cisrXSA9IGFycmF5RGF0YVttcHRyKytdXG4gICAgICB9XG4gICAgICBpbmRleEFycmF5W3BvaW50ZXJdID0gYXJyYXlEYXRhW21wdHJdXG4gICAgICBwb2ludGVyICs9IDFcblxuICAgICAgLy9RdWV1ZSBuZXcgaXRlbXNcbiAgICAgIHRvVmlzaXQucHVzaChhcnJheS5oaShuXzIpKVxuICAgICAgaWYobm4gPiAyKSB7XG4gICAgICAgIHRvVmlzaXQucHVzaChhcnJheS5sbyhuXzIrMSkpXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vQ29weSBpbnRvIG5ldyBhcnJheVxuICAgICAgdmFyIG1wdHIgPSBhcnJheS5vZmZzZXRcbiAgICAgIHZhciBwcHRyID0gcG9pbnRBcnJheS5pbmRleChwb2ludGVyLCAwKVxuICAgICAgZm9yKHZhciBpPTA7IGk8ZDsgKytpKSB7XG4gICAgICAgIHBvaW50RGF0YVtwcHRyK2ldID0gYXJyYXlEYXRhW21wdHIrK11cbiAgICAgIH1cbiAgICAgIGluZGV4QXJyYXlbcG9pbnRlcl0gPSBhcnJheURhdGFbbXB0cl1cbiAgICAgIHBvaW50ZXIgKz0gMVxuICAgIH1cbiAgfVxuXG4gIC8vUmVsZWFzZSBpbmRleGVkXG4gIHBvb2wuZnJlZShpbmRleGVkLmRhdGEpXG5cbiAgcmV0dXJuIG5ldyBLRFRyZWUocG9pbnRBcnJheSwgaW5kZXhBcnJheSwgbiwgZClcbn1cblxuZnVuY3Rpb24gZGVzZXJpYWxpemVLRFRyZWUoZGF0YSkge1xuICB2YXIgcG9pbnRzID0gZGF0YS5wXG4gIHZhciBpZHMgPSBkYXRhLmlcbiAgaWYocG9pbnRzKSB7XG4gICAgdmFyIG5kID0gcG9pbnRzLmxlbmd0aFxuICAgIHZhciBwb2ludEFycmF5ID0gcG9vbC5tYWxsb2NGbG9hdDY0KG5kKVxuICAgIGZvcih2YXIgaT0wOyBpPG5kOyArK2kpIHtcbiAgICAgIHBvaW50QXJyYXlbaV0gPSBwb2ludHNbaV1cbiAgICB9XG4gICAgdmFyIG4gPSBpZHMubGVuZ3RoXG4gICAgdmFyIGlkQXJyYXkgPSBwb29sLm1hbGxvY0ludDMyKG4pXG4gICAgZm9yKHZhciBpPTA7IGk8bjsgKytpKSB7XG4gICAgICBpZEFycmF5W2ldID0gaWRzW2ldXG4gICAgfVxuICAgIHZhciBkID0gKG5kL24pfDBcbiAgICByZXR1cm4gbmV3IEtEVHJlZShcbiAgICAgIG5kYXJyYXkocG9pbnRBcnJheSwgW24sZF0pLFxuICAgICAgaWRBcnJheSxcbiAgICAgIG4sXG4gICAgICBkKVxuICB9IGVsc2Uge1xuICAgIHJldHVybiBuZXcgS0RUcmVlKG51bGwsIG51bGwsIDAsIGRhdGEuZClcbiAgfVxufSJdfQ== | |
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"resl":[function(require,module,exports){ | |
/* global XMLHttpRequest */ | |
var configParameters = [ | |
'manifest', | |
'onDone', | |
'onProgress', | |
'onError' | |
] | |
var manifestParameters = [ | |
'type', | |
'src', | |
'stream', | |
'credentials', | |
'parser' | |
] | |
var parserParameters = [ | |
'onData', | |
'onDone' | |
] | |
var STATE_ERROR = -1 | |
var STATE_DATA = 0 | |
var STATE_COMPLETE = 1 | |
function raise (message) { | |
throw new Error('resl: ' + message) | |
} | |
function checkType (object, parameters, name) { | |
Object.keys(object).forEach(function (param) { | |
if (parameters.indexOf(param) < 0) { | |
raise('invalid parameter "' + param + '" in ' + name) | |
} | |
}) | |
} | |
function Loader (name, cancel) { | |
this.state = STATE_DATA | |
this.ready = false | |
this.progress = 0 | |
this.name = name | |
this.cancel = cancel | |
} | |
module.exports = function resl (config) { | |
if (typeof config !== 'object' || !config) { | |
raise('invalid or missing configuration') | |
} | |
checkType(config, configParameters, 'config') | |
var manifest = config.manifest | |
if (typeof manifest !== 'object' || !manifest) { | |
raise('missing manifest') | |
} | |
function getFunction (name, dflt) { | |
if (name in config) { | |
var func = config[name] | |
if (typeof func !== 'function') { | |
raise('invalid callback "' + name + '"') | |
} | |
return func | |
} | |
return null | |
} | |
var onDone = getFunction('onDone') | |
if (!onDone) { | |
raise('missing onDone() callback') | |
} | |
var onProgress = getFunction('onProgress') | |
var onError = getFunction('onError') | |
var assets = {} | |
var state = STATE_DATA | |
function loadXHR (request) { | |
var name = request.name | |
var stream = request.stream | |
var binary = request.type === 'binary' | |
var parser = request.parser | |
var xhr = new XMLHttpRequest() | |
var asset = null | |
var loader = new Loader(name, cancel) | |
if (stream) { | |
xhr.onreadystatechange = onReadyStateChange | |
} else { | |
xhr.onreadystatechange = function () { | |
if (xhr.readyState === 4) { | |
onReadyStateChange() | |
} | |
} | |
} | |
if (binary) { | |
xhr.responseType = 'arraybuffer' | |
} | |
function onReadyStateChange () { | |
if (xhr.readyState < 2 || | |
loader.state === STATE_COMPLETE || | |
loader.state === STATE_ERROR) { | |
return | |
} | |
if (xhr.status !== 200) { | |
return abort('error loading resource "' + request.name + '"') | |
} | |
if (xhr.readyState > 2 && loader.state === STATE_DATA) { | |
var response | |
if (request.type === 'binary') { | |
response = xhr.response | |
} else { | |
response = xhr.responseText | |
} | |
if (parser.data) { | |
try { | |
asset = parser.data(response) | |
} catch (e) { | |
return abort(e) | |
} | |
} else { | |
asset = response | |
} | |
} | |
if (xhr.readyState > 3 && loader.state === STATE_DATA) { | |
if (parser.done) { | |
try { | |
asset = parser.done() | |
} catch (e) { | |
return abort(e) | |
} | |
} | |
loader.state = STATE_COMPLETE | |
} | |
assets[name] = asset | |
loader.progress = 0.75 * loader.progress + 0.25 | |
loader.ready = | |
(request.stream && !!asset) || | |
loader.state === STATE_COMPLETE | |
notifyProgress() | |
} | |
function cancel () { | |
if (loader.state === STATE_COMPLETE || loader.state === STATE_ERROR) { | |
return | |
} | |
xhr.onreadystatechange = null | |
xhr.abort() | |
loader.state = STATE_ERROR | |
} | |
// set up request | |
if (request.credentials) { | |
xhr.withCredentials = true | |
} | |
xhr.open('GET', request.src, true) | |
xhr.send() | |
return loader | |
} | |
function loadElement (request, element) { | |
var name = request.name | |
var parser = request.parser | |
var loader = new Loader(name, cancel) | |
var asset = element | |
function handleProgress () { | |
if (loader.state === STATE_DATA) { | |
if (parser.data) { | |
try { | |
asset = parser.data(element) | |
} catch (e) { | |
return abort(e) | |
} | |
} else { | |
asset = element | |
} | |
} | |
} | |
function onProgress (e) { | |
handleProgress() | |
assets[name] = asset | |
if (e.lengthComputable) { | |
loader.progress = Math.max(loader.progress, e.loaded / e.total) | |
} else { | |
loader.progress = 0.75 * loader.progress + 0.25 | |
} | |
loader.ready = request.stream | |
notifyProgress(name) | |
} | |
function onComplete () { | |
handleProgress() | |
if (loader.state === STATE_DATA) { | |
if (parser.done) { | |
try { | |
asset = parser.done() | |
} catch (e) { | |
return abort(e) | |
} | |
} | |
loader.state = STATE_COMPLETE | |
} | |
loader.progress = 1 | |
loader.ready = true | |
assets[name] = asset | |
removeListeners() | |
notifyProgress('finish ' + name) | |
} | |
function onError () { | |
abort('error loading asset "' + name + '"') | |
} | |
if (request.stream) { | |
element.addEventListener('progress', onProgress) | |
} | |
if (request.type === 'image') { | |
element.addEventListener('load', onComplete) | |
} else { | |
var canPlay = false | |
var loadedMetaData = false | |
element.addEventListener('loadedmetadata', function () { | |
loadedMetaData = true | |
if (canPlay) { | |
onComplete() | |
} | |
}) | |
element.addEventListener('canplay', function () { | |
canPlay = true | |
if (loadedMetaData) { | |
onComplete() | |
} | |
}) | |
} | |
element.addEventListener('error', onError) | |
function removeListeners () { | |
if (request.stream) { | |
element.removeEventListener('progress', onProgress) | |
} | |
if (request.type === 'image') { | |
element.addEventListener('load', onComplete) | |
} else { | |
element.addEventListener('canplay', onComplete) | |
} | |
element.removeEventListener('error', onError) | |
} | |
function cancel () { | |
if (loader.state === STATE_COMPLETE || loader.state === STATE_ERROR) { | |
return | |
} | |
loader.state = STATE_ERROR | |
removeListeners() | |
element.src = '' | |
} | |
// set up request | |
if (request.credentials) { | |
element.crossOrigin = 'use-credentials' | |
} else { | |
element.crossOrigin = 'anonymous' | |
} | |
element.src = request.src | |
return loader | |
} | |
var loaders = { | |
text: loadXHR, | |
binary: function (request) { | |
// TODO use fetch API for streaming if supported | |
return loadXHR(request) | |
}, | |
image: function (request) { | |
return loadElement(request, document.createElement('img')) | |
}, | |
video: function (request) { | |
return loadElement(request, document.createElement('video')) | |
}, | |
audio: function (request) { | |
return loadElement(request, document.createElement('audio')) | |
} | |
} | |
// First we parse all objects in order to verify that all type information | |
// is correct | |
var pending = Object.keys(manifest).map(function (name) { | |
var request = manifest[name] | |
if (typeof request === 'string') { | |
request = { | |
src: request | |
} | |
} else if (typeof request !== 'object' || !request) { | |
raise('invalid asset definition "' + name + '"') | |
} | |
checkType(request, manifestParameters, 'asset "' + name + '"') | |
function getParameter (prop, accepted, init) { | |
var value = init | |
if (prop in request) { | |
value = request[prop] | |
} | |
if (accepted.indexOf(value) < 0) { | |
raise('invalid ' + prop + ' "' + value + '" for asset "' + name + '", possible values: ' + accepted) | |
} | |
return value | |
} | |
function getString (prop, required, init) { | |
var value = init | |
if (prop in request) { | |
value = request[prop] | |
} else if (required) { | |
raise('missing ' + prop + ' for asset "' + name + '"') | |
} | |
if (typeof value !== 'string') { | |
raise('invalid ' + prop + ' for asset "' + name + '", must be a string') | |
} | |
return value | |
} | |
function getParseFunc (name, dflt) { | |
if (name in request.parser) { | |
var result = request.parser[name] | |
if (typeof result !== 'function') { | |
raise('invalid parser callback ' + name + ' for asset "' + name + '"') | |
} | |
return result | |
} else { | |
return dflt | |
} | |
} | |
var parser = {} | |
if ('parser' in request) { | |
if (typeof request.parser === 'function') { | |
parser = { | |
data: request.parser | |
} | |
} else if (typeof request.parser === 'object' && request.parser) { | |
checkType(parser, parserParameters, 'parser for asset "' + name + '"') | |
if (!('onData' in parser)) { | |
raise('missing onData callback for parser in asset "' + name + '"') | |
} | |
parser = { | |
data: getParseFunc('onData'), | |
done: getParseFunc('onDone') | |
} | |
} else { | |
raise('invalid parser for asset "' + name + '"') | |
} | |
} | |
return { | |
name: name, | |
type: getParameter('type', Object.keys(loaders), 'text'), | |
stream: !!request.stream, | |
credentials: !!request.credentials, | |
src: getString('src', true, ''), | |
parser: parser | |
} | |
}).map(function (request) { | |
return (loaders[request.type])(request) | |
}) | |
function abort (message) { | |
if (state === STATE_ERROR || state === STATE_COMPLETE) { | |
return | |
} | |
state = STATE_ERROR | |
pending.forEach(function (loader) { | |
loader.cancel() | |
}) | |
if (onError) { | |
if (typeof message === 'string') { | |
onError(new Error('resl: ' + message)) | |
} else { | |
onError(message) | |
} | |
} else { | |
console.error('resl error:', message) | |
} | |
} | |
function notifyProgress (message) { | |
if (state === STATE_ERROR || state === STATE_COMPLETE) { | |
return | |
} | |
var progress = 0 | |
var numReady = 0 | |
pending.forEach(function (loader) { | |
if (loader.ready) { | |
numReady += 1 | |
} | |
progress += loader.progress | |
}) | |
if (numReady === pending.length) { | |
state = STATE_COMPLETE | |
onDone(assets) | |
} else { | |
if (onProgress) { | |
onProgress(progress / pending.length, message) | |
} | |
} | |
} | |
} | |
},{}]},{},[]) | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImluZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIvKiBnbG9iYWwgWE1MSHR0cFJlcXVlc3QgKi9cbnZhciBjb25maWdQYXJhbWV0ZXJzID0gW1xuICAnbWFuaWZlc3QnLFxuICAnb25Eb25lJyxcbiAgJ29uUHJvZ3Jlc3MnLFxuICAnb25FcnJvcidcbl1cblxudmFyIG1hbmlmZXN0UGFyYW1ldGVycyA9IFtcbiAgJ3R5cGUnLFxuICAnc3JjJyxcbiAgJ3N0cmVhbScsXG4gICdjcmVkZW50aWFscycsXG4gICdwYXJzZXInXG5dXG5cbnZhciBwYXJzZXJQYXJhbWV0ZXJzID0gW1xuICAnb25EYXRhJyxcbiAgJ29uRG9uZSdcbl1cblxudmFyIFNUQVRFX0VSUk9SID0gLTFcbnZhciBTVEFURV9EQVRBID0gMFxudmFyIFNUQVRFX0NPTVBMRVRFID0gMVxuXG5mdW5jdGlvbiByYWlzZSAobWVzc2FnZSkge1xuICB0aHJvdyBuZXcgRXJyb3IoJ3Jlc2w6ICcgKyBtZXNzYWdlKVxufVxuXG5mdW5jdGlvbiBjaGVja1R5cGUgKG9iamVjdCwgcGFyYW1ldGVycywgbmFtZSkge1xuICBPYmplY3Qua2V5cyhvYmplY3QpLmZvckVhY2goZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgaWYgKHBhcmFtZXRlcnMuaW5kZXhPZihwYXJhbSkgPCAwKSB7XG4gICAgICByYWlzZSgnaW52YWxpZCBwYXJhbWV0ZXIgXCInICsgcGFyYW0gKyAnXCIgaW4gJyArIG5hbWUpXG4gICAgfVxuICB9KVxufVxuXG5mdW5jdGlvbiBMb2FkZXIgKG5hbWUsIGNhbmNlbCkge1xuICB0aGlzLnN0YXRlID0gU1RBVEVfREFUQVxuICB0aGlzLnJlYWR5ID0gZmFsc2VcbiAgdGhpcy5wcm9ncmVzcyA9IDBcbiAgdGhpcy5uYW1lID0gbmFtZVxuICB0aGlzLmNhbmNlbCA9IGNhbmNlbFxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHJlc2wgKGNvbmZpZykge1xuICBpZiAodHlwZW9mIGNvbmZpZyAhPT0gJ29iamVjdCcgfHwgIWNvbmZpZykge1xuICAgIHJhaXNlKCdpbnZhbGlkIG9yIG1pc3NpbmcgY29uZmlndXJhdGlvbicpXG4gIH1cblxuICBjaGVja1R5cGUoY29uZmlnLCBjb25maWdQYXJhbWV0ZXJzLCAnY29uZmlnJylcblxuICB2YXIgbWFuaWZlc3QgPSBjb25maWcubWFuaWZlc3RcbiAgaWYgKHR5cGVvZiBtYW5pZmVzdCAhPT0gJ29iamVjdCcgfHwgIW1hbmlmZXN0KSB7XG4gICAgcmFpc2UoJ21pc3NpbmcgbWFuaWZlc3QnKVxuICB9XG5cbiAgZnVuY3Rpb24gZ2V0RnVuY3Rpb24gKG5hbWUsIGRmbHQpIHtcbiAgICBpZiAobmFtZSBpbiBjb25maWcpIHtcbiAgICAgIHZhciBmdW5jID0gY29uZmlnW25hbWVdXG4gICAgICBpZiAodHlwZW9mIGZ1bmMgIT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgcmFpc2UoJ2ludmFsaWQgY2FsbGJhY2sgXCInICsgbmFtZSArICdcIicpXG4gICAgICB9XG4gICAgICByZXR1cm4gZnVuY1xuICAgIH1cbiAgICByZXR1cm4gbnVsbFxuICB9XG5cbiAgdmFyIG9uRG9uZSA9IGdldEZ1bmN0aW9uKCdvbkRvbmUnKVxuICBpZiAoIW9uRG9uZSkge1xuICAgIHJhaXNlKCdtaXNzaW5nIG9uRG9uZSgpIGNhbGxiYWNrJylcbiAgfVxuXG4gIHZhciBvblByb2dyZXNzID0gZ2V0RnVuY3Rpb24oJ29uUHJvZ3Jlc3MnKVxuICB2YXIgb25FcnJvciA9IGdldEZ1bmN0aW9uKCdvbkVycm9yJylcblxuICB2YXIgYXNzZXRzID0ge31cblxuICB2YXIgc3RhdGUgPSBTVEFURV9EQVRBXG5cbiAgZnVuY3Rpb24gbG9hZFhIUiAocmVxdWVzdCkge1xuICAgIHZhciBuYW1lID0gcmVxdWVzdC5uYW1lXG4gICAgdmFyIHN0cmVhbSA9IHJlcXVlc3Quc3RyZWFtXG4gICAgdmFyIGJpbmFyeSA9IHJlcXVlc3QudHlwZSA9PT0gJ2JpbmFyeSdcbiAgICB2YXIgcGFyc2VyID0gcmVxdWVzdC5wYXJzZXJcblxuICAgIHZhciB4aHIgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKVxuICAgIHZhciBhc3NldCA9IG51bGxcblxuICAgIHZhciBsb2FkZXIgPSBuZXcgTG9hZGVyKG5hbWUsIGNhbmNlbClcblxuICAgIGlmIChzdHJlYW0pIHtcbiAgICAgIHhoci5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBvblJlYWR5U3RhdGVDaGFuZ2VcbiAgICB9IGVsc2Uge1xuICAgICAgeGhyLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHhoci5yZWFkeVN0YXRlID09PSA0KSB7XG4gICAgICAgICAgb25SZWFkeVN0YXRlQ2hhbmdlKClcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChiaW5hcnkpIHtcbiAgICAgIHhoci5yZXNwb25zZVR5cGUgPSAnYXJyYXlidWZmZXInXG4gICAgfVxuXG4gICAgZnVuY3Rpb24gb25SZWFkeVN0YXRlQ2hhbmdlICgpIHtcbiAgICAgIGlmICh4aHIucmVhZHlTdGF0ZSA8IDIgfHxcbiAgICAgICAgICBsb2FkZXIuc3RhdGUgPT09IFNUQVRFX0NPTVBMRVRFIHx8XG4gICAgICAgICAgbG9hZGVyLnN0YXRlID09PSBTVEFURV9FUlJPUikge1xuICAgICAgICByZXR1cm5cbiAgICAgIH1cbiAgICAgIGlmICh4aHIuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgICAgcmV0dXJuIGFib3J0KCdlcnJvciBsb2FkaW5nIHJlc291cmNlIFwiJyArIHJlcXVlc3QubmFtZSArICdcIicpXG4gICAgICB9XG4gICAgICBpZiAoeGhyLnJlYWR5U3RhdGUgPiAyICYmIGxvYWRlci5zdGF0ZSA9PT0gU1RBVEVfREFUQSkge1xuICAgICAgICB2YXIgcmVzcG9uc2VcbiAgICAgICAgaWYgKHJlcXVlc3QudHlwZSA9PT0gJ2JpbmFyeScpIHtcbiAgICAgICAgICByZXNwb25zZSA9IHhoci5yZXNwb25zZVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJlc3BvbnNlID0geGhyLnJlc3BvbnNlVGV4dFxuICAgICAgICB9XG4gICAgICAgIGlmIChwYXJzZXIuZGF0YSkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhc3NldCA9IHBhcnNlci5kYXRhKHJlc3BvbnNlKVxuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJldHVybiBhYm9ydChlKVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBhc3NldCA9IHJlc3BvbnNlXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmICh4aHIucmVhZHlTdGF0ZSA+IDMgJiYgbG9hZGVyLnN0YXRlID09PSBTVEFURV9EQVRBKSB7XG4gICAgICAgIGlmIChwYXJzZXIuZG9uZSkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhc3NldCA9IHBhcnNlci5kb25lKClcbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICByZXR1cm4gYWJvcnQoZSlcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgbG9hZGVyLnN0YXRlID0gU1RBVEVfQ09NUExFVEVcbiAgICAgIH1cbiAgICAgIGFzc2V0c1tuYW1lXSA9IGFzc2V0XG4gICAgICBsb2FkZXIucHJvZ3Jlc3MgPSAwLjc1ICogbG9hZGVyLnByb2dyZXNzICsgMC4yNVxuICAgICAgbG9hZGVyLnJlYWR5ID1cbiAgICAgICAgKHJlcXVlc3Quc3RyZWFtICYmICEhYXNzZXQpIHx8XG4gICAgICAgIGxvYWRlci5zdGF0ZSA9PT0gU1RBVEVfQ09NUExFVEVcbiAgICAgIG5vdGlmeVByb2dyZXNzKClcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjYW5jZWwgKCkge1xuICAgICAgaWYgKGxvYWRlci5zdGF0ZSA9PT0gU1RBVEVfQ09NUExFVEUgfHwgbG9hZGVyLnN0YXRlID09PSBTVEFURV9FUlJPUikge1xuICAgICAgICByZXR1cm5cbiAgICAgIH1cbiAgICAgIHhoci5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBudWxsXG4gICAgICB4aHIuYWJvcnQoKVxuICAgICAgbG9hZGVyLnN0YXRlID0gU1RBVEVfRVJST1JcbiAgICB9XG5cbiAgICAvLyBzZXQgdXAgcmVxdWVzdFxuICAgIGlmIChyZXF1ZXN0LmNyZWRlbnRpYWxzKSB7XG4gICAgICB4aHIud2l0aENyZWRlbnRpYWxzID0gdHJ1ZVxuICAgIH1cbiAgICB4aHIub3BlbignR0VUJywgcmVxdWVzdC5zcmMsIHRydWUpXG4gICAgeGhyLnNlbmQoKVxuXG4gICAgcmV0dXJuIGxvYWRlclxuICB9XG5cbiAgZnVuY3Rpb24gbG9hZEVsZW1lbnQgKHJlcXVlc3QsIGVsZW1lbnQpIHtcbiAgICB2YXIgbmFtZSA9IHJlcXVlc3QubmFtZVxuICAgIHZhciBwYXJzZXIgPSByZXF1ZXN0LnBhcnNlclxuXG4gICAgdmFyIGxvYWRlciA9IG5ldyBMb2FkZXIobmFtZSwgY2FuY2VsKVxuICAgIHZhciBhc3NldCA9IGVsZW1lbnRcblxuICAgIGZ1bmN0aW9uIGhhbmRsZVByb2dyZXNzICgpIHtcbiAgICAgIGlmIChsb2FkZXIuc3RhdGUgPT09IFNUQVRFX0RBVEEpIHtcbiAgICAgICAgaWYgKHBhcnNlci5kYXRhKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGFzc2V0ID0gcGFyc2VyLmRhdGEoZWxlbWVudClcbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICByZXR1cm4gYWJvcnQoZSlcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYXNzZXQgPSBlbGVtZW50XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBvblByb2dyZXNzIChlKSB7XG4gICAgICBoYW5kbGVQcm9ncmVzcygpXG4gICAgICBhc3NldHNbbmFtZV0gPSBhc3NldFxuICAgICAgaWYgKGUubGVuZ3RoQ29tcHV0YWJsZSkge1xuICAgICAgICBsb2FkZXIucHJvZ3Jlc3MgPSBNYXRoLm1heChsb2FkZXIucHJvZ3Jlc3MsIGUubG9hZGVkIC8gZS50b3RhbClcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvYWRlci5wcm9ncmVzcyA9IDAuNzUgKiBsb2FkZXIucHJvZ3Jlc3MgKyAwLjI1XG4gICAgICB9XG4gICAgICBsb2FkZXIucmVhZHkgPSByZXF1ZXN0LnN0cmVhbVxuICAgICAgbm90aWZ5UHJvZ3Jlc3MobmFtZSlcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBvbkNvbXBsZXRlICgpIHtcbiAgICAgIGhhbmRsZVByb2dyZXNzKClcbiAgICAgIGlmIChsb2FkZXIuc3RhdGUgPT09IFNUQVRFX0RBVEEpIHtcbiAgICAgICAgaWYgKHBhcnNlci5kb25lKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGFzc2V0ID0gcGFyc2VyLmRvbmUoKVxuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJldHVybiBhYm9ydChlKVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBsb2FkZXIuc3RhdGUgPSBTVEFURV9DT01QTEVURVxuICAgICAgfVxuICAgICAgbG9hZGVyLnByb2dyZXNzID0gMVxuICAgICAgbG9hZGVyLnJlYWR5ID0gdHJ1ZVxuICAgICAgYXNzZXRzW25hbWVdID0gYXNzZXRcbiAgICAgIHJlbW92ZUxpc3RlbmVycygpXG4gICAgICBub3RpZnlQcm9ncmVzcygnZmluaXNoICcgKyBuYW1lKVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIG9uRXJyb3IgKCkge1xuICAgICAgYWJvcnQoJ2Vycm9yIGxvYWRpbmcgYXNzZXQgXCInICsgbmFtZSArICdcIicpXG4gICAgfVxuXG4gICAgaWYgKHJlcXVlc3Quc3RyZWFtKSB7XG4gICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3Byb2dyZXNzJywgb25Qcm9ncmVzcylcbiAgICB9XG4gICAgaWYgKHJlcXVlc3QudHlwZSA9PT0gJ2ltYWdlJykge1xuICAgICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgb25Db21wbGV0ZSlcbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGNhblBsYXkgPSBmYWxzZVxuICAgICAgdmFyIGxvYWRlZE1ldGFEYXRhID0gZmFsc2VcbiAgICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbG9hZGVkbWV0YWRhdGEnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGxvYWRlZE1ldGFEYXRhID0gdHJ1ZVxuICAgICAgICBpZiAoY2FuUGxheSkge1xuICAgICAgICAgIG9uQ29tcGxldGUoKVxuICAgICAgICB9XG4gICAgICB9KVxuICAgICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdjYW5wbGF5JywgZnVuY3Rpb24gKCkge1xuICAgICAgICBjYW5QbGF5ID0gdHJ1ZVxuICAgICAgICBpZiAobG9hZGVkTWV0YURhdGEpIHtcbiAgICAgICAgICBvbkNvbXBsZXRlKClcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICB9XG4gICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdlcnJvcicsIG9uRXJyb3IpXG5cbiAgICBmdW5jdGlvbiByZW1vdmVMaXN0ZW5lcnMgKCkge1xuICAgICAgaWYgKHJlcXVlc3Quc3RyZWFtKSB7XG4gICAgICAgIGVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigncHJvZ3Jlc3MnLCBvblByb2dyZXNzKVxuICAgICAgfVxuICAgICAgaWYgKHJlcXVlc3QudHlwZSA9PT0gJ2ltYWdlJykge1xuICAgICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCBvbkNvbXBsZXRlKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdjYW5wbGF5Jywgb25Db21wbGV0ZSlcbiAgICAgIH1cbiAgICAgIGVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignZXJyb3InLCBvbkVycm9yKVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNhbmNlbCAoKSB7XG4gICAgICBpZiAobG9hZGVyLnN0YXRlID09PSBTVEFURV9DT01QTEVURSB8fCBsb2FkZXIuc3RhdGUgPT09IFNUQVRFX0VSUk9SKSB7XG4gICAgICAgIHJldHVyblxuICAgICAgfVxuICAgICAgbG9hZGVyLnN0YXRlID0gU1RBVEVfRVJST1JcbiAgICAgIHJlbW92ZUxpc3RlbmVycygpXG4gICAgICBlbGVtZW50LnNyYyA9ICcnXG4gICAgfVxuXG4gICAgLy8gc2V0IHVwIHJlcXVlc3RcbiAgICBpZiAocmVxdWVzdC5jcmVkZW50aWFscykge1xuICAgICAgZWxlbWVudC5jcm9zc09yaWdpbiA9ICd1c2UtY3JlZGVudGlhbHMnXG4gICAgfSBlbHNlIHtcbiAgICAgIGVsZW1lbnQuY3Jvc3NPcmlnaW4gPSAnYW5vbnltb3VzJ1xuICAgIH1cbiAgICBlbGVtZW50LnNyYyA9IHJlcXVlc3Quc3JjXG5cbiAgICByZXR1cm4gbG9hZGVyXG4gIH1cblxuICB2YXIgbG9hZGVycyA9IHtcbiAgICB0ZXh0OiBsb2FkWEhSLFxuICAgIGJpbmFyeTogZnVuY3Rpb24gKHJlcXVlc3QpIHtcbiAgICAgIC8vIFRPRE8gdXNlIGZldGNoIEFQSSBmb3Igc3RyZWFtaW5nIGlmIHN1cHBvcnRlZFxuICAgICAgcmV0dXJuIGxvYWRYSFIocmVxdWVzdClcbiAgICB9LFxuICAgIGltYWdlOiBmdW5jdGlvbiAocmVxdWVzdCkge1xuICAgICAgcmV0dXJuIGxvYWRFbGVtZW50KHJlcXVlc3QsIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2ltZycpKVxuICAgIH0sXG4gICAgdmlkZW86IGZ1bmN0aW9uIChyZXF1ZXN0KSB7XG4gICAgICByZXR1cm4gbG9hZEVsZW1lbnQocmVxdWVzdCwgZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndmlkZW8nKSlcbiAgICB9LFxuICAgIGF1ZGlvOiBmdW5jdGlvbiAocmVxdWVzdCkge1xuICAgICAgcmV0dXJuIGxvYWRFbGVtZW50KHJlcXVlc3QsIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2F1ZGlvJykpXG4gICAgfVxuICB9XG5cbiAgLy8gRmlyc3Qgd2UgcGFyc2UgYWxsIG9iamVjdHMgaW4gb3JkZXIgdG8gdmVyaWZ5IHRoYXQgYWxsIHR5cGUgaW5mb3JtYXRpb25cbiAgLy8gaXMgY29ycmVjdFxuICB2YXIgcGVuZGluZyA9IE9iamVjdC5rZXlzKG1hbmlmZXN0KS5tYXAoZnVuY3Rpb24gKG5hbWUpIHtcbiAgICB2YXIgcmVxdWVzdCA9IG1hbmlmZXN0W25hbWVdXG4gICAgaWYgKHR5cGVvZiByZXF1ZXN0ID09PSAnc3RyaW5nJykge1xuICAgICAgcmVxdWVzdCA9IHtcbiAgICAgICAgc3JjOiByZXF1ZXN0XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgcmVxdWVzdCAhPT0gJ29iamVjdCcgfHwgIXJlcXVlc3QpIHtcbiAgICAgIHJhaXNlKCdpbnZhbGlkIGFzc2V0IGRlZmluaXRpb24gXCInICsgbmFtZSArICdcIicpXG4gICAgfVxuXG4gICAgY2hlY2tUeXBlKHJlcXVlc3QsIG1hbmlmZXN0UGFyYW1ldGVycywgJ2Fzc2V0IFwiJyArIG5hbWUgKyAnXCInKVxuXG4gICAgZnVuY3Rpb24gZ2V0UGFyYW1ldGVyIChwcm9wLCBhY2NlcHRlZCwgaW5pdCkge1xuICAgICAgdmFyIHZhbHVlID0gaW5pdFxuICAgICAgaWYgKHByb3AgaW4gcmVxdWVzdCkge1xuICAgICAgICB2YWx1ZSA9IHJlcXVlc3RbcHJvcF1cbiAgICAgIH1cbiAgICAgIGlmIChhY2NlcHRlZC5pbmRleE9mKHZhbHVlKSA8IDApIHtcbiAgICAgICAgcmFpc2UoJ2ludmFsaWQgJyArIHByb3AgKyAnIFwiJyArIHZhbHVlICsgJ1wiIGZvciBhc3NldCBcIicgKyBuYW1lICsgJ1wiLCBwb3NzaWJsZSB2YWx1ZXM6ICcgKyBhY2NlcHRlZClcbiAgICAgIH1cbiAgICAgIHJldHVybiB2YWx1ZVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldFN0cmluZyAocHJvcCwgcmVxdWlyZWQsIGluaXQpIHtcbiAgICAgIHZhciB2YWx1ZSA9IGluaXRcbiAgICAgIGlmIChwcm9wIGluIHJlcXVlc3QpIHtcbiAgICAgICAgdmFsdWUgPSByZXF1ZXN0W3Byb3BdXG4gICAgICB9IGVsc2UgaWYgKHJlcXVpcmVkKSB7XG4gICAgICAgIHJhaXNlKCdtaXNzaW5nICcgKyBwcm9wICsgJyBmb3IgYXNzZXQgXCInICsgbmFtZSArICdcIicpXG4gICAgICB9XG4gICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnc3RyaW5nJykge1xuICAgICAgICByYWlzZSgnaW52YWxpZCAnICsgcHJvcCArICcgZm9yIGFzc2V0IFwiJyArIG5hbWUgKyAnXCIsIG11c3QgYmUgYSBzdHJpbmcnKVxuICAgICAgfVxuICAgICAgcmV0dXJuIHZhbHVlXG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0UGFyc2VGdW5jIChuYW1lLCBkZmx0KSB7XG4gICAgICBpZiAobmFtZSBpbiByZXF1ZXN0LnBhcnNlcikge1xuICAgICAgICB2YXIgcmVzdWx0ID0gcmVxdWVzdC5wYXJzZXJbbmFtZV1cbiAgICAgICAgaWYgKHR5cGVvZiByZXN1bHQgIT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICByYWlzZSgnaW52YWxpZCBwYXJzZXIgY2FsbGJhY2sgJyArIG5hbWUgKyAnIGZvciBhc3NldCBcIicgKyBuYW1lICsgJ1wiJylcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gZGZsdFxuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBwYXJzZXIgPSB7fVxuICAgIGlmICgncGFyc2VyJyBpbiByZXF1ZXN0KSB7XG4gICAgICBpZiAodHlwZW9mIHJlcXVlc3QucGFyc2VyID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHBhcnNlciA9IHtcbiAgICAgICAgICBkYXRhOiByZXF1ZXN0LnBhcnNlclxuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHR5cGVvZiByZXF1ZXN0LnBhcnNlciA9PT0gJ29iamVjdCcgJiYgcmVxdWVzdC5wYXJzZXIpIHtcbiAgICAgICAgY2hlY2tUeXBlKHBhcnNlciwgcGFyc2VyUGFyYW1ldGVycywgJ3BhcnNlciBmb3IgYXNzZXQgXCInICsgbmFtZSArICdcIicpXG4gICAgICAgIGlmICghKCdvbkRhdGEnIGluIHBhcnNlcikpIHtcbiAgICAgICAgICByYWlzZSgnbWlzc2luZyBvbkRhdGEgY2FsbGJhY2sgZm9yIHBhcnNlciBpbiBhc3NldCBcIicgKyBuYW1lICsgJ1wiJylcbiAgICAgICAgfVxuICAgICAgICBwYXJzZXIgPSB7XG4gICAgICAgICAgZGF0YTogZ2V0UGFyc2VGdW5jKCdvbkRhdGEnKSxcbiAgICAgICAgICBkb25lOiBnZXRQYXJzZUZ1bmMoJ29uRG9uZScpXG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJhaXNlKCdpbnZhbGlkIHBhcnNlciBmb3IgYXNzZXQgXCInICsgbmFtZSArICdcIicpXG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6IG5hbWUsXG4gICAgICB0eXBlOiBnZXRQYXJhbWV0ZXIoJ3R5cGUnLCBPYmplY3Qua2V5cyhsb2FkZXJzKSwgJ3RleHQnKSxcbiAgICAgIHN0cmVhbTogISFyZXF1ZXN0LnN0cmVhbSxcbiAgICAgIGNyZWRlbnRpYWxzOiAhIXJlcXVlc3QuY3JlZGVudGlhbHMsXG4gICAgICBzcmM6IGdldFN0cmluZygnc3JjJywgdHJ1ZSwgJycpLFxuICAgICAgcGFyc2VyOiBwYXJzZXJcbiAgICB9XG4gIH0pLm1hcChmdW5jdGlvbiAocmVxdWVzdCkge1xuICAgIHJldHVybiAobG9hZGVyc1tyZXF1ZXN0LnR5cGVdKShyZXF1ZXN0KVxuICB9KVxuXG4gIGZ1bmN0aW9uIGFib3J0IChtZXNzYWdlKSB7XG4gICAgaWYgKHN0YXRlID09PSBTVEFURV9FUlJPUiB8fCBzdGF0ZSA9PT0gU1RBVEVfQ09NUExFVEUpIHtcbiAgICAgIHJldHVyblxuICAgIH1cbiAgICBzdGF0ZSA9IFNUQVRFX0VSUk9SXG4gICAgcGVuZGluZy5mb3JFYWNoKGZ1bmN0aW9uIChsb2FkZXIpIHtcbiAgICAgIGxvYWRlci5jYW5jZWwoKVxuICAgIH0pXG4gICAgaWYgKG9uRXJyb3IpIHtcbiAgICAgIGlmICh0eXBlb2YgbWVzc2FnZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgb25FcnJvcihuZXcgRXJyb3IoJ3Jlc2w6ICcgKyBtZXNzYWdlKSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG9uRXJyb3IobWVzc2FnZSlcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5lcnJvcigncmVzbCBlcnJvcjonLCBtZXNzYWdlKVxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIG5vdGlmeVByb2dyZXNzIChtZXNzYWdlKSB7XG4gICAgaWYgKHN0YXRlID09PSBTVEFURV9FUlJPUiB8fCBzdGF0ZSA9PT0gU1RBVEVfQ09NUExFVEUpIHtcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIHZhciBwcm9ncmVzcyA9IDBcbiAgICB2YXIgbnVtUmVhZHkgPSAwXG4gICAgcGVuZGluZy5mb3JFYWNoKGZ1bmN0aW9uIChsb2FkZXIpIHtcbiAgICAgIGlmIChsb2FkZXIucmVhZHkpIHtcbiAgICAgICAgbnVtUmVhZHkgKz0gMVxuICAgICAgfVxuICAgICAgcHJvZ3Jlc3MgKz0gbG9hZGVyLnByb2dyZXNzXG4gICAgfSlcblxuICAgIGlmIChudW1SZWFkeSA9PT0gcGVuZGluZy5sZW5ndGgpIHtcbiAgICAgIHN0YXRlID0gU1RBVEVfQ09NUExFVEVcbiAgICAgIG9uRG9uZShhc3NldHMpXG4gICAgfSBlbHNlIHtcbiAgICAgIGlmIChvblByb2dyZXNzKSB7XG4gICAgICAgIG9uUHJvZ3Jlc3MocHJvZ3Jlc3MgLyBwZW5kaW5nLmxlbmd0aCwgbWVzc2FnZSlcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiJdfQ== | |
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
var GL_FLOAT = 5126 | |
function AttributeRecord () { | |
this.state = 0 | |
this.x = 0.0 | |
this.y = 0.0 | |
this.z = 0.0 | |
this.w = 0.0 | |
this.buffer = null | |
this.size = 0 | |
this.normalized = false | |
this.type = GL_FLOAT | |
this.offset = 0 | |
this.stride = 0 | |
this.divisor = 0 | |
} | |
module.exports = function wrapAttributeState ( | |
gl, | |
extensions, | |
limits, | |
bufferState, | |
stringStore) { | |
var NUM_ATTRIBUTES = limits.maxAttributes | |
var attributeBindings = new Array(NUM_ATTRIBUTES) | |
for (var i = 0; i < NUM_ATTRIBUTES; ++i) { | |
attributeBindings[i] = new AttributeRecord() | |
} | |
return { | |
Record: AttributeRecord, | |
scope: {}, | |
state: attributeBindings | |
} | |
} | |
},{}],2:[function(require,module,exports){ | |
var check = require('./util/check') | |
var isTypedArray = require('./util/is-typed-array') | |
var isNDArrayLike = require('./util/is-ndarray') | |
var values = require('./util/values') | |
var pool = require('./util/pool') | |
var arrayTypes = require('./constants/arraytypes.json') | |
var bufferTypes = require('./constants/dtypes.json') | |
var usageTypes = require('./constants/usage.json') | |
var GL_STATIC_DRAW = 0x88E4 | |
var GL_STREAM_DRAW = 0x88E0 | |
var GL_UNSIGNED_BYTE = 5121 | |
var GL_FLOAT = 5126 | |
var DTYPES_SIZES = [] | |
DTYPES_SIZES[5120] = 1 // int8 | |
DTYPES_SIZES[5122] = 2 // int16 | |
DTYPES_SIZES[5124] = 4 // int32 | |
DTYPES_SIZES[5121] = 1 // uint8 | |
DTYPES_SIZES[5123] = 2 // uint16 | |
DTYPES_SIZES[5125] = 4 // uint32 | |
DTYPES_SIZES[5126] = 4 // float32 | |
function typedArrayCode (data) { | |
return arrayTypes[Object.prototype.toString.call(data)] | 0 | |
} | |
function copyArray (out, inp) { | |
for (var i = 0; i < inp.length; ++i) { | |
out[i] = inp[i] | |
} | |
} | |
function transpose ( | |
result, data, shapeX, shapeY, strideX, strideY, offset) { | |
var ptr = 0 | |
for (var i = 0; i < shapeX; ++i) { | |
for (var j = 0; j < shapeY; ++j) { | |
result[ptr++] = data[strideX * i + strideY * j + offset] | |
} | |
} | |
} | |
function flatten (result, data, dimension) { | |
var ptr = 0 | |
for (var i = 0; i < data.length; ++i) { | |
var v = data[i] | |
for (var j = 0; j < dimension; ++j) { | |
result[ptr++] = v[j] | |
} | |
} | |
} | |
module.exports = function wrapBufferState (gl, stats, config) { | |
var bufferCount = 0 | |
var bufferSet = {} | |
function REGLBuffer (type) { | |
this.id = bufferCount++ | |
this.buffer = gl.createBuffer() | |
this.type = type | |
this.usage = GL_STATIC_DRAW | |
this.byteLength = 0 | |
this.dimension = 1 | |
this.dtype = GL_UNSIGNED_BYTE | |
if (config.profile) { | |
this.stats = {size: 0} | |
} | |
} | |
REGLBuffer.prototype.bind = function () { | |
gl.bindBuffer(this.type, this.buffer) | |
} | |
REGLBuffer.prototype.destroy = function () { | |
destroy(this) | |
} | |
var streamPool = [] | |
function createStream (type, data) { | |
var buffer = streamPool.pop() | |
if (!buffer) { | |
buffer = new REGLBuffer(type) | |
} | |
buffer.bind() | |
initBufferFromData(buffer, data, GL_STREAM_DRAW, 0, 1) | |
return buffer | |
} | |
function destroyStream (stream) { | |
streamPool.push(stream) | |
} | |
function initBufferFromTypedArray (buffer, data, usage) { | |
buffer.byteLength = data.byteLength | |
gl.bufferData(buffer.type, data, usage) | |
} | |
function initBufferFromData (buffer, data, usage, dtype, dimension) { | |
buffer.usage = usage | |
if (Array.isArray(data)) { | |
buffer.dtype = dtype || GL_FLOAT | |
if (data.length > 0) { | |
var flatData | |
if (Array.isArray(data[0])) { | |
buffer.dimension = data[0].length | |
flatData = pool.allocType( | |
buffer.dtype, | |
data.length * buffer.dimension) | |
flatten(flatData, data, buffer.dimension) | |
initBufferFromTypedArray(buffer, flatData, usage) | |
pool.freeType(flatData) | |
} else if (typeof data[0] === 'number') { | |
buffer.dimension = dimension | |
var typedData = pool.allocType(buffer.dtype, data.length) | |
copyArray(typedData, data) | |
initBufferFromTypedArray(buffer, typedData, usage) | |
pool.freeType(typedData) | |
} else if (isTypedArray(data[0])) { | |
buffer.dimension = data[0].length | |
buffer.dtype = dtype || typedArrayCode(data[0]) || GL_FLOAT | |
flatData = pool.allocType( | |
buffer.dtype, | |
data.length * buffer.dimension) | |
flatten(flatData, data, buffer.dimension) | |
initBufferFromTypedArray(buffer, flatData, usage) | |
pool.freeType(flatData) | |
} else { | |
check.raise('invalid buffer data') | |
} | |
} | |
} else if (isTypedArray(data)) { | |
buffer.dtype = dtype || typedArrayCode(data) | |
buffer.dimension = dimension | |
initBufferFromTypedArray(buffer, data, usage) | |
} else if (isNDArrayLike(data)) { | |
var shape = data.shape | |
var stride = data.stride | |
var offset = data.offset | |
var shapeX = 0 | |
var shapeY = 0 | |
var strideX = 0 | |
var strideY = 0 | |
if (shape.length === 1) { | |
shapeX = shape[0] | |
shapeY = 1 | |
strideX = stride[0] | |
strideY = 0 | |
} else if (shape.length === 2) { | |
shapeX = shape[0] | |
shapeY = shape[1] | |
strideX = stride[0] | |
strideY = stride[1] | |
} else { | |
check.raise('invalid shape') | |
} | |
buffer.dtype = dtype || typedArrayCode(data.data) || GL_FLOAT | |
buffer.dimension = shapeY | |
var transposeData = pool.allocType(buffer.dtype, shapeX * shapeY) | |
transpose(transposeData, | |
data.data, | |
shapeX, shapeY, | |
strideX, strideY, | |
offset) | |
initBufferFromTypedArray(buffer, transposeData, usage) | |
pool.freeType(transposeData) | |
} else { | |
check.raise('invalid buffer data') | |
} | |
} | |
function destroy (buffer) { | |
stats.bufferCount-- | |
var handle = buffer.buffer | |
check(handle, 'buffer must not be deleted already') | |
gl.deleteBuffer(handle) | |
buffer.buffer = null | |
delete bufferSet[buffer.id] | |
} | |
function createBuffer (options, type, deferInit) { | |
stats.bufferCount++ | |
var buffer = new REGLBuffer(type) | |
bufferSet[buffer.id] = buffer | |
function reglBuffer (options) { | |
var usage = GL_STATIC_DRAW | |
var data = null | |
var byteLength = 0 | |
var dtype = 0 | |
var dimension = 1 | |
if (Array.isArray(options) || | |
isTypedArray(options) || | |
isNDArrayLike(options)) { | |
data = options | |
} else if (typeof options === 'number') { | |
byteLength = options | 0 | |
} else if (options) { | |
check.type( | |
options, 'object', | |
'buffer arguments must be an object, a number or an array') | |
if ('data' in options) { | |
check( | |
data === null || | |
Array.isArray(data) || | |
isTypedArray(data) || | |
isNDArrayLike(data), | |
'invalid data for buffer') | |
data = options.data | |
} | |
if ('usage' in options) { | |
check.parameter(options.usage, usageTypes, 'invalid buffer usage') | |
usage = usageTypes[options.usage] | |
} | |
if ('type' in options) { | |
check.parameter(options.type, bufferTypes, 'invalid buffer type') | |
dtype = bufferTypes[options.type] | |
} | |
if ('dimension' in options) { | |
check.type(options.dimension, 'number', 'invalid dimension') | |
dimension = options.dimension | 0 | |
} | |
if ('length' in options) { | |
check.nni(byteLength, 'buffer length must be a nonnegative integer') | |
byteLength = options.length | 0 | |
} | |
} | |
buffer.bind() | |
if (!data) { | |
gl.bufferData(buffer.type, byteLength, usage) | |
buffer.dtype = dtype || GL_UNSIGNED_BYTE | |
buffer.usage = usage | |
buffer.dimension = dimension | |
buffer.byteLength = byteLength | |
} else { | |
initBufferFromData(buffer, data, usage, dtype, dimension) | |
} | |
if (config.profile) { | |
buffer.stats.size = buffer.byteLength * DTYPES_SIZES[buffer.dtype] | |
} | |
return reglBuffer | |
} | |
function setSubData (data, offset) { | |
check(offset + data.byteLength <= buffer.byteLength, | |
'invalid buffer subdata call, buffer is too small. ' + ' Can\'t write data of size ' + data.byteLength + ' starting from offset ' + offset + ' to a buffer of size ' + buffer.byteLength) | |
gl.bufferSubData(buffer.type, offset, data) | |
} | |
function subdata (data, offset_) { | |
var offset = (offset_ || 0) | 0 | |
buffer.bind() | |
if (Array.isArray(data)) { | |
if (data.length > 0) { | |
if (typeof data[0] === 'number') { | |
var converted = pool.allocType(buffer.dtype, data.length) | |
copyArray(converted, data) | |
setSubData(converted, offset) | |
pool.freeType(converted) | |
} else if (Array.isArray(data[0]) || isTypedArray(data[0])) { | |
var dimension = data[0].length | |
var flatData = pool.allocType(buffer.dtype, data.length * dimension) | |
flatten(flatData, data, dimension) | |
setSubData(flatData, offset) | |
pool.freeType(flatData) | |
} else { | |
check.raise('invalid buffer data') | |
} | |
} | |
} else if (isTypedArray(data)) { | |
setSubData(data, offset) | |
} else if (isNDArrayLike(data)) { | |
var shape = data.shape | |
var stride = data.stride | |
var shapeX = 0 | |
var shapeY = 0 | |
var strideX = 0 | |
var strideY = 0 | |
if (shape.length === 1) { | |
shapeX = shape[0] | |
shapeY = 1 | |
strideX = stride[0] | |
strideY = 0 | |
} else if (shape.length === 2) { | |
shapeX = shape[0] | |
shapeY = shape[1] | |
strideX = stride[0] | |
strideY = stride[1] | |
} else { | |
check.raise('invalid shape') | |
} | |
var dtype = Array.isArray(data.data) | |
? buffer.dtype | |
: typedArrayCode(data.data) | |
var transposeData = pool.allocType(dtype, shapeX * shapeY) | |
transpose(transposeData, | |
data.data, | |
shapeX, shapeY, | |
strideX, strideY, | |
data.offset) | |
setSubData(transposeData, offset) | |
pool.freeType(transposeData) | |
} else { | |
check.raise('invalid data for buffer subdata') | |
} | |
return reglBuffer | |
} | |
if (!deferInit) { | |
reglBuffer(options) | |
} | |
reglBuffer._reglType = 'buffer' | |
reglBuffer._buffer = buffer | |
reglBuffer.subdata = subdata | |
if (config.profile) { | |
reglBuffer.stats = buffer.stats | |
} | |
reglBuffer.destroy = function () { destroy(buffer) } | |
return reglBuffer | |
} | |
if (config.profile) { | |
stats.getTotalBufferSize = function () { | |
var total = 0 | |
// TODO: Right now, the streams are not part of the total count. | |
Object.keys(bufferSet).forEach(function (key) { | |
total += bufferSet[key].stats.size | |
}) | |
return total | |
} | |
} | |
return { | |
create: createBuffer, | |
createStream: createStream, | |
destroyStream: destroyStream, | |
clear: function () { | |
values(bufferSet).forEach(destroy) | |
streamPool.forEach(destroy) | |
}, | |
getBuffer: function (wrapper) { | |
if (wrapper && wrapper._buffer instanceof REGLBuffer) { | |
return wrapper._buffer | |
} | |
return null | |
}, | |
_initBuffer: initBufferFromData | |
} | |
} | |
},{"./constants/arraytypes.json":3,"./constants/dtypes.json":4,"./constants/usage.json":6,"./util/check":20,"./util/is-ndarray":25,"./util/is-typed-array":26,"./util/pool":28,"./util/values":31}],3:[function(require,module,exports){ | |
module.exports={ | |
"[object Int8Array]": 5120 | |
, "[object Int16Array]": 5122 | |
, "[object Int32Array]": 5124 | |
, "[object Uint8Array]": 5121 | |
, "[object Uint8ClampedArray]": 5121 | |
, "[object Uint16Array]": 5123 | |
, "[object Uint32Array]": 5125 | |
, "[object Float32Array]": 5126 | |
, "[object Float64Array]": 5121 | |
, "[object ArrayBuffer]": 5121 | |
} | |
},{}],4:[function(require,module,exports){ | |
module.exports={ | |
"int8": 5120 | |
, "int16": 5122 | |
, "int32": 5124 | |
, "uint8": 5121 | |
, "uint16": 5123 | |
, "uint32": 5125 | |
, "float": 5126 | |
, "float32": 5126 | |
} | |
},{}],5:[function(require,module,exports){ | |
module.exports={ | |
"points": 0, | |
"point": 0, | |
"lines": 1, | |
"line": 1, | |
"line loop": 2, | |
"line strip": 3, | |
"triangles": 4, | |
"triangle": 4, | |
"triangle strip": 5, | |
"triangle fan": 6 | |
} | |
},{}],6:[function(require,module,exports){ | |
module.exports={ | |
"static": 35044, | |
"dynamic": 35048, | |
"stream": 35040 | |
} | |
},{}],7:[function(require,module,exports){ | |
var check = require('./util/check') | |
var createEnvironment = require('./util/codegen') | |
var loop = require('./util/loop') | |
var isTypedArray = require('./util/is-typed-array') | |
var isNDArray = require('./util/is-ndarray') | |
var isArrayLike = require('./util/is-array-like') | |
var dynamic = require('./dynamic') | |
var primTypes = require('./constants/primitives.json') | |
var glTypes = require('./constants/dtypes.json') | |
// "cute" names for vector components | |
var CUTE_COMPONENTS = 'xyzw'.split('') | |
var GL_UNSIGNED_BYTE = 5121 | |
var ATTRIB_STATE_POINTER = 1 | |
var ATTRIB_STATE_CONSTANT = 2 | |
var DYN_FUNC = 0 | |
var DYN_PROP = 1 | |
var DYN_CONTEXT = 2 | |
var DYN_STATE = 3 | |
var DYN_THUNK = 4 | |
var S_DITHER = 'dither' | |
var S_BLEND_ENABLE = 'blend.enable' | |
var S_BLEND_COLOR = 'blend.color' | |
var S_BLEND_EQUATION = 'blend.equation' | |
var S_BLEND_FUNC = 'blend.func' | |
var S_DEPTH_ENABLE = 'depth.enable' | |
var S_DEPTH_FUNC = 'depth.func' | |
var S_DEPTH_RANGE = 'depth.range' | |
var S_DEPTH_MASK = 'depth.mask' | |
var S_COLOR_MASK = 'colorMask' | |
var S_CULL_ENABLE = 'cull.enable' | |
var S_CULL_FACE = 'cull.face' | |
var S_FRONT_FACE = 'frontFace' | |
var S_LINE_WIDTH = 'lineWidth' | |
var S_POLYGON_OFFSET_ENABLE = 'polygonOffset.enable' | |
var S_POLYGON_OFFSET_OFFSET = 'polygonOffset.offset' | |
var S_SAMPLE_ALPHA = 'sample.alpha' | |
var S_SAMPLE_ENABLE = 'sample.enable' | |
var S_SAMPLE_COVERAGE = 'sample.coverage' | |
var S_STENCIL_ENABLE = 'stencil.enable' | |
var S_STENCIL_MASK = 'stencil.mask' | |
var S_STENCIL_FUNC = 'stencil.func' | |
var S_STENCIL_OPFRONT = 'stencil.opFront' | |
var S_STENCIL_OPBACK = 'stencil.opBack' | |
var S_SCISSOR_ENABLE = 'scissor.enable' | |
var S_SCISSOR_BOX = 'scissor.box' | |
var S_VIEWPORT = 'viewport' | |
var S_PROFILE = 'profile' | |
var S_FRAMEBUFFER = 'framebuffer' | |
var S_VERT = 'vert' | |
var S_FRAG = 'frag' | |
var S_ELEMENTS = 'elements' | |
var S_PRIMITIVE = 'primitive' | |
var S_COUNT = 'count' | |
var S_OFFSET = 'offset' | |
var S_INSTANCES = 'instances' | |
var SUFFIX_WIDTH = 'Width' | |
var SUFFIX_HEIGHT = 'Height' | |
var S_FRAMEBUFFER_WIDTH = S_FRAMEBUFFER + SUFFIX_WIDTH | |
var S_FRAMEBUFFER_HEIGHT = S_FRAMEBUFFER + SUFFIX_HEIGHT | |
var S_VIEWPORT_WIDTH = S_VIEWPORT + SUFFIX_WIDTH | |
var S_VIEWPORT_HEIGHT = S_VIEWPORT + SUFFIX_HEIGHT | |
var S_DRAWINGBUFFER = 'drawingBuffer' | |
var S_DRAWINGBUFFER_WIDTH = S_DRAWINGBUFFER + SUFFIX_WIDTH | |
var S_DRAWINGBUFFER_HEIGHT = S_DRAWINGBUFFER + SUFFIX_HEIGHT | |
var NESTED_OPTIONS = [ | |
S_BLEND_FUNC, | |
S_BLEND_EQUATION, | |
S_STENCIL_FUNC, | |
S_STENCIL_OPFRONT, | |
S_STENCIL_OPBACK, | |
S_SAMPLE_COVERAGE, | |
S_VIEWPORT, | |
S_SCISSOR_BOX, | |
S_POLYGON_OFFSET_OFFSET | |
] | |
var GL_ARRAY_BUFFER = 34962 | |
var GL_ELEMENT_ARRAY_BUFFER = 34963 | |
var GL_FRAGMENT_SHADER = 35632 | |
var GL_VERTEX_SHADER = 35633 | |
var GL_TEXTURE_2D = 0x0DE1 | |
var GL_TEXTURE_CUBE_MAP = 0x8513 | |
var GL_CULL_FACE = 0x0B44 | |
var GL_BLEND = 0x0BE2 | |
var GL_DITHER = 0x0BD0 | |
var GL_STENCIL_TEST = 0x0B90 | |
var GL_DEPTH_TEST = 0x0B71 | |
var GL_SCISSOR_TEST = 0x0C11 | |
var GL_POLYGON_OFFSET_FILL = 0x8037 | |
var GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E | |
var GL_SAMPLE_COVERAGE = 0x80A0 | |
var GL_FLOAT = 5126 | |
var GL_FLOAT_VEC2 = 35664 | |
var GL_FLOAT_VEC3 = 35665 | |
var GL_FLOAT_VEC4 = 35666 | |
var GL_INT = 5124 | |
var GL_INT_VEC2 = 35667 | |
var GL_INT_VEC3 = 35668 | |
var GL_INT_VEC4 = 35669 | |
var GL_BOOL = 35670 | |
var GL_BOOL_VEC2 = 35671 | |
var GL_BOOL_VEC3 = 35672 | |
var GL_BOOL_VEC4 = 35673 | |
var GL_FLOAT_MAT2 = 35674 | |
var GL_FLOAT_MAT3 = 35675 | |
var GL_FLOAT_MAT4 = 35676 | |
var GL_SAMPLER_2D = 35678 | |
var GL_SAMPLER_CUBE = 35680 | |
var GL_TRIANGLES = 4 | |
var GL_FRONT = 1028 | |
var GL_BACK = 1029 | |
var GL_CW = 0x0900 | |
var GL_CCW = 0x0901 | |
var GL_MIN_EXT = 0x8007 | |
var GL_MAX_EXT = 0x8008 | |
var GL_ALWAYS = 519 | |
var GL_KEEP = 7680 | |
var GL_ZERO = 0 | |
var GL_ONE = 1 | |
var GL_FUNC_ADD = 0x8006 | |
var GL_LESS = 513 | |
var GL_FRAMEBUFFER = 0x8D40 | |
var GL_COLOR_ATTACHMENT0 = 0x8CE0 | |
var blendFuncs = { | |
'0': 0, | |
'1': 1, | |
'zero': 0, | |
'one': 1, | |
'src color': 768, | |
'one minus src color': 769, | |
'src alpha': 770, | |
'one minus src alpha': 771, | |
'dst color': 774, | |
'one minus dst color': 775, | |
'dst alpha': 772, | |
'one minus dst alpha': 773, | |
'constant color': 32769, | |
'one minus constant color': 32770, | |
'constant alpha': 32771, | |
'one minus constant alpha': 32772, | |
'src alpha saturate': 776 | |
} | |
var compareFuncs = { | |
'never': 512, | |
'less': 513, | |
'<': 513, | |
'equal': 514, | |
'=': 514, | |
'==': 514, | |
'===': 514, | |
'lequal': 515, | |
'<=': 515, | |
'greater': 516, | |
'>': 516, | |
'notequal': 517, | |
'!=': 517, | |
'!==': 517, | |
'gequal': 518, | |
'>=': 518, | |
'always': 519 | |
} | |
var stencilOps = { | |
'0': 0, | |
'zero': 0, | |
'keep': 7680, | |
'replace': 7681, | |
'increment': 7682, | |
'decrement': 7683, | |
'increment wrap': 34055, | |
'decrement wrap': 34056, | |
'invert': 5386 | |
} | |
var shaderType = { | |
'frag': GL_FRAGMENT_SHADER, | |
'vert': GL_VERTEX_SHADER | |
} | |
var orientationType = { | |
'cw': GL_CW, | |
'ccw': GL_CCW | |
} | |
function isBufferArgs (x) { | |
return Array.isArray(x) || | |
isTypedArray(x) || | |
isNDArray(x) | |
} | |
// Make sure viewport is processed first | |
function sortState (state) { | |
return state.sort(function (a, b) { | |
if (a === S_VIEWPORT) { | |
return -1 | |
} else if (b === S_VIEWPORT) { | |
return 1 | |
} | |
return (a < b) ? -1 : 1 | |
}) | |
} | |
function Declaration (thisDep, contextDep, propDep, append) { | |
this.thisDep = thisDep | |
this.contextDep = contextDep | |
this.propDep = propDep | |
this.append = append | |
} | |
function isStatic (decl) { | |
return decl && !(decl.thisDep || decl.contextDep || decl.propDep) | |
} | |
function createStaticDecl (append) { | |
return new Declaration(false, false, false, append) | |
} | |
function createDynamicDecl (dyn, append) { | |
var type = dyn.type | |
if (type === DYN_FUNC) { | |
var numArgs = dyn.data.length | |
return new Declaration( | |
true, | |
numArgs >= 1, | |
numArgs >= 2, | |
append) | |
} else if (type === DYN_THUNK) { | |
var data = dyn.data | |
return new Declaration( | |
data.thisDep, | |
data.contextDep, | |
data.propDep, | |
append) | |
} else { | |
return new Declaration( | |
type === DYN_STATE, | |
type === DYN_CONTEXT, | |
type === DYN_PROP, | |
append) | |
} | |
} | |
var SCOPE_DECL = new Declaration(false, false, false, function () {}) | |
module.exports = function reglCore ( | |
gl, | |
stringStore, | |
extensions, | |
limits, | |
bufferState, | |
elementState, | |
textureState, | |
framebufferState, | |
uniformState, | |
attributeState, | |
shaderState, | |
drawState, | |
contextState, | |
timer, | |
config) { | |
var AttributeRecord = attributeState.Record | |
var blendEquations = { | |
'add': 32774, | |
'subtract': 32778, | |
'reverse subtract': 32779 | |
} | |
if (extensions.ext_blend_minmax) { | |
blendEquations.min = GL_MIN_EXT | |
blendEquations.max = GL_MAX_EXT | |
} | |
var extInstancing = extensions.angle_instanced_arrays | |
var extDrawBuffers = extensions.webgl_draw_buffers | |
// =================================================== | |
// =================================================== | |
// WEBGL STATE | |
// =================================================== | |
// =================================================== | |
var currentState = { | |
dirty: true, | |
profile: config.profile | |
} | |
var nextState = {} | |
var GL_STATE_NAMES = [] | |
var GL_FLAGS = {} | |
var GL_VARIABLES = {} | |
function propName (name) { | |
return name.replace('.', '_') | |
} | |
function stateFlag (sname, cap, init) { | |
var name = propName(sname) | |
GL_STATE_NAMES.push(sname) | |
nextState[name] = currentState[name] = !!init | |
GL_FLAGS[name] = cap | |
} | |
function stateVariable (sname, func, init) { | |
var name = propName(sname) | |
GL_STATE_NAMES.push(sname) | |
if (Array.isArray(init)) { | |
currentState[name] = init.slice() | |
nextState[name] = init.slice() | |
} else { | |
currentState[name] = nextState[name] = init | |
} | |
GL_VARIABLES[name] = func | |
} | |
// Dithering | |
stateFlag(S_DITHER, GL_DITHER) | |
// Blending | |
stateFlag(S_BLEND_ENABLE, GL_BLEND) | |
stateVariable(S_BLEND_COLOR, 'blendColor', [0, 0, 0, 0]) | |
stateVariable(S_BLEND_EQUATION, 'blendEquationSeparate', | |
[GL_FUNC_ADD, GL_FUNC_ADD]) | |
stateVariable(S_BLEND_FUNC, 'blendFuncSeparate', | |
[GL_ONE, GL_ZERO, GL_ONE, GL_ZERO]) | |
// Depth | |
stateFlag(S_DEPTH_ENABLE, GL_DEPTH_TEST, true) | |
stateVariable(S_DEPTH_FUNC, 'depthFunc', GL_LESS) | |
stateVariable(S_DEPTH_RANGE, 'depthRange', [0, 1]) | |
stateVariable(S_DEPTH_MASK, 'depthMask', true) | |
// Color mask | |
stateVariable(S_COLOR_MASK, S_COLOR_MASK, [true, true, true, true]) | |
// Face culling | |
stateFlag(S_CULL_ENABLE, GL_CULL_FACE) | |
stateVariable(S_CULL_FACE, 'cullFace', GL_BACK) | |
// Front face orientation | |
stateVariable(S_FRONT_FACE, S_FRONT_FACE, GL_CCW) | |
// Line width | |
stateVariable(S_LINE_WIDTH, S_LINE_WIDTH, 1) | |
// Polygon offset | |
stateFlag(S_POLYGON_OFFSET_ENABLE, GL_POLYGON_OFFSET_FILL) | |
stateVariable(S_POLYGON_OFFSET_OFFSET, 'polygonOffset', [0, 0]) | |
// Sample coverage | |
stateFlag(S_SAMPLE_ALPHA, GL_SAMPLE_ALPHA_TO_COVERAGE) | |
stateFlag(S_SAMPLE_ENABLE, GL_SAMPLE_COVERAGE) | |
stateVariable(S_SAMPLE_COVERAGE, 'sampleCoverage', [1, false]) | |
// Stencil | |
stateFlag(S_STENCIL_ENABLE, GL_STENCIL_TEST) | |
stateVariable(S_STENCIL_MASK, 'stencilMask', -1) | |
stateVariable(S_STENCIL_FUNC, 'stencilFunc', [GL_ALWAYS, 0, -1]) | |
stateVariable(S_STENCIL_OPFRONT, 'stencilOpSeparate', | |
[GL_FRONT, GL_KEEP, GL_KEEP, GL_KEEP]) | |
stateVariable(S_STENCIL_OPBACK, 'stencilOpSeparate', | |
[GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP]) | |
// Scissor | |
stateFlag(S_SCISSOR_ENABLE, GL_SCISSOR_TEST) | |
stateVariable(S_SCISSOR_BOX, 'scissor', | |
[0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]) | |
// Viewport | |
stateVariable(S_VIEWPORT, S_VIEWPORT, | |
[0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]) | |
// =================================================== | |
// =================================================== | |
// ENVIRONMENT | |
// =================================================== | |
// =================================================== | |
var sharedState = { | |
gl: gl, | |
context: contextState, | |
strings: stringStore, | |
next: nextState, | |
current: currentState, | |
draw: drawState, | |
elements: elementState, | |
buffer: bufferState, | |
shader: shaderState, | |
attributes: attributeState.state, | |
uniforms: uniformState, | |
framebuffer: framebufferState, | |
extensions: extensions, | |
timer: timer, | |
isBufferArgs: isBufferArgs | |
} | |
var sharedConstants = { | |
primTypes: primTypes, | |
compareFuncs: compareFuncs, | |
blendFuncs: blendFuncs, | |
blendEquations: blendEquations, | |
stencilOps: stencilOps, | |
glTypes: glTypes, | |
orientationType: orientationType | |
} | |
check.optional(function () { | |
sharedState.isArrayLike = isArrayLike | |
}) | |
if (extDrawBuffers) { | |
sharedConstants.backBuffer = [GL_BACK] | |
sharedConstants.drawBuffer = loop(limits.maxDrawbuffers, function (i) { | |
if (i === 0) { | |
return [0] | |
} | |
return loop(i, function (j) { | |
return GL_COLOR_ATTACHMENT0 + j | |
}) | |
}) | |
} | |
var drawCallCounter = 0 | |
function createREGLEnvironment () { | |
var env = createEnvironment() | |
var link = env.link | |
var global = env.global | |
env.id = drawCallCounter++ | |
env.batchId = '0' | |
// link shared state | |
var SHARED = link(sharedState) | |
var shared = env.shared = { | |
props: 'a0' | |
} | |
Object.keys(sharedState).forEach(function (prop) { | |
shared[prop] = global.def(SHARED, '.', prop) | |
}) | |
// Inject runtime assertion stuff for debug builds | |
check.optional(function () { | |
env.CHECK = link(check) | |
env.commandStr = check.guessCommand() | |
env.command = link(env.commandStr) | |
env.assert = function (block, pred, message) { | |
block( | |
'if(!(', pred, '))', | |
this.CHECK, '.commandRaise(', link(message), ',', this.command, ');') | |
} | |
}) | |
// Copy GL state variables over | |
var nextVars = env.next = {} | |
var currentVars = env.current = {} | |
Object.keys(GL_VARIABLES).forEach(function (variable) { | |
if (Array.isArray(currentState[variable])) { | |
nextVars[variable] = global.def(shared.next, '.', variable) | |
currentVars[variable] = global.def(shared.current, '.', variable) | |
} | |
}) | |
// Initialize shared constants | |
var constants = env.constants = {} | |
Object.keys(sharedConstants).forEach(function (name) { | |
constants[name] = global.def(JSON.stringify(sharedConstants[name])) | |
}) | |
// Helper function for calling a block | |
env.invoke = function (block, x) { | |
switch (x.type) { | |
case DYN_FUNC: | |
var argList = [ | |
'this', | |
shared.context, | |
shared.props, | |
env.batchId | |
] | |
return block.def( | |
link(x.data), '.call(', | |
argList.slice(0, Math.max(x.data.length + 1, 4)), | |
')') | |
case DYN_PROP: | |
return block.def(shared.props, x.data) | |
case DYN_CONTEXT: | |
return block.def(shared.context, x.data) | |
case DYN_STATE: | |
return block.def('this', x.data) | |
case DYN_THUNK: | |
x.data.append(env, block) | |
return x.data.ref | |
} | |
} | |
env.attribCache = {} | |
var scopeAttribs = {} | |
env.scopeAttrib = function (name) { | |
var id = stringStore.id(name) | |
if (id in scopeAttribs) { | |
return scopeAttribs[id] | |
} | |
var binding = attributeState.scope[id] | |
if (!binding) { | |
binding = attributeState.scope[id] = new AttributeRecord() | |
} | |
var result = scopeAttribs[id] = link(binding) | |
return result | |
} | |
return env | |
} | |
// =================================================== | |
// =================================================== | |
// PARSING | |
// =================================================== | |
// =================================================== | |
function parseProfile (options) { | |
var staticOptions = options.static | |
var dynamicOptions = options.dynamic | |
var profileEnable | |
if (S_PROFILE in staticOptions) { | |
var value = !!staticOptions[S_PROFILE] | |
profileEnable = createStaticDecl(function (env, scope) { | |
return value | |
}) | |
profileEnable.enable = value | |
} else if (S_PROFILE in dynamicOptions) { | |
var dyn = dynamicOptions[S_PROFILE] | |
profileEnable = createDynamicDecl(dyn, function (env, scope) { | |
return env.invoke(scope, dyn) | |
}) | |
} | |
return profileEnable | |
} | |
function parseFramebuffer (options) { | |
var staticOptions = options.static | |
var dynamicOptions = options.dynamic | |
if (S_FRAMEBUFFER in staticOptions) { | |
var framebuffer = staticOptions[S_FRAMEBUFFER] | |
if (framebuffer) { | |
framebuffer = framebufferState.getFramebuffer(framebuffer) | |
check.command(framebuffer, 'invalid framebuffer object') | |
return createStaticDecl(function (env, block) { | |
var FRAMEBUFFER = env.link(framebuffer) | |
var shared = env.shared | |
block.set( | |
shared.framebuffer, | |
'.next', | |
FRAMEBUFFER) | |
var CONTEXT = shared.context | |
block.set( | |
CONTEXT, | |
'.' + S_FRAMEBUFFER_WIDTH, | |
FRAMEBUFFER + '.width') | |
block.set( | |
CONTEXT, | |
'.' + S_FRAMEBUFFER_HEIGHT, | |
FRAMEBUFFER + '.height') | |
return FRAMEBUFFER | |
}) | |
} else { | |
return createStaticDecl(function (env, scope) { | |
var shared = env.shared | |
scope.set( | |
shared.framebuffer, | |
'.next', | |
'null') | |
var CONTEXT = shared.context | |
scope.set( | |
CONTEXT, | |
'.' + S_FRAMEBUFFER_WIDTH, | |
CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH) | |
scope.set( | |
CONTEXT, | |
'.' + S_FRAMEBUFFER_HEIGHT, | |
CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT) | |
return 'null' | |
}) | |
} | |
} else if (S_FRAMEBUFFER in dynamicOptions) { | |
var dyn = dynamicOptions[S_FRAMEBUFFER] | |
return createDynamicDecl(dyn, function (env, scope) { | |
var FRAMEBUFFER_FUNC = env.invoke(scope, dyn) | |
var shared = env.shared | |
var FRAMEBUFFER_STATE = shared.framebuffer | |
var FRAMEBUFFER = scope.def( | |
FRAMEBUFFER_STATE, '.getFramebuffer(', FRAMEBUFFER_FUNC, ')') | |
check.optional(function () { | |
env.assert(scope, | |
'!' + FRAMEBUFFER_FUNC + '||' + FRAMEBUFFER, | |
'invalid framebuffer object') | |
}) | |
scope.set( | |
FRAMEBUFFER_STATE, | |
'.next', | |
FRAMEBUFFER) | |
var CONTEXT = shared.context | |
scope.set( | |
CONTEXT, | |
'.' + S_FRAMEBUFFER_WIDTH, | |
FRAMEBUFFER + '?' + FRAMEBUFFER + '.width:' + | |
CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH) | |
scope.set( | |
CONTEXT, | |
'.' + S_FRAMEBUFFER_HEIGHT, | |
FRAMEBUFFER + | |
'?' + FRAMEBUFFER + '.height:' + | |
CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT) | |
return FRAMEBUFFER | |
}) | |
} else { | |
return null | |
} | |
} | |
function parseViewportScissor (options, framebuffer) { | |
var staticOptions = options.static | |
var dynamicOptions = options.dynamic | |
function parseBox (param) { | |
if (param in staticOptions) { | |
var box = staticOptions[param] | |
check.commandType(box, 'object', 'invalid ' + param) | |
var isStatic = true | |
var x = box.x | 0 | |
var y = box.y | 0 | |
check.command(x >= 0 && y >= 0, 'invalid ' + param) | |
var w, h | |
if ('width' in box) { | |
w = box.width | 0 | |
check.command(w > 0, 'invalid ' + param) | |
} else { | |
isStatic = false | |
} | |
if ('height' in box) { | |
h = box.height | 0 | |
check.command(h > 0, 'invalid ' + param) | |
} else { | |
isStatic = false | |
} | |
return new Declaration( | |
!isStatic && framebuffer && framebuffer.thisDep, | |
!isStatic && framebuffer && framebuffer.contextDep, | |
!isStatic && framebuffer && framebuffer.propDep, | |
function (env, scope) { | |
var CONTEXT = env.shared.context | |
var BOX_W = w | |
if (!('width' in box)) { | |
BOX_W = scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', x) | |
} else { | |
check.command(w > 0, 'invalid ' + param) | |
} | |
var BOX_H = h | |
if (!('height' in box)) { | |
BOX_H = scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', y) | |
} else { | |
check.command(h > 0, 'invalid ' + param) | |
} | |
return [x, y, BOX_W, BOX_H] | |
}) | |
} else if (param in dynamicOptions) { | |
var dynBox = dynamicOptions[param] | |
var result = createDynamicDecl(dynBox, function (env, scope) { | |
var BOX = env.invoke(scope, dynBox) | |
check.optional(function () { | |
env.assert(scope, | |
BOX + '&&typeof ' + BOX + '==="object"', | |
'invalid ' + param) | |
}) | |
var CONTEXT = env.shared.context | |
var BOX_X = scope.def(BOX, '.x|0') | |
var BOX_Y = scope.def(BOX, '.y|0') | |
var BOX_W = scope.def( | |
'"width" in ', BOX, '?', BOX, '.width|0:', | |
'(', CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', BOX_X, ')') | |
var BOX_H = scope.def( | |
'"height" in ', BOX, '?', BOX, '.height|0:', | |
'(', CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', BOX_Y, ')') | |
check.optional(function () { | |
env.assert(scope, | |
BOX_X + '>=0&&' + | |
BOX_Y + '>=0&&' + | |
BOX_W + '>0&&' + | |
BOX_H + '>0', | |
'invalid ' + param) | |
}) | |
return [BOX_X, BOX_Y, BOX_W, BOX_H] | |
}) | |
if (framebuffer) { | |
result.thisDep = result.thisDep || framebuffer.thisDep | |
result.contextDep = result.contextDep || framebuffer.contextDep | |
result.propDep = result.propDep || framebuffer.propDep | |
} | |
return result | |
} else if (framebuffer) { | |
return new Declaration( | |
framebuffer.thisDep, | |
framebuffer.contextDep, | |
framebuffer.propDep, | |
function (env, scope) { | |
var CONTEXT = env.shared.context | |
return [ | |
0, 0, | |
scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH), | |
scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT)] | |
}) | |
} else { | |
return null | |
} | |
} | |
var viewport = parseBox(S_VIEWPORT) | |
if (viewport) { | |
var prevViewport = viewport | |
viewport = new Declaration( | |
viewport.thisDep, | |
viewport.contextDep, | |
viewport.propDep, | |
function (env, scope) { | |
var VIEWPORT = prevViewport.append(env, scope) | |
var CONTEXT = env.shared.context | |
scope.set( | |
CONTEXT, | |
'.' + S_VIEWPORT_WIDTH, | |
VIEWPORT[2]) | |
scope.set( | |
CONTEXT, | |
'.' + S_VIEWPORT_HEIGHT, | |
VIEWPORT[3]) | |
return VIEWPORT | |
}) | |
} | |
return { | |
viewport: viewport, | |
scissor_box: parseBox(S_SCISSOR_BOX) | |
} | |
} | |
function parseProgram (options) { | |
var staticOptions = options.static | |
var dynamicOptions = options.dynamic | |
function parseShader (name) { | |
if (name in staticOptions) { | |
var id = stringStore.id(staticOptions[name]) | |
check.optional(function () { | |
shaderState.shader(shaderType[name], id, check.guessCommand()) | |
}) | |
var result = createStaticDecl(function () { | |
return id | |
}) | |
result.id = id | |
return result | |
} else if (name in dynamicOptions) { | |
var dyn = dynamicOptions[name] | |
return createDynamicDecl(dyn, function (env, scope) { | |
var str = env.invoke(scope, dyn) | |
var id = scope.def(env.shared.strings, '.id(', str, ')') | |
check.optional(function () { | |
scope( | |
env.shared.shader, '.shader(', | |
shaderType[name], ',', | |
id, ',', | |
env.command, ');') | |
}) | |
return id | |
}) | |
} | |
return null | |
} | |
var frag = parseShader(S_FRAG) | |
var vert = parseShader(S_VERT) | |
var program = null | |
var progVar | |
if (isStatic(frag) && isStatic(vert)) { | |
program = shaderState.program(vert.id, frag.id) | |
progVar = createStaticDecl(function (env, scope) { | |
return env.link(program) | |
}) | |
} else { | |
progVar = new Declaration( | |
(frag && frag.thisDep) || (vert && vert.thisDep), | |
(frag && frag.contextDep) || (vert && vert.contextDep), | |
(frag && frag.propDep) || (vert && vert.propDep), | |
function (env, scope) { | |
var SHADER_STATE = env.shared.shader | |
var fragId | |
if (frag) { | |
fragId = frag.append(env, scope) | |
} else { | |
fragId = scope.def(SHADER_STATE, '.', S_FRAG) | |
} | |
var vertId | |
if (vert) { | |
vertId = vert.append(env, scope) | |
} else { | |
vertId = scope.def(SHADER_STATE, '.', S_VERT) | |
} | |
var progDef = SHADER_STATE + '.program(' + vertId + ',' + fragId | |
check.optional(function () { | |
progDef += ',' + env.command | |
}) | |
return scope.def(progDef + ')') | |
}) | |
} | |
return { | |
frag: frag, | |
vert: vert, | |
progVar: progVar, | |
program: program | |
} | |
} | |
function parseDraw (options) { | |
var staticOptions = options.static | |
var dynamicOptions = options.dynamic | |
function parseElements () { | |
if (S_ELEMENTS in staticOptions) { | |
var elements = staticOptions[S_ELEMENTS] | |
if (isBufferArgs(elements)) { | |
elements = elementState.getElements(elementState.create(elements)) | |
} else if (elements) { | |
elements = elementState.getElements(elements) | |
check.command(elements, 'invalid elements') | |
} | |
var result = createStaticDecl(function (env, scope) { | |
if (elements) { | |
var result = env.link(elements) | |
env.ELEMENTS = result | |
return result | |
} | |
env.ELEMENTS = null | |
return null | |
}) | |
result.value = elements | |
return result | |
} else if (S_ELEMENTS in dynamicOptions) { | |
var dyn = dynamicOptions[S_ELEMENTS] | |
return createDynamicDecl(dyn, function (env, scope) { | |
var shared = env.shared | |
var IS_BUFFER_ARGS = shared.isBufferArgs | |
var ELEMENT_STATE = shared.elements | |
var elementDefn = env.invoke(scope, dyn) | |
var elements = scope.def('null') | |
var elementStream = scope.def(IS_BUFFER_ARGS, '(', elementDefn, ')') | |
var ifte = env.cond(elementStream) | |
.then(elements, '=', ELEMENT_STATE, '.createStream(', elementDefn, ');') | |
.else(elements, '=', ELEMENT_STATE, '.getElements(', elementDefn, ');') | |
check.optional(function () { | |
env.assert(ifte.else, | |
'!' + elementDefn + '||' + elements, | |
'invalid elements') | |
}) | |
scope.entry(ifte) | |
scope.exit( | |
env.cond(elementStream) | |
.then(ELEMENT_STATE, '.destroyStream(', elements, ');')) | |
env.ELEMENTS = elements | |
return elements | |
}) | |
} | |
return null | |
} | |
var elements = parseElements() | |
function parsePrimitive () { | |
if (S_PRIMITIVE in staticOptions) { | |
var primitive = staticOptions[S_PRIMITIVE] | |
check.commandParameter(primitive, primTypes, 'invalid primitve') | |
return createStaticDecl(function (env, scope) { | |
return primTypes[primitive] | |
}) | |
} else if (S_PRIMITIVE in dynamicOptions) { | |
var dynPrimitive = dynamicOptions[S_PRIMITIVE] | |
return createDynamicDecl(dynPrimitive, function (env, scope) { | |
var PRIM_TYPES = env.constants.primTypes | |
var prim = env.invoke(scope, dynPrimitive) | |
check.optional(function () { | |
env.assert(scope, | |
prim + ' in ' + PRIM_TYPES, | |
'invalid primitive, must be one of ' + Object.keys(primTypes)) | |
}) | |
return scope.def(PRIM_TYPES, '[', prim, ']') | |
}) | |
} else if (elements) { | |
if (isStatic(elements)) { | |
if (elements.value) { | |
return createStaticDecl(function (env, scope) { | |
return scope.def(env.ELEMENTS, '.primType') | |
}) | |
} else { | |
return createStaticDecl(function () { | |
return GL_TRIANGLES | |
}) | |
} | |
} else { | |
return new Declaration( | |
elements.thisDep, | |
elements.contextDep, | |
elements.propDep, | |
function (env, scope) { | |
var elements = env.ELEMENTS | |
return scope.def(elements, '?', elements, '.primType:', GL_TRIANGLES) | |
}) | |
} | |
} | |
return null | |
} | |
function parseParam (param, isOffset) { | |
if (param in staticOptions) { | |
var value = staticOptions[param] | 0 | |
check.command(!isOffset || value >= 0, 'invalid ' + param) | |
return createStaticDecl(function (env, scope) { | |
if (isOffset) { | |
env.OFFSET = value | |
} | |
return value | |
}) | |
} else if (param in dynamicOptions) { | |
var dynValue = dynamicOptions[param] | |
return createDynamicDecl(dynValue, function (env, scope) { | |
var result = env.invoke(scope, dynValue) | |
if (isOffset) { | |
env.OFFSET = result | |
check.optional(function () { | |
env.assert(scope, | |
result + '>=0', | |
'invalid ' + param) | |
}) | |
} | |
return result | |
}) | |
} else if (isOffset && elements) { | |
return createStaticDecl(function (env, scope) { | |
env.OFFSET = '0' | |
return 0 | |
}) | |
} | |
return null | |
} | |
var OFFSET = parseParam(S_OFFSET, true) | |
function parseVertCount () { | |
if (S_COUNT in staticOptions) { | |
var count = staticOptions[S_COUNT] | 0 | |
check.command( | |
typeof count === 'number' && count >= 0, 'invalid vertex count') | |
return createStaticDecl(function () { | |
return count | |
}) | |
} else if (S_COUNT in dynamicOptions) { | |
var dynCount = dynamicOptions[S_COUNT] | |
return createDynamicDecl(dynCount, function (env, scope) { | |
var result = env.invoke(scope, dynCount) | |
check.optional(function () { | |
env.assert(scope, | |
'typeof ' + result + '==="number"&&' + | |
result + '>=0&&' + | |
result + '===(' + result + '|0)', | |
'invalid vertex count') | |
}) | |
return result | |
}) | |
} else if (elements) { | |
if (isStatic(elements)) { | |
if (elements) { | |
if (OFFSET) { | |
return new Declaration( | |
OFFSET.thisDep, | |
OFFSET.contextDep, | |
OFFSET.propDep, | |
function (env, scope) { | |
var result = scope.def( | |
env.ELEMENTS, '.vertCount-', env.OFFSET) | |
check.optional(function () { | |
env.assert(scope, | |
result + '>=0', | |
'invalid vertex offset/element buffer too small') | |
}) | |
return result | |
}) | |
} else { | |
return createStaticDecl(function (env, scope) { | |
return scope.def(env.ELEMENTS, '.vertCount') | |
}) | |
} | |
} else { | |
var result = createStaticDecl(function () { | |
return -1 | |
}) | |
check.optional(function () { | |
result.MISSING = true | |
}) | |
return result | |
} | |
} else { | |
var variable = new Declaration( | |
elements.thisDep || OFFSET.thisDep, | |
elements.contextDep || OFFSET.contextDep, | |
elements.propDep || OFFSET.propDep, | |
function (env, scope) { | |
var elements = env.ELEMENTS | |
if (env.OFFSET) { | |
return scope.def(elements, '?', elements, '.vertCount-', | |
env.OFFSET, ':-1') | |
} | |
return scope.def(elements, '?', elements, '.vertCount:-1') | |
}) | |
check.optional(function () { | |
variable.DYNAMIC = true | |
}) | |
return variable | |
} | |
} | |
return null | |
} | |
return { | |
elements: elements, | |
primitive: parsePrimitive(), | |
count: parseVertCount(), | |
instances: parseParam(S_INSTANCES, false), | |
offset: OFFSET | |
} | |
} | |
function parseGLState (options) { | |
var staticOptions = options.static | |
var dynamicOptions = options.dynamic | |
var STATE = {} | |
GL_STATE_NAMES.forEach(function (prop) { | |
var param = propName(prop) | |
function parseParam (parseStatic, parseDynamic) { | |
if (prop in staticOptions) { | |
var value = parseStatic(staticOptions[prop]) | |
STATE[param] = createStaticDecl(function () { | |
return value | |
}) | |
} else if (prop in dynamicOptions) { | |
var dyn = dynamicOptions[prop] | |
STATE[param] = createDynamicDecl(dyn, function (env, scope) { | |
return parseDynamic(env, scope, env.invoke(scope, dyn)) | |
}) | |
} | |
} | |
switch (prop) { | |
case S_CULL_ENABLE: | |
case S_BLEND_ENABLE: | |
case S_DITHER: | |
case S_STENCIL_ENABLE: | |
case S_DEPTH_ENABLE: | |
case S_SCISSOR_ENABLE: | |
case S_POLYGON_OFFSET_ENABLE: | |
case S_SAMPLE_ALPHA: | |
case S_SAMPLE_ENABLE: | |
case S_DEPTH_MASK: | |
return parseParam( | |
function (value) { | |
check.commandType(value, 'boolean', prop) | |
return value | |
}, | |
function (env, scope, value) { | |
check.optional(function () { | |
env.assert(scope, | |
'typeof ' + value + '==="boolean"', | |
'invalid flag ' + prop) | |
}) | |
return value | |
}) | |
case S_DEPTH_FUNC: | |
return parseParam( | |
function (value) { | |
check.commandParameter(value, compareFuncs, 'invalid ' + prop) | |
return compareFuncs[value] | |
}, | |
function (env, scope, value) { | |
var COMPARE_FUNCS = env.constants.compareFuncs | |
check.optional(function () { | |
env.assert(scope, | |
value + ' in ' + COMPARE_FUNCS, | |
'invalid ' + prop + ', must be one of ' + Object.keys(compareFuncs)) | |
}) | |
return scope.def(COMPARE_FUNCS, '[', value, ']') | |
}) | |
case S_DEPTH_RANGE: | |
return parseParam( | |
function (value) { | |
check.command( | |
isArrayLike(value) && | |
value.length === 2 && | |
typeof value[0] === 'number' && | |
typeof value[1] === 'number' && | |
value[0] <= value[1], | |
'depth range is 2d array') | |
return value | |
}, | |
function (env, scope, value) { | |
check.optional(function () { | |
env.assert(scope, | |
env.shared.isArrayLike + '(' + value + ')&&' + | |
value + '.length===2&&' + | |
'typeof ' + value + '[0]==="number"&&' + | |
'typeof ' + value + '[1]==="number"&&' + | |
value + '[0]<=' + value + '[1]', | |
'depth range must be a 2d array') | |
}) | |
var Z_NEAR = scope.def('+', value, '[0]') | |
var Z_FAR = scope.def('+', value, '[1]') | |
return [Z_NEAR, Z_FAR] | |
}) | |
case S_BLEND_FUNC: | |
return parseParam( | |
function (value) { | |
check.commandType(value, 'object', 'blend.func') | |
var srcRGB = ('srcRGB' in value ? value.srcRGB : value.src) | |
var srcAlpha = ('srcAlpha' in value ? value.srcAlpha : value.src) | |
var dstRGB = ('dstRGB' in value ? value.dstRGB : value.dst) | |
var dstAlpha = ('dstAlpha' in value ? value.dstAlpha : value.dst) | |
check.commandParameter(srcRGB, blendFuncs, param + '.srcRGB') | |
check.commandParameter(srcAlpha, blendFuncs, param + '.srcAlpha') | |
check.commandParameter(dstRGB, blendFuncs, param + '.dstRGB') | |
check.commandParameter(dstAlpha, blendFuncs, param + '.dstAlpha') | |
return [ | |
blendFuncs[srcRGB], | |
blendFuncs[dstRGB], | |
blendFuncs[srcAlpha], | |
blendFuncs[dstAlpha] | |
] | |
}, | |
function (env, scope, value) { | |
var BLEND_FUNCS = env.constants.blendFuncs | |
check.optional(function () { | |
env.assert(scope, | |
value + '&&typeof ' + value + '==="object"', | |
'invalid blend func, must be an object') | |
}) | |
function read (prefix, suffix) { | |
var func = scope.def( | |
'"', prefix, suffix, '" in ', value, | |
'?', value, '.', prefix, suffix, | |
':', value, '.', prefix) | |
check.optional(function () { | |
env.assert(scope, | |
func + ' in ' + BLEND_FUNCS, | |
'invalid ' + prop + '.' + prefix + suffix + ', must be one of ' + Object.keys(blendFuncs)) | |
}) | |
return scope.def(BLEND_FUNCS, '[', func, ']') | |
} | |
var SRC_RGB = read('src', 'RGB') | |
var SRC_ALPHA = read('src', 'Alpha') | |
var DST_RGB = read('dst', 'RGB') | |
var DST_ALPHA = read('dst', 'Alpha') | |
return [SRC_RGB, DST_RGB, SRC_ALPHA, DST_ALPHA] | |
}) | |
case S_BLEND_EQUATION: | |
return parseParam( | |
function (value) { | |
if (typeof value === 'string') { | |
check.commandParameter(value, blendEquations, 'invalid ' + prop) | |
return [ | |
blendEquations[value], | |
blendEquations[value] | |
] | |
} else if (typeof value === 'object') { | |
check.commandParameter( | |
value.rgb, blendEquations, prop + '.rgb') | |
check.commandParameter( | |
value.alpha, blendEquations, prop + '.alpha') | |
return [ | |
blendEquations[value.rgb], | |
blendEquations[value.alpha] | |
] | |
} else { | |
check.commandRaise('invalid blend.equation') | |
} | |
}, | |
function (env, scope, value) { | |
var BLEND_EQUATIONS = env.constants.blendEquations | |
var RGB = scope.def() | |
var ALPHA = scope.def() | |
var ifte = env.cond('typeof ', value, '==="string"') | |
check.optional(function () { | |
function checkProp (block, name, value) { | |
env.assert(block, | |
value + ' in ' + BLEND_EQUATIONS, | |
'invalid ' + name + ', must be one of ' + Object.keys(blendEquations)) | |
} | |
checkProp(ifte.then, prop, value) | |
env.assert(ifte.else, | |
value + '&&typeof ' + value + '==="object"', | |
'invalid ' + prop) | |
checkProp(ifte.else, prop + '.rgb', value + '.rgb') | |
checkProp(ifte.else, prop + '.alpha', value + '.alpha') | |
}) | |
ifte.then( | |
RGB, '=', ALPHA, '=', BLEND_EQUATIONS, '[', value, '];') | |
ifte.else( | |
RGB, '=', BLEND_EQUATIONS, '[', value, '.rgb];', | |
ALPHA, '=', BLEND_EQUATIONS, '[', value, '.alpha];') | |
scope(ifte) | |
return [RGB, ALPHA] | |
}) | |
case S_BLEND_COLOR: | |
return parseParam( | |
function (value) { | |
check.command( | |
isArrayLike(value) && | |
value.length === 4, | |
'blend.color must be a 4d array') | |
return loop(4, function (i) { | |
return +value[i] | |
}) | |
}, | |
function (env, scope, value) { | |
check.optional(function () { | |
env.assert(scope, | |
env.shared.isArrayLike + '(' + value + ')&&' + | |
value + '.length===4', | |
'blend.color must be a 4d array') | |
}) | |
return loop(4, function (i) { | |
return scope.def('+', value, '[', i, ']') | |
}) | |
}) | |
case S_STENCIL_MASK: | |
return parseParam( | |
function (value) { | |
check.commandType(value, 'number', param) | |
return value | 0 | |
}, | |
function (env, scope, value) { | |
check.optional(function () { | |
env.assert(scope, | |
'typeof ' + value + '==="number"', | |
'invalid stencil.mask') | |
}) | |
return scope.def(value, '|0') | |
}) | |
case S_STENCIL_FUNC: | |
return parseParam( | |
function (value) { | |
check.commandType(value, 'object', param) | |
var cmp = value.cmp || 'keep' | |
var ref = value.ref || 0 | |
var mask = 'mask' in value ? value.mask : -1 | |
check.commandParameter(cmp, compareFuncs, prop + '.cmp') | |
check.commandType(ref, 'number', prop + '.ref') | |
check.commandType(mask, 'number', prop + '.mask') | |
return [ | |
compareFuncs[cmp], | |
ref, | |
mask | |
] | |
}, | |
function (env, scope, value) { | |
var COMPARE_FUNCS = env.constants.compareFuncs | |
check.optional(function () { | |
function assert () { | |
env.assert(scope, | |
Array.prototype.join.call(arguments, ''), | |
'invalid stencil.func') | |
} | |
assert(value + '&&typeof ', value, '==="object"') | |
assert('!("cmp" in ', value, ')||(', | |
value, '.cmp in ', COMPARE_FUNCS, ')') | |
}) | |
var cmp = scope.def( | |
'"cmp" in ', value, | |
'?', COMPARE_FUNCS, '[', value, '.cmp]', | |
':', GL_KEEP) | |
var ref = scope.def(value, '.ref|0') | |
var mask = scope.def( | |
'"mask" in ', value, | |
'?', value, '.mask|0:-1') | |
return [cmp, ref, mask] | |
}) | |
case S_STENCIL_OPFRONT: | |
case S_STENCIL_OPBACK: | |
return parseParam( | |
function (value) { | |
check.commandType(value, 'object', param) | |
var fail = value.fail || 'keep' | |
var zfail = value.zfail || 'keep' | |
var pass = value.pass || 'keep' | |
check.commandParameter(fail, stencilOps, prop + '.fail') | |
check.commandParameter(zfail, stencilOps, prop + '.zfail') | |
check.commandParameter(pass, stencilOps, prop + '.pass') | |
return [ | |
prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT, | |
stencilOps[fail], | |
stencilOps[zfail], | |
stencilOps[pass] | |
] | |
}, | |
function (env, scope, value) { | |
var STENCIL_OPS = env.constants.stencilOps | |
check.optional(function () { | |
env.assert(scope, | |
value + '&&typeof ' + value + '==="object"', | |
'invalid ' + prop) | |
}) | |
function read (name) { | |
check.optional(function () { | |
env.assert(scope, | |
'!("' + name + '" in ' + value + ')||' + | |
'(' + value + '.' + name + ' in ' + STENCIL_OPS + ')', | |
'invalid ' + prop + '.' + name + ', must be one of ' + Object.keys(stencilOps)) | |
}) | |
return scope.def( | |
'"', name, '" in ', value, | |
'?', STENCIL_OPS, '[', value, '.', name, ']:', | |
GL_KEEP) | |
} | |
return [ | |
prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT, | |
read('fail'), | |
read('zfail'), | |
read('pass') | |
] | |
}) | |
case S_POLYGON_OFFSET_OFFSET: | |
return parseParam( | |
function (value) { | |
check.commandType(value, 'object', param) | |
var factor = value.factor | 0 | |
var units = value.units | 0 | |
check.commandType(factor, 'number', param + '.factor') | |
check.commandType(units, 'number', param + '.units') | |
return [factor, units] | |
}, | |
function (env, scope, value) { | |
check.optional(function () { | |
env.assert(scope, | |
value + '&&typeof ' + value + '==="object"', | |
'invalid ' + prop) | |
}) | |
var FACTOR = scope.def(value, '.factor|0') | |
var UNITS = scope.def(value, '.units|0') | |
return [FACTOR, UNITS] | |
}) | |
case S_CULL_FACE: | |
return parseParam( | |
function (value) { | |
var face = 0 | |
if (value === 'front') { | |
face = GL_FRONT | |
} else if (value === 'back') { | |
face = GL_BACK | |
} | |
check.command(!!face, param) | |
return face | |
}, | |
function (env, scope, value) { | |
check.optional(function () { | |
env.assert(scope, | |
value + '==="front"||' + | |
value + '==="back"', | |
'invalid cull.face') | |
}) | |
return scope.def(value, '==="front"?', GL_FRONT, ':', GL_BACK) | |
}) | |
case S_LINE_WIDTH: | |
return parseParam( | |
function (value) { | |
check.command( | |
typeof value === 'number' && | |
value >= limits.lineWidthDims[0] && | |
value <= limits.lineWidthDims[1], | |
'invalid line width, must positive number between ' + | |
limits.lineWidthDims[0] + ' and ' + limits.lineWidthDims[1]) | |
return value | |
}, | |
function (env, scope, value) { | |
check.optional(function () { | |
env.assert(scope, | |
'typeof ' + value + '==="number"&&' + | |
value + '>=' + limits.lineWidthDims[0] + '&&' + | |
value + '<=' + limits.lineWidthDims[1], | |
'invalid line width') | |
}) | |
return value | |
}) | |
case S_FRONT_FACE: | |
return parseParam( | |
function (value) { | |
check.commandParameter(value, orientationType, param) | |
return orientationType[value] | |
}, | |
function (env, scope, value) { | |
check.optional(function () { | |
env.assert(scope, | |
value + '==="cw"||' + | |
value + '==="ccw"', | |
'invalid frontFace, must be one of cw,ccw') | |
}) | |
return scope.def(value + '==="cw"?' + GL_CW + ':' + GL_CCW) | |
}) | |
case S_COLOR_MASK: | |
return parseParam( | |
function (value) { | |
check.command( | |
isArrayLike(value) && value.length === 4, | |
'color.mask must be length 4 array') | |
return value.map(function (v) { return !!v }) | |
}, | |
function (env, scope, value) { | |
check.optional(function () { | |
env.assert(scope, | |
env.shared.isArrayLike + '(' + value + ')&&' + | |
value + '.length===4', | |
'invalid color.mask') | |
}) | |
return loop(4, function (i) { | |
return '!!' + value + '[' + i + ']' | |
}) | |
}) | |
case S_SAMPLE_COVERAGE: | |
return parseParam( | |
function (value) { | |
check.command(typeof value === 'object' && value, param) | |
var sampleValue = 'value' in value ? value.value : 1 | |
var sampleInvert = !!value.invert | |
check.command( | |
typeof sampleValue === 'number' && | |
sampleValue >= 0 && sampleValue <= 1, | |
'sample.coverage.value must be a number between 0 and 1') | |
return [sampleValue, sampleInvert] | |
}, | |
function (env, scope, value) { | |
check.optional(function () { | |
env.assert(scope, | |
value + '&&typeof ' + value + '==="object"', | |
'invalid sample.coverage') | |
}) | |
var VALUE = scope.def( | |
'"value" in ', value, '?+', value, '.value:1') | |
var INVERT = scope.def('!!', value, '.invert') | |
return [VALUE, INVERT] | |
}) | |
} | |
}) | |
return STATE | |
} | |
function parseOptions (options) { | |
var staticOptions = options.static | |
var dynamicOptions = options.dynamic | |
check.optional(function () { | |
var command = check.guessCommand() | |
var KEY_NAMES = [ | |
S_FRAMEBUFFER, | |
S_VERT, | |
S_FRAG, | |
S_ELEMENTS, | |
S_PRIMITIVE, | |
S_OFFSET, | |
S_COUNT, | |
S_INSTANCES, | |
S_PROFILE | |
].concat(GL_STATE_NAMES) | |
function checkKeys (dict) { | |
Object.keys(dict).forEach(function (key) { | |
check.command( | |
KEY_NAMES.indexOf(key) >= 0, | |
'unknown parameter "' + key + '"', | |
command) | |
}) | |
} | |
checkKeys(staticOptions) | |
checkKeys(dynamicOptions) | |
}) | |
var framebuffer = parseFramebuffer(options) | |
var viewportAndScissor = parseViewportScissor(options, framebuffer) | |
var draw = parseDraw(options) | |
var state = parseGLState(options) | |
var shader = parseProgram(options) | |
function copyBox (name) { | |
var defn = viewportAndScissor[name] | |
if (defn) { | |
state[name] = defn | |
} | |
} | |
copyBox(S_VIEWPORT) | |
copyBox(propName(S_SCISSOR_BOX)) | |
var dirty = Object.keys(state).length > 0 | |
return { | |
framebuffer: framebuffer, | |
draw: draw, | |
shader: shader, | |
state: state, | |
dirty: dirty | |
} | |
} | |
function parseUniforms (uniforms) { | |
var staticUniforms = uniforms.static | |
var dynamicUniforms = uniforms.dynamic | |
var UNIFORMS = {} | |
Object.keys(staticUniforms).forEach(function (name) { | |
var value = staticUniforms[name] | |
var result | |
if (typeof value === 'number' || | |
typeof value === 'boolean') { | |
result = createStaticDecl(function () { | |
return value | |
}) | |
} else if (typeof value === 'function') { | |
var reglType = value._reglType | |
if (reglType === 'texture2d' || | |
reglType === 'textureCube') { | |
result = createStaticDecl(function (env) { | |
return env.link(value) | |
}) | |
} else if (reglType === 'framebuffer' || | |
reglType === 'framebufferCube') { | |
check(value.color.length > 0, | |
'missing color attachment for framebuffer sent to uniform "' + name + '"') | |
result = createStaticDecl(function (env) { | |
return env.link(value.color[0]) | |
}) | |
} else { | |
check.raise('invalid data for uniform "' + name + '"') | |
} | |
} else if (isArrayLike(value)) { | |
result = createStaticDecl(function (env) { | |
var ITEM = env.global.def('[', | |
loop(value.length, function (i) { | |
check.command( | |
typeof value[i] === 'number' || | |
typeof value[i] === 'boolean', | |
'invalid uniform ' + name) | |
return value[i] | |
}), ']') | |
return ITEM | |
}) | |
} else { | |
check.commandRaise('invalid or missing data for uniform "' + name + '"') | |
} | |
result.value = value | |
UNIFORMS[name] = result | |
}) | |
Object.keys(dynamicUniforms).forEach(function (key) { | |
var dyn = dynamicUniforms[key] | |
UNIFORMS[key] = createDynamicDecl(dyn, function (env, scope) { | |
return env.invoke(scope, dyn) | |
}) | |
}) | |
return UNIFORMS | |
} | |
function parseAttributes (attributes) { | |
var staticAttributes = attributes.static | |
var dynamicAttributes = attributes.dynamic | |
var attributeDefs = {} | |
Object.keys(staticAttributes).forEach(function (attribute) { | |
var value = staticAttributes[attribute] | |
var id = stringStore.id(attribute) | |
var record = new AttributeRecord() | |
if (isBufferArgs(value)) { | |
record.state = ATTRIB_STATE_POINTER | |
record.buffer = bufferState.getBuffer( | |
bufferState.create(value, GL_ARRAY_BUFFER, false)) | |
record.type = record.buffer.dtype | |
} else { | |
var buffer = bufferState.getBuffer(value) | |
if (buffer) { | |
record.state = ATTRIB_STATE_POINTER | |
record.buffer = buffer | |
record.type = buffer.dtype | |
} else { | |
check.command(typeof value === 'object' && value, | |
'invalid data for attribute ' + attribute) | |
if (value.constant) { | |
var constant = value.constant | |
record.buffer = 'null' | |
record.state = ATTRIB_STATE_CONSTANT | |
if (typeof constant === 'number') { | |
record.x = constant | |
} else { | |
check.command( | |
isArrayLike(constant) && | |
constant.length > 0 && | |
constant.length <= 4, | |
'invalid constant for attribute ' + attribute) | |
CUTE_COMPONENTS.forEach(function (c, i) { | |
if (i < constant.length) { | |
record[c] = constant[i] | |
} | |
}) | |
} | |
} else { | |
buffer = bufferState.getBuffer(value.buffer) | |
check.command(!!buffer, 'missing buffer for attribute "' + attribute + '"') | |
var offset = value.offset | 0 | |
check.command(offset >= 0, | |
'invalid offset for attribute "' + attribute + '"') | |
var stride = value.stride | 0 | |
check.command(stride >= 0 && stride < 256, | |
'invalid stride for attribute "' + attribute + '", must be integer betweeen [0, 255]') | |
var size = value.size | 0 | |
check.command(!('size' in value) || (size > 0 && size <= 4), | |
'invalid size for attribute "' + attribute + '", must be 1,2,3,4') | |
var normalized = !!value.normalized | |
var type = 0 | |
if ('type' in value) { | |
check.commandParameter( | |
value.type, glTypes, | |
'invalid type for attribute ' + attribute) | |
type = glTypes[value.type] | |
} | |
var divisor = value.divisor | 0 | |
if ('divisor' in value) { | |
check.command(divisor === 0 || extInstancing, | |
'cannot specify divisor for attribute "' + attribute + '", instancing not supported') | |
check.command(divisor >= 0, | |
'invalid divisor for attribute "' + attribute + '"') | |
} | |
check.optional(function () { | |
var command = check.guessCommand() | |
var VALID_KEYS = [ | |
'buffer', | |
'offset', | |
'divisor', | |
'normalized', | |
'type', | |
'size', | |
'stride' | |
] | |
Object.keys(value).forEach(function (prop) { | |
check.command( | |
VALID_KEYS.indexOf(prop) >= 0, | |
'unknown parameter "' + prop + '" for attribute pointer "' + attribute + '" (valid parameters are ' + VALID_KEYS + ')', | |
command) | |
}) | |
}) | |
record.buffer = buffer | |
record.state = ATTRIB_STATE_POINTER | |
record.size = size | |
record.normalized = normalized | |
record.type = type || buffer.dtype | |
record.offset = offset | |
record.stride = stride | |
record.divisor = divisor | |
} | |
} | |
} | |
attributeDefs[attribute] = createStaticDecl(function (env, scope) { | |
var cache = env.attribCache | |
if (id in cache) { | |
return cache[id] | |
} | |
var result = { | |
isStream: false | |
} | |
Object.keys(record).forEach(function (key) { | |
result[key] = record[key] | |
}) | |
if (record.buffer) { | |
result.buffer = env.link(record.buffer) | |
} | |
cache[id] = result | |
return result | |
}) | |
}) | |
Object.keys(dynamicAttributes).forEach(function (attribute) { | |
var dyn = dynamicAttributes[attribute] | |
function appendAttributeCode (env, block) { | |
var VALUE = env.invoke(block, dyn) | |
var shared = env.shared | |
var IS_BUFFER_ARGS = shared.isBufferArgs | |
var BUFFER_STATE = shared.buffer | |
// Perform validation on attribute | |
check.optional(function () { | |
env.assert(block, | |
VALUE + '&&(typeof ' + VALUE + '==="object"||typeof ' + | |
VALUE + '==="function")&&(' + | |
IS_BUFFER_ARGS + '(' + VALUE + ')||' + | |
BUFFER_STATE + '.getBuffer(' + VALUE + ')||' + | |
BUFFER_STATE + '.getBuffer(' + VALUE + '.buffer)||' + | |
'("constant" in ' + VALUE + | |
'&&(typeof ' + VALUE + '.constant==="number"||' + | |
shared.isArrayLike + '(' + VALUE + '.constant))))', | |
'invalid dynamic attribute "' + attribute + '"') | |
}) | |
// allocate names for result | |
var result = { | |
isStream: block.def(false) | |
} | |
var defaultRecord = new AttributeRecord() | |
defaultRecord.state = ATTRIB_STATE_POINTER | |
Object.keys(defaultRecord).forEach(function (key) { | |
result[key] = block.def('' + defaultRecord[key]) | |
}) | |
var BUFFER = result.buffer | |
var TYPE = result.type | |
block( | |
'if(', IS_BUFFER_ARGS, '(', VALUE, ')){', | |
result.isStream, '=true;', | |
BUFFER, '=', BUFFER_STATE, '.createStream(', GL_ARRAY_BUFFER, ',', VALUE, ');', | |
TYPE, '=', BUFFER, '.dtype;', | |
'}else{', | |
BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, ');', | |
'if(', BUFFER, '){', | |
TYPE, '=', BUFFER, '.dtype;', | |
'}else if("constant" in ', VALUE, '){', | |
result.state, '=', ATTRIB_STATE_CONSTANT, ';', | |
'if(typeof ' + VALUE + '.constant === "number"){', | |
result[CUTE_COMPONENTS[0]], '=', VALUE, '.constant;', | |
CUTE_COMPONENTS.slice(1).map(function (n) { | |
return result[n] | |
}).join('='), '=0;', | |
'}else{', | |
CUTE_COMPONENTS.map(function (name, i) { | |
return ( | |
result[name] + '=' + VALUE + '.constant.length>=' + i + | |
'?' + VALUE + '.constant[' + i + ']:0;' | |
) | |
}).join(''), | |
'}}else{', | |
BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, '.buffer);', | |
TYPE, '="type" in ', VALUE, '?', | |
shared.glTypes, '[', VALUE, '.type]:', BUFFER, '.dtype;', | |
result.normalized, '=!!', VALUE, '.normalized;') | |
function emitReadRecord (name) { | |
block(result[name], '=', VALUE, '.', name, '|0;') | |
} | |
emitReadRecord('size') | |
emitReadRecord('offset') | |
emitReadRecord('stride') | |
emitReadRecord('divisor') | |
block('}}') | |
block.exit( | |
'if(', result.isStream, '){', | |
BUFFER_STATE, '.destroyStream(', BUFFER, ');', | |
'}') | |
return result | |
} | |
attributeDefs[attribute] = createDynamicDecl(dyn, appendAttributeCode) | |
}) | |
return attributeDefs | |
} | |
function parseContext (context) { | |
var staticContext = context.static | |
var dynamicContext = context.dynamic | |
var result = {} | |
Object.keys(staticContext).forEach(function (name) { | |
var value = staticContext[name] | |
result[name] = createStaticDecl(function (env, scope) { | |
if (typeof value === 'number' || typeof value === 'boolean') { | |
return '' + value | |
} else { | |
return env.link(value) | |
} | |
}) | |
}) | |
Object.keys(dynamicContext).forEach(function (name) { | |
var dyn = dynamicContext[name] | |
result[name] = createDynamicDecl(dyn, function (env, scope) { | |
return env.invoke(scope, dyn) | |
}) | |
}) | |
return result | |
} | |
function parseArguments (options, attributes, uniforms, context) { | |
var result = parseOptions(options) | |
result.profile = parseProfile(options) | |
result.uniforms = parseUniforms(uniforms) | |
result.attributes = parseAttributes(attributes) | |
result.context = parseContext(context) | |
return result | |
} | |
// =================================================== | |
// =================================================== | |
// COMMON UPDATE FUNCTIONS | |
// =================================================== | |
// =================================================== | |
function emitContext (env, scope, context) { | |
var shared = env.shared | |
var CONTEXT = shared.context | |
var contextEnter = env.scope() | |
Object.keys(context).forEach(function (name) { | |
scope.save(CONTEXT, '.' + name) | |
var defn = context[name] | |
contextEnter(CONTEXT, '.', name, '=', defn.append(env, scope), ';') | |
}) | |
scope(contextEnter) | |
} | |
// =================================================== | |
// =================================================== | |
// COMMON DRAWING FUNCTIONS | |
// =================================================== | |
// =================================================== | |
function emitPollFramebuffer (env, scope, framebuffer, skipCheck) { | |
var shared = env.shared | |
var GL = shared.gl | |
var FRAMEBUFFER_STATE = shared.framebuffer | |
var EXT_DRAW_BUFFERS | |
if (extDrawBuffers) { | |
EXT_DRAW_BUFFERS = scope.def(shared.extensions, '.webgl_draw_buffers') | |
} | |
var constants = env.constants | |
var DRAW_BUFFERS = constants.drawBuffer | |
var BACK_BUFFER = constants.backBuffer | |
var NEXT | |
if (framebuffer) { | |
NEXT = framebuffer.append(env, scope) | |
} else { | |
NEXT = scope.def(FRAMEBUFFER_STATE, '.next') | |
} | |
if (!skipCheck) { | |
scope('if(', NEXT, '!==', FRAMEBUFFER_STATE, '.cur){') | |
} | |
scope( | |
'if(', NEXT, '){', | |
GL, '.bindFramebuffer(', GL_FRAMEBUFFER, ',', NEXT, '.framebuffer);') | |
if (extDrawBuffers) { | |
scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(', | |
DRAW_BUFFERS, '[', NEXT, '.colorAttachments.length]);') | |
} | |
scope('}else{', | |
GL, '.bindFramebuffer(', GL_FRAMEBUFFER, ',null);') | |
if (extDrawBuffers) { | |
scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(', BACK_BUFFER, ');') | |
} | |
scope( | |
'}', | |
FRAMEBUFFER_STATE, '.cur=', NEXT, ';') | |
if (!skipCheck) { | |
scope('}') | |
} | |
} | |
function emitPollState (env, scope, args) { | |
var shared = env.shared | |
var GL = shared.gl | |
var CURRENT_VARS = env.current | |
var NEXT_VARS = env.next | |
var CURRENT_STATE = shared.current | |
var NEXT_STATE = shared.next | |
var block = env.cond(CURRENT_STATE, '.dirty') | |
GL_STATE_NAMES.forEach(function (prop) { | |
var param = propName(prop) | |
if (param in args.state) { | |
return | |
} | |
var NEXT, CURRENT | |
if (param in NEXT_VARS) { | |
NEXT = NEXT_VARS[param] | |
CURRENT = CURRENT_VARS[param] | |
var parts = loop(currentState[param].length, function (i) { | |
return block.def(NEXT, '[', i, ']') | |
}) | |
block(env.cond(parts.map(function (p, i) { | |
return p + '!==' + CURRENT + '[' + i + ']' | |
}).join('||')) | |
.then( | |
GL, '.', GL_VARIABLES[param], '(', parts, ');', | |
parts.map(function (p, i) { | |
return CURRENT + '[' + i + ']=' + p | |
}).join(';'), ';')) | |
} else { | |
NEXT = block.def(NEXT_STATE, '.', param) | |
var ifte = env.cond(NEXT, '!==', CURRENT_STATE, '.', param) | |
block(ifte) | |
if (param in GL_FLAGS) { | |
ifte( | |
env.cond(NEXT) | |
.then(GL, '.enable(', GL_FLAGS[param], ');') | |
.else(GL, '.disable(', GL_FLAGS[param], ');'), | |
CURRENT_STATE, '.', param, '=', NEXT, ';') | |
} else { | |
ifte( | |
GL, '.', GL_VARIABLES[param], '(', NEXT, ');', | |
CURRENT_STATE, '.', param, '=', NEXT, ';') | |
} | |
} | |
}) | |
if (Object.keys(args.state).length === 0) { | |
block(CURRENT_STATE, '.dirty=false;') | |
} | |
scope(block) | |
} | |
function emitSetOptions (env, scope, options, filter) { | |
var shared = env.shared | |
var CURRENT_VARS = env.current | |
var CURRENT_STATE = shared.current | |
var GL = shared.gl | |
sortState(Object.keys(options)).forEach(function (param) { | |
var defn = options[param] | |
if (filter && !filter(defn)) { | |
return | |
} | |
var variable = defn.append(env, scope) | |
if (GL_FLAGS[param]) { | |
var flag = GL_FLAGS[param] | |
if (isStatic(defn)) { | |
if (variable) { | |
scope(GL, '.enable(', flag, ');') | |
} else { | |
scope(GL, '.disable(', flag, ');') | |
} | |
} else { | |
scope(env.cond(variable) | |
.then(GL, '.enable(', flag, ');') | |
.else(GL, '.disable(', flag, ');')) | |
} | |
scope(CURRENT_STATE, '.', param, '=', variable, ';') | |
} else if (isArrayLike(variable)) { | |
var CURRENT = CURRENT_VARS[param] | |
scope( | |
GL, '.', GL_VARIABLES[param], '(', variable, ');', | |
variable.map(function (v, i) { | |
return CURRENT + '[' + i + ']=' + v | |
}).join(';'), ';') | |
} else { | |
scope( | |
GL, '.', GL_VARIABLES[param], '(', variable, ');', | |
CURRENT_STATE, '.', param, '=', variable, ';') | |
} | |
}) | |
} | |
function injectExtensions (env, scope) { | |
if (extInstancing && !env.instancing) { | |
env.instancing = scope.def( | |
env.shared.extensions, '.angle_instanced_arrays') | |
} | |
} | |
function emitProfile (env, scope, args, useScope, incrementCounter) { | |
var shared = env.shared | |
var STATS = env.stats | |
var CURRENT_STATE = shared.current | |
var TIMER = shared.timer | |
var profileArg = args.profile | |
function perfCounter () { | |
if (typeof performance === 'undefined') { | |
return 'Date.now()' | |
} else { | |
return 'performance.now()' | |
} | |
} | |
var CPU_START, QUERY_COUNTER | |
function emitProfileStart (block) { | |
CPU_START = scope.def() | |
block(CPU_START, '=', perfCounter(), ';') | |
if (typeof incrementCounter === 'string') { | |
block(STATS, '.count+=', incrementCounter, ';') | |
} else { | |
block(STATS, '.count++;') | |
} | |
if (timer) { | |
if (useScope) { | |
QUERY_COUNTER = scope.def() | |
block(QUERY_COUNTER, '=', TIMER, '.getNumPendingQueries();') | |
} else { | |
block(TIMER, '.beginQuery(', STATS, ');') | |
} | |
} | |
} | |
function emitProfileEnd (block) { | |
block(STATS, '.cpuTime+=', perfCounter(), '-', CPU_START, ';') | |
if (timer) { | |
if (useScope) { | |
block(TIMER, '.pushScopeStats(', | |
QUERY_COUNTER, ',', | |
TIMER, '.getNumPendingQueries(),', | |
STATS, ');') | |
} else { | |
block(TIMER, '.endQuery();') | |
} | |
} | |
} | |
function scopeProfile (value) { | |
var prev = scope.def(CURRENT_STATE, '.profile') | |
scope(CURRENT_STATE, '.profile=', value, ';') | |
scope.exit(CURRENT_STATE, '.profile=', prev, ';') | |
} | |
var USE_PROFILE | |
if (profileArg) { | |
if (isStatic(profileArg)) { | |
if (profileArg.enable) { | |
emitProfileStart(scope) | |
emitProfileEnd(scope.exit) | |
scopeProfile('true') | |
} else { | |
scopeProfile('false') | |
} | |
return | |
} | |
USE_PROFILE = profileArg.append(env, scope) | |
scopeProfile(USE_PROFILE) | |
} else { | |
USE_PROFILE = scope.def(CURRENT_STATE, '.profile') | |
} | |
var start = env.block() | |
emitProfileStart(start) | |
scope('if(', USE_PROFILE, '){', start, '}') | |
var end = env.block() | |
emitProfileEnd(end) | |
scope.exit('if(', USE_PROFILE, '){', end, '}') | |
} | |
function emitAttributes (env, scope, args, attributes, filter) { | |
var shared = env.shared | |
function typeLength (x) { | |
switch (x) { | |
case GL_FLOAT_VEC2: | |
case GL_INT_VEC2: | |
case GL_BOOL_VEC2: | |
return 2 | |
case GL_FLOAT_VEC3: | |
case GL_INT_VEC3: | |
case GL_BOOL_VEC3: | |
return 3 | |
case GL_FLOAT_VEC4: | |
case GL_INT_VEC4: | |
case GL_BOOL_VEC4: | |
return 4 | |
default: | |
return 1 | |
} | |
} | |
function emitBindAttribute (ATTRIBUTE, size, record) { | |
var GL = shared.gl | |
var LOCATION = scope.def(ATTRIBUTE, '.location') | |
var BINDING = scope.def(shared.attributes, '[', LOCATION, ']') | |
var STATE = record.state | |
var BUFFER = record.buffer | |
var CONST_COMPONENTS = [ | |
record.x, | |
record.y, | |
record.z, | |
record.w | |
] | |
var COMMON_KEYS = [ | |
'buffer', | |
'normalized', | |
'offset', | |
'stride' | |
] | |
function emitBuffer () { | |
scope( | |
'if(!', BINDING, '.buffer){', | |
GL, '.enableVertexAttribArray(', LOCATION, ');}') | |
var TYPE = record.type | |
var SIZE | |
if (!record.size) { | |
SIZE = size | |
} else { | |
SIZE = scope.def(record.size, '||', size) | |
} | |
scope('if(', | |
BINDING, '.type!==', TYPE, '||', | |
BINDING, '.size!==', SIZE, '||', | |
COMMON_KEYS.map(function (key) { | |
return BINDING + '.' + key + '!==' + record[key] | |
}).join('||'), | |
'){', | |
GL, '.bindBuffer(', GL_ARRAY_BUFFER, ',', BUFFER, '.buffer);', | |
GL, '.vertexAttribPointer(', [ | |
LOCATION, | |
SIZE, | |
TYPE, | |
record.normalized, | |
record.stride, | |
record.offset | |
], ');', | |
BINDING, '.type=', TYPE, ';', | |
BINDING, '.size=', SIZE, ';', | |
COMMON_KEYS.map(function (key) { | |
return BINDING + '.' + key + '=' + record[key] + ';' | |
}).join(''), | |
'}') | |
if (extInstancing) { | |
var DIVISOR = record.divisor | |
scope( | |
'if(', BINDING, '.divisor!==', DIVISOR, '){', | |
env.instancing, '.vertexAttribDivisorANGLE(', [LOCATION, DIVISOR], ');', | |
BINDING, '.divisor=', DIVISOR, ';}') | |
} | |
} | |
function emitConstant () { | |
scope( | |
'if(', BINDING, '.buffer){', | |
GL, '.disableVertexAttribArray(', LOCATION, ');', | |
'}if(', CUTE_COMPONENTS.map(function (c, i) { | |
return BINDING + '.' + c + '!==' + CONST_COMPONENTS[i] | |
}).join('||'), '){', | |
GL, '.vertexAttrib4f(', LOCATION, ',', CONST_COMPONENTS, ');', | |
CUTE_COMPONENTS.map(function (c, i) { | |
return BINDING + '.' + c + '=' + CONST_COMPONENTS[i] + ';' | |
}).join(''), | |
'}') | |
} | |
if (STATE === ATTRIB_STATE_POINTER) { | |
emitBuffer() | |
} else if (STATE === ATTRIB_STATE_CONSTANT) { | |
emitConstant() | |
} else { | |
scope('if(', STATE, '===', ATTRIB_STATE_POINTER, '){') | |
emitBuffer() | |
scope('}else{') | |
emitConstant() | |
scope('}') | |
} | |
} | |
attributes.forEach(function (attribute) { | |
var name = attribute.name | |
var arg = args.attributes[name] | |
var record | |
if (arg) { | |
if (!filter(arg)) { | |
return | |
} | |
record = arg.append(env, scope) | |
} else { | |
if (!filter(SCOPE_DECL)) { | |
return | |
} | |
var scopeAttrib = env.scopeAttrib(name) | |
check.optional(function () { | |
env.assert(scope, | |
scopeAttrib + '.state', | |
'missing attribute ' + name) | |
}) | |
record = {} | |
Object.keys(new AttributeRecord()).forEach(function (key) { | |
record[key] = scope.def(scopeAttrib, '.', key) | |
}) | |
} | |
emitBindAttribute( | |
env.link(attribute), typeLength(attribute.info.type), record) | |
}) | |
} | |
function emitUniforms (env, scope, args, uniforms, filter) { | |
var shared = env.shared | |
var GL = shared.gl | |
var infix | |
for (var i = 0; i < uniforms.length; ++i) { | |
var uniform = uniforms[i] | |
var name = uniform.name | |
var type = uniform.info.type | |
var arg = args.uniforms[name] | |
var UNIFORM = env.link(uniform) | |
var LOCATION = UNIFORM + '.location' | |
var VALUE | |
if (arg) { | |
if (!filter(arg)) { | |
continue | |
} | |
if (isStatic(arg)) { | |
var value = arg.value | |
check.command( | |
value !== null && typeof value !== 'undefined', | |
'missing uniform "' + name + '"') | |
if (type === GL_SAMPLER_2D || type === GL_SAMPLER_CUBE) { | |
check.command( | |
typeof value === 'function' && | |
((type === GL_SAMPLER_2D && | |
(value._reglType === 'texture2d' || | |
value._reglType === 'framebuffer')) || | |
(type === GL_SAMPLER_CUBE && | |
(value._reglType === 'textureCube' || | |
value._reglType === 'framebufferCube'))), | |
'invalid texture for uniform ' + name) | |
var TEX_VALUE = env.link(value._texture || value.color[0]._texture) | |
scope(GL, '.uniform1i(', LOCATION, ',', TEX_VALUE + '.bind());') | |
scope.exit(TEX_VALUE, '.unbind();') | |
} else if ( | |
type === GL_FLOAT_MAT2 || | |
type === GL_FLOAT_MAT3 || | |
type === GL_FLOAT_MAT4) { | |
check.optional(function () { | |
check.command(isArrayLike(value), | |
'invalid matrix for uniform ' + name) | |
check.command( | |
(type === GL_FLOAT_MAT2 && value.length === 4) || | |
(type === GL_FLOAT_MAT3 && value.length === 9) || | |
(type === GL_FLOAT_MAT4 && value.length === 16), | |
'invalid length for matrix uniform ' + name) | |
}) | |
var MAT_VALUE = env.global.def('new Float32Array([' + | |
Array.prototype.slice.call(value) + '])') | |
var dim = 2 | |
if (type === GL_FLOAT_MAT3) { | |
dim = 3 | |
} else if (type === GL_FLOAT_MAT4) { | |
dim = 4 | |
} | |
scope( | |
GL, '.uniformMatrix', dim, 'fv(', | |
LOCATION, ',false,', MAT_VALUE, ');') | |
} else { | |
switch (type) { | |
case GL_FLOAT: | |
check.commandType(value, 'number', 'uniform ' + name) | |
infix = '1f' | |
break | |
case GL_FLOAT_VEC2: | |
check.command( | |
isArrayLike(value) && value.length === 2, | |
'uniform ' + name) | |
infix = '2f' | |
break | |
case GL_FLOAT_VEC3: | |
check.command( | |
isArrayLike(value) && value.length === 3, | |
'uniform ' + name) | |
infix = '3f' | |
break | |
case GL_FLOAT_VEC4: | |
check.command( | |
isArrayLike(value) && value.length === 4, | |
'uniform ' + name) | |
infix = '4f' | |
break | |
case GL_BOOL: | |
check.commandType(value, 'boolean', 'uniform ' + name) | |
infix = '1i' | |
break | |
case GL_INT: | |
check.commandType(value, 'number', 'uniform ' + name) | |
infix = '1i' | |
break | |
case GL_BOOL_VEC2: | |
check.command( | |
isArrayLike(value) && value.length === 2, | |
'uniform ' + name) | |
infix = '2i' | |
break | |
case GL_INT_VEC2: | |
check.command( | |
isArrayLike(value) && value.length === 2, | |
'uniform ' + name) | |
infix = '2i' | |
break | |
case GL_BOOL_VEC3: | |
check.command( | |
isArrayLike(value) && value.length === 3, | |
'uniform ' + name) | |
infix = '3i' | |
break | |
case GL_INT_VEC3: | |
check.command( | |
isArrayLike(value) && value.length === 3, | |
'uniform ' + name) | |
infix = '3i' | |
break | |
case GL_BOOL_VEC4: | |
check.command( | |
isArrayLike(value) && value.length === 4, | |
'uniform ' + name) | |
infix = '4i' | |
break | |
case GL_INT_VEC4: | |
check.command( | |
isArrayLike(value) && value.length === 4, | |
'uniform ' + name) | |
infix = '4i' | |
break | |
} | |
scope(GL, '.uniform', infix, '(', LOCATION, ',', | |
isArrayLike(value) ? Array.prototype.slice.call(value) : value, | |
');') | |
} | |
continue | |
} else { | |
VALUE = arg.append(env, scope) | |
} | |
} else { | |
if (!filter(SCOPE_DECL)) { | |
continue | |
} | |
VALUE = scope.def(shared.uniforms, '[', stringStore.id(name), ']') | |
} | |
if (type === GL_SAMPLER_2D) { | |
scope( | |
'if(', VALUE, '&&', VALUE, '._reglType==="framebuffer"){', | |
VALUE, '=', VALUE, '.color[0];', | |
'}') | |
} else if (type === GL_SAMPLER_CUBE) { | |
scope( | |
'if(', VALUE, '&&', VALUE, '._reglType==="framebufferCube"){', | |
VALUE, '=', VALUE, '.color[0];', | |
'}') | |
} | |
// perform type validation | |
check.optional(function () { | |
function check (pred, message) { | |
env.assert(scope, pred, | |
'bad data for uniform "' + name + '". ' + message) | |
} | |
function checkType (type) { | |
check( | |
'typeof ' + VALUE + '==="' + type + '"', | |
'invalid type, expected ' + type) | |
} | |
function checkVector (n, type) { | |
check( | |
shared.isArrayLike + '(' + VALUE + ')&&' + VALUE + '.length===' + n, | |
'invalid vector, should have length ' + n) | |
} | |
function checkTexture (target) { | |
check( | |
'typeof ' + VALUE + '==="function"&&' + | |
VALUE + '._reglType==="texture' + | |
(target === GL_TEXTURE_2D ? '2d' : 'Cube') + '"', | |
'invalid texture type') | |
} | |
switch (type) { | |
case GL_INT: | |
checkType('number') | |
break | |
case GL_INT_VEC2: | |
checkVector(2, 'number') | |
break | |
case GL_INT_VEC3: | |
checkVector(3, 'number') | |
break | |
case GL_INT_VEC4: | |
checkVector(4, 'number') | |
break | |
case GL_FLOAT: | |
checkType('number') | |
break | |
case GL_FLOAT_VEC2: | |
checkVector(2, 'number') | |
break | |
case GL_FLOAT_VEC3: | |
checkVector(3, 'number') | |
break | |
case GL_FLOAT_VEC4: | |
checkVector(4, 'number') | |
break | |
case GL_BOOL: | |
checkType('boolean') | |
break | |
case GL_BOOL_VEC2: | |
checkVector(2, 'boolean') | |
break | |
case GL_BOOL_VEC3: | |
checkVector(3, 'boolean') | |
break | |
case GL_BOOL_VEC4: | |
checkVector(4, 'boolean') | |
break | |
case GL_FLOAT_MAT2: | |
checkVector(4, 'number') | |
break | |
case GL_FLOAT_MAT3: | |
checkVector(9, 'number') | |
break | |
case GL_FLOAT_MAT4: | |
checkVector(16, 'number') | |
break | |
case GL_SAMPLER_2D: | |
checkTexture(GL_TEXTURE_2D) | |
break | |
case GL_SAMPLER_CUBE: | |
checkTexture(GL_TEXTURE_CUBE_MAP) | |
break | |
} | |
}) | |
var unroll = 1 | |
switch (type) { | |
case GL_SAMPLER_2D: | |
case GL_SAMPLER_CUBE: | |
var TEX = scope.def(VALUE, '._texture') | |
scope(GL, '.uniform1i(', LOCATION, ',', TEX, '.bind());') | |
scope.exit(TEX, '.unbind();') | |
continue | |
case GL_INT: | |
case GL_BOOL: | |
infix = '1i' | |
break | |
case GL_INT_VEC2: | |
case GL_BOOL_VEC2: | |
infix = '2i' | |
unroll = 2 | |
break | |
case GL_INT_VEC3: | |
case GL_BOOL_VEC3: | |
infix = '3i' | |
unroll = 3 | |
break | |
case GL_INT_VEC4: | |
case GL_BOOL_VEC4: | |
infix = '4i' | |
unroll = 4 | |
break | |
case GL_FLOAT: | |
infix = '1f' | |
break | |
case GL_FLOAT_VEC2: | |
infix = '2f' | |
unroll = 2 | |
break | |
case GL_FLOAT_VEC3: | |
infix = '3f' | |
unroll = 3 | |
break | |
case GL_FLOAT_VEC4: | |
infix = '4f' | |
unroll = 4 | |
break | |
case GL_FLOAT_MAT2: | |
infix = 'Matrix2fv' | |
break | |
case GL_FLOAT_MAT3: | |
infix = 'Matrix3fv' | |
break | |
case GL_FLOAT_MAT4: | |
infix = 'Matrix4fv' | |
break | |
} | |
scope(GL, '.uniform', infix, '(', LOCATION, ',') | |
if (infix.charAt(0) === 'M') { | |
var matSize = Math.pow(type - GL_FLOAT_MAT2 + 2, 2) | |
var STORAGE = env.global.def('new Float32Array(', matSize, ')') | |
scope( | |
'false,(Array.isArray(', VALUE, ')||', VALUE, ' instanceof Float32Array)?', VALUE, ':(', | |
loop(matSize, function (i) { | |
return STORAGE + '[' + i + ']=' + VALUE + '[' + i + ']' | |
}), ',', STORAGE, ')') | |
} else if (unroll > 1) { | |
scope(loop(unroll, function (i) { | |
return VALUE + '[' + i + ']' | |
})) | |
} else { | |
scope(VALUE) | |
} | |
scope(');') | |
} | |
} | |
function emitDraw (env, outer, inner, args) { | |
var shared = env.shared | |
var GL = shared.gl | |
var DRAW_STATE = shared.draw | |
var drawOptions = args.draw | |
function emitElements () { | |
var defn = drawOptions.elements | |
var ELEMENTS | |
var scope = outer | |
if (defn) { | |
if ((defn.contextDep && args.contextDynamic) || defn.propDep) { | |
scope = inner | |
} | |
ELEMENTS = defn.append(env, scope) | |
} else { | |
ELEMENTS = scope.def(DRAW_STATE, '.', S_ELEMENTS) | |
} | |
if (ELEMENTS) { | |
scope( | |
'if(' + ELEMENTS + ')' + | |
GL + '.bindBuffer(' + GL_ELEMENT_ARRAY_BUFFER + ',' + ELEMENTS + '.buffer.buffer);') | |
} | |
return ELEMENTS | |
} | |
function emitCount () { | |
var defn = drawOptions.count | |
var COUNT | |
var scope = outer | |
if (defn) { | |
if ((defn.contextDep && args.contextDynamic) || defn.propDep) { | |
scope = inner | |
} | |
COUNT = defn.append(env, scope) | |
check.optional(function () { | |
if (defn.MISSING) { | |
env.assert(outer, 'false', 'missing vertex count') | |
} | |
if (defn.DYNAMIC) { | |
env.assert(scope, COUNT + '>=0', 'missing vertex count') | |
} | |
}) | |
} else { | |
COUNT = scope.def(DRAW_STATE, '.', S_COUNT) | |
check.optional(function () { | |
env.assert(scope, COUNT + '>=0', 'missing vertex count') | |
}) | |
} | |
return COUNT | |
} | |
var ELEMENTS = emitElements() | |
function emitValue (name) { | |
var defn = drawOptions[name] | |
if (defn) { | |
if ((defn.contextDep && args.contextDynamic) || defn.propDep) { | |
return defn.append(env, inner) | |
} else { | |
return defn.append(env, outer) | |
} | |
} else { | |
return outer.def(DRAW_STATE, '.', name) | |
} | |
} | |
var PRIMITIVE = emitValue(S_PRIMITIVE) | |
var OFFSET = emitValue(S_OFFSET) | |
var COUNT = emitCount() | |
if (typeof COUNT === 'number') { | |
if (COUNT === 0) { | |
return | |
} | |
} else { | |
inner('if(', COUNT, '){') | |
inner.exit('}') | |
} | |
var INSTANCES, EXT_INSTANCING | |
if (extInstancing) { | |
INSTANCES = emitValue(S_INSTANCES) | |
EXT_INSTANCING = env.instancing | |
} | |
var ELEMENT_TYPE = ELEMENTS + '.type' | |
var elementsStatic = drawOptions.elements && isStatic(drawOptions.elements) | |
function emitInstancing () { | |
function drawElements () { | |
inner(EXT_INSTANCING, '.drawElementsInstancedANGLE(', [ | |
PRIMITIVE, | |
COUNT, | |
ELEMENT_TYPE, | |
OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE + ')>>1)', | |
INSTANCES | |
], ');') | |
} | |
function drawArrays () { | |
inner(EXT_INSTANCING, '.drawArraysInstancedANGLE(', | |
[PRIMITIVE, OFFSET, COUNT, INSTANCES], ');') | |
} | |
if (ELEMENTS) { | |
if (!elementsStatic) { | |
inner('if(', ELEMENTS, '){') | |
drawElements() | |
inner('}else{') | |
drawArrays() | |
inner('}') | |
} else { | |
drawElements() | |
} | |
} else { | |
drawArrays() | |
} | |
} | |
function emitRegular () { | |
function drawElements () { | |
inner(GL + '.drawElements(' + [ | |
PRIMITIVE, | |
COUNT, | |
ELEMENT_TYPE, | |
OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE + ')>>1)' | |
] + ');') | |
} | |
function drawArrays () { | |
inner(GL + '.drawArrays(' + [PRIMITIVE, OFFSET, COUNT] + ');') | |
} | |
if (ELEMENTS) { | |
if (!elementsStatic) { | |
inner('if(', ELEMENTS, '){') | |
drawElements() | |
inner('}else{') | |
drawArrays() | |
inner('}') | |
} else { | |
drawElements() | |
} | |
} else { | |
drawArrays() | |
} | |
} | |
if (extInstancing && (typeof INSTANCES !== 'number' || INSTANCES >= 0)) { | |
if (typeof INSTANCES === 'string') { | |
inner('if(', INSTANCES, '>0){') | |
emitInstancing() | |
inner('}else if(', INSTANCES, '<0){') | |
emitRegular() | |
inner('}') | |
} else { | |
emitInstancing() | |
} | |
} else { | |
emitRegular() | |
} | |
} | |
function createBody (emitBody, parentEnv, args, program, count) { | |
var env = createREGLEnvironment() | |
var scope = env.proc('body', count) | |
check.optional(function () { | |
env.commandStr = parentEnv.commandStr | |
env.command = env.link(parentEnv.commandStr) | |
}) | |
if (extInstancing) { | |
env.instancing = scope.def( | |
env.shared.extensions, '.angle_instanced_arrays') | |
} | |
emitBody(env, scope, args, program) | |
return env.compile().body | |
} | |
// =================================================== | |
// =================================================== | |
// DRAW PROC | |
// =================================================== | |
// =================================================== | |
function emitDrawBody (env, draw, args, program) { | |
injectExtensions(env, draw) | |
emitAttributes(env, draw, args, program.attributes, function () { | |
return true | |
}) | |
emitUniforms(env, draw, args, program.uniforms, function () { | |
return true | |
}) | |
emitDraw(env, draw, draw, args) | |
} | |
function emitDrawProc (env, args) { | |
var draw = env.proc('draw', 1) | |
injectExtensions(env, draw) | |
emitContext(env, draw, args.context) | |
emitPollFramebuffer(env, draw, args.framebuffer) | |
emitPollState(env, draw, args) | |
emitSetOptions(env, draw, args.state) | |
emitProfile(env, draw, args, false, true) | |
var program = args.shader.progVar.append(env, draw) | |
draw(env.shared.gl, '.useProgram(', program, '.program);') | |
if (args.shader.program) { | |
emitDrawBody(env, draw, args, args.shader.program) | |
} else { | |
var drawCache = env.global.def('{}') | |
var PROG_ID = draw.def(program, '.id') | |
var CACHED_PROC = draw.def(drawCache, '[', PROG_ID, ']') | |
draw( | |
env.cond(CACHED_PROC) | |
.then(CACHED_PROC, '.call(this,a0);') | |
.else( | |
CACHED_PROC, '=', drawCache, '[', PROG_ID, ']=', | |
env.link(function (program) { | |
return createBody(emitDrawBody, env, args, program, 1) | |
}), '(', program, ');', | |
CACHED_PROC, '.call(this,a0);')) | |
} | |
if (Object.keys(args.state).length > 0) { | |
draw(env.shared.current, '.dirty=true;') | |
} | |
} | |
// =================================================== | |
// =================================================== | |
// BATCH PROC | |
// =================================================== | |
// =================================================== | |
function emitBatchDynamicShaderBody (env, scope, args, program) { | |
env.batchId = 'a1' | |
injectExtensions(env, scope) | |
function all () { | |
return true | |
} | |
emitAttributes(env, scope, args, program.attributes, all) | |
emitUniforms(env, scope, args, program.uniforms, all) | |
emitDraw(env, scope, scope, args) | |
} | |
function emitBatchBody (env, scope, args, program) { | |
injectExtensions(env, scope) | |
var contextDynamic = args.contextDep | |
var BATCH_ID = scope.def() | |
var PROP_LIST = 'a0' | |
var NUM_PROPS = 'a1' | |
var PROPS = scope.def() | |
env.shared.props = PROPS | |
env.batchId = BATCH_ID | |
var outer = env.scope() | |
var inner = env.scope() | |
scope( | |
outer.entry, | |
'for(', BATCH_ID, '=0;', BATCH_ID, '<', NUM_PROPS, ';++', BATCH_ID, '){', | |
PROPS, '=', PROP_LIST, '[', BATCH_ID, '];', | |
inner, | |
'}', | |
outer.exit) | |
function isInnerDefn (defn) { | |
return ((defn.contextDep && contextDynamic) || defn.propDep) | |
} | |
function isOuterDefn (defn) { | |
return !isInnerDefn(defn) | |
} | |
if (args.needsContext) { | |
emitContext(env, inner, args.context) | |
} | |
if (args.needsFramebuffer) { | |
emitPollFramebuffer(env, inner, args.framebuffer) | |
} | |
emitSetOptions(env, inner, args.state, isInnerDefn) | |
if (args.profile && isInnerDefn(args.profile)) { | |
emitProfile(env, inner, args, false, true) | |
} | |
if (!program) { | |
var progCache = env.global.def('{}') | |
var PROGRAM = args.shader.progVar.append(env, inner) | |
var PROG_ID = inner.def(PROGRAM, '.id') | |
var CACHED_PROC = inner.def(progCache, '[', PROG_ID, ']') | |
inner( | |
env.shared.gl, '.useProgram(', PROGRAM, '.program);', | |
'if(!', CACHED_PROC, '){', | |
CACHED_PROC, '=', progCache, '[', PROG_ID, ']=', | |
env.link(function (program) { | |
return createBody( | |
emitBatchDynamicShaderBody, env, args, program, 2) | |
}), '(', PROGRAM, ');}', | |
CACHED_PROC, '.call(this,a0[', BATCH_ID, '],', BATCH_ID, ');') | |
} else { | |
emitAttributes(env, outer, args, program.attributes, isOuterDefn) | |
emitAttributes(env, inner, args, program.attributes, isInnerDefn) | |
emitUniforms(env, outer, args, program.uniforms, isOuterDefn) | |
emitUniforms(env, inner, args, program.uniforms, isInnerDefn) | |
emitDraw(env, outer, inner, args) | |
} | |
} | |
function emitBatchProc (env, args) { | |
var batch = env.proc('batch', 2) | |
env.batchId = '0' | |
injectExtensions(env, batch) | |
// Check if any context variables depend on props | |
var contextDynamic = false | |
var needsContext = true | |
Object.keys(args.context).forEach(function (name) { | |
contextDynamic = contextDynamic || args.context[name].propDep | |
}) | |
if (!contextDynamic) { | |
emitContext(env, batch, args.context) | |
needsContext = false | |
} | |
// framebuffer state affects framebufferWidth/height context vars | |
var framebuffer = args.framebuffer | |
var needsFramebuffer = false | |
if (framebuffer) { | |
if (framebuffer.propDep) { | |
contextDynamic = needsFramebuffer = true | |
} else if (framebuffer.contextDep && contextDynamic) { | |
needsFramebuffer = true | |
} | |
if (!needsFramebuffer) { | |
emitPollFramebuffer(env, batch, framebuffer) | |
} | |
} else { | |
emitPollFramebuffer(env, batch, null) | |
} | |
// viewport is weird because it can affect context vars | |
if (args.state.viewport && args.state.viewport.propDep) { | |
contextDynamic = true | |
} | |
function isInnerDefn (defn) { | |
return (defn.contextDep && contextDynamic) || defn.propDep | |
} | |
// set webgl options | |
emitPollState(env, batch, args) | |
emitSetOptions(env, batch, args.state, function (defn) { | |
return !isInnerDefn(defn) | |
}) | |
if (!args.profile || !isInnerDefn(args.profile)) { | |
emitProfile(env, batch, args, false, 'a1') | |
} | |
// Save these values to args so that the batch body routine can use them | |
args.contextDep = contextDynamic | |
args.needsContext = needsContext | |
args.needsFramebuffer = needsFramebuffer | |
// determine if shader is dynamic | |
var progDefn = args.shader.progVar | |
if ((progDefn.contextDep && contextDynamic) || progDefn.propDep) { | |
emitBatchBody( | |
env, | |
batch, | |
args, | |
null) | |
} else { | |
var PROGRAM = progDefn.append(env, batch) | |
batch(env.shared.gl, '.useProgram(', PROGRAM, '.program);') | |
if (args.shader.program) { | |
emitBatchBody( | |
env, | |
batch, | |
args, | |
args.shader.program) | |
} else { | |
var batchCache = env.global.def('{}') | |
var PROG_ID = batch.def(PROGRAM, '.id') | |
var CACHED_PROC = batch.def(batchCache, '[', PROG_ID, ']') | |
batch( | |
env.cond(CACHED_PROC) | |
.then(CACHED_PROC, '.call(this,a0,a1);') | |
.else( | |
CACHED_PROC, '=', batchCache, '[', PROG_ID, ']=', | |
env.link(function (program) { | |
return createBody(emitBatchBody, env, args, program, 2) | |
}), '(', PROGRAM, ');', | |
CACHED_PROC, '.call(this,a0,a1);')) | |
} | |
} | |
if (Object.keys(args.state).length > 0) { | |
batch(env.shared.current, '.dirty=true;') | |
} | |
} | |
// =================================================== | |
// =================================================== | |
// SCOPE COMMAND | |
// =================================================== | |
// =================================================== | |
function emitScopeProc (env, args) { | |
var scope = env.proc('scope', 3) | |
env.batchId = 'a2' | |
var shared = env.shared | |
var CURRENT_STATE = shared.current | |
emitContext(env, scope, args.context) | |
if (args.framebuffer) { | |
args.framebuffer.append(env, scope) | |
} | |
sortState(Object.keys(args.state)).forEach(function (name) { | |
var defn = args.state[name] | |
var value = defn.append(env, scope) | |
if (isArrayLike(value)) { | |
value.forEach(function (v, i) { | |
scope.set(env.next[name], '[' + i + ']', v) | |
}) | |
} else { | |
scope.set(shared.next, '.' + name, value) | |
} | |
}) | |
emitProfile(env, scope, args, true, true) | |
;[S_ELEMENTS, S_OFFSET, S_COUNT, S_INSTANCES, S_PRIMITIVE].forEach( | |
function (opt) { | |
var variable = args.draw[opt] | |
if (!variable) { | |
return | |
} | |
scope.set(shared.draw, '.' + opt, '' + variable.append(env, scope)) | |
}) | |
Object.keys(args.uniforms).forEach(function (opt) { | |
scope.set( | |
shared.uniforms, | |
'[' + stringStore.id(opt) + ']', | |
args.uniforms[opt].append(env, scope)) | |
}) | |
Object.keys(args.attributes).forEach(function (name) { | |
var record = args.attributes[name].append(env, scope) | |
var scopeAttrib = env.scopeAttrib(name) | |
Object.keys(new AttributeRecord()).forEach(function (prop) { | |
scope.set(scopeAttrib, '.' + prop, record[prop]) | |
}) | |
}) | |
function saveShader (name) { | |
var shader = args.shader[name] | |
if (shader) { | |
scope.set(shared.shader, '.' + name, shader.append(env, scope)) | |
} | |
} | |
saveShader(S_VERT) | |
saveShader(S_FRAG) | |
if (Object.keys(args.state).length > 0) { | |
scope(CURRENT_STATE, '.dirty=true;') | |
scope.exit(CURRENT_STATE, '.dirty=true;') | |
} | |
scope('a1(', env.shared.context, ',a0,', env.batchId, ');') | |
} | |
function isDynamicObject (object) { | |
if (typeof object !== 'object' || isArrayLike(object)) { | |
return | |
} | |
var props = Object.keys(object) | |
for (var i = 0; i < props.length; ++i) { | |
if (dynamic.isDynamic(object[props[i]])) { | |
return true | |
} | |
} | |
return false | |
} | |
function splatObject (env, options, name) { | |
var object = options.static[name] | |
if (!object || !isDynamicObject(object)) { | |
return | |
} | |
var globals = env.global | |
var keys = Object.keys(object) | |
var thisDep = false | |
var contextDep = false | |
var propDep = false | |
var objectRef = env.global.def('{}') | |
keys.forEach(function (key) { | |
var value = object[key] | |
if (dynamic.isDynamic(value)) { | |
if (typeof value === 'function') { | |
value = object[key] = dynamic.unbox(value) | |
} | |
var deps = createDynamicDecl(value, null) | |
thisDep = thisDep || deps.thisDep | |
propDep = propDep || deps.propDep | |
contextDep = contextDep || deps.contextDep | |
} else { | |
globals(objectRef, '.', key, '=') | |
switch (typeof value) { | |
case 'number': | |
globals(value) | |
break | |
case 'string': | |
globals('"', value, '"') | |
break | |
case 'object': | |
if (Array.isArray(value)) { | |
globals('[', value.join(), ']') | |
} | |
break | |
default: | |
globals(env.link(value)) | |
break | |
} | |
globals(';') | |
} | |
}) | |
function appendBlock (env, block) { | |
keys.forEach(function (key) { | |
var value = object[key] | |
if (!dynamic.isDynamic(value)) { | |
return | |
} | |
var ref = env.invoke(block, value) | |
block(objectRef, '.', key, '=', ref, ';') | |
}) | |
} | |
options.dynamic[name] = new dynamic.DynamicVariable(DYN_THUNK, { | |
thisDep: thisDep, | |
contextDep: contextDep, | |
propDep: propDep, | |
ref: objectRef, | |
append: appendBlock | |
}) | |
delete options.static[name] | |
} | |
// =========================================================================== | |
// =========================================================================== | |
// MAIN DRAW COMMAND | |
// =========================================================================== | |
// =========================================================================== | |
function compileCommand (options, attributes, uniforms, context, stats) { | |
var env = createREGLEnvironment() | |
// link stats, so that we can easily access it in the program. | |
env.stats = env.link(stats) | |
// splat options and attributes to allow for dynamic nested properties | |
Object.keys(attributes.static).forEach(function (key) { | |
splatObject(env, attributes, key) | |
}) | |
NESTED_OPTIONS.forEach(function (name) { | |
splatObject(env, options, name) | |
}) | |
var args = parseArguments(options, attributes, uniforms, context) | |
emitDrawProc(env, args) | |
emitScopeProc(env, args) | |
emitBatchProc(env, args) | |
return env.compile() | |
} | |
// =========================================================================== | |
// =========================================================================== | |
// POLL / REFRESH | |
// =========================================================================== | |
// =========================================================================== | |
return { | |
next: nextState, | |
current: currentState, | |
procs: (function () { | |
var env = createREGLEnvironment() | |
var poll = env.proc('poll') | |
var refresh = env.proc('refresh') | |
var common = env.block() | |
poll(common) | |
refresh(common) | |
var shared = env.shared | |
var GL = shared.gl | |
var NEXT_STATE = shared.next | |
var CURRENT_STATE = shared.current | |
common(CURRENT_STATE, '.dirty=false;') | |
emitPollFramebuffer(env, poll) | |
emitPollFramebuffer(env, refresh, null, true) | |
// Refresh updates all attribute state changes | |
var extInstancing = gl.getExtension('angle_instanced_arrays') | |
var INSTANCING | |
if (extInstancing) { | |
INSTANCING = env.link(extInstancing) | |
} | |
for (var i = 0; i < limits.maxAttributes; ++i) { | |
var BINDING = refresh.def(shared.attributes, '[', i, ']') | |
var ifte = env.cond(BINDING, '.buffer') | |
ifte.then( | |
GL, '.enableVertexAttribArray(', i, ');', | |
GL, '.bindBuffer(', | |
GL_ARRAY_BUFFER, ',', | |
BINDING, '.buffer.buffer);', | |
GL, '.vertexAttribPointer(', | |
i, ',', | |
BINDING, '.size,', | |
BINDING, '.type,', | |
BINDING, '.normalized,', | |
BINDING, '.stride,', | |
BINDING, '.offset);' | |
).else( | |
GL, '.disableVertexAttribArray(', i, ');', | |
GL, '.vertexAttrib4f(', | |
i, ',', | |
BINDING, '.x,', | |
BINDING, '.y,', | |
BINDING, '.z,', | |
BINDING, '.w);', | |
BINDING, '.buffer=null;') | |
refresh(ifte) | |
if (extInstancing) { | |
refresh( | |
INSTANCING, '.vertexAttribDivisorANGLE(', | |
i, ',', | |
BINDING, '.divisor);') | |
} | |
} | |
Object.keys(GL_FLAGS).forEach(function (flag) { | |
var cap = GL_FLAGS[flag] | |
var NEXT = common.def(NEXT_STATE, '.', flag) | |
var block = env.block() | |
block('if(', NEXT, '){', | |
GL, '.enable(', cap, ')}else{', | |
GL, '.disable(', cap, ')}', | |
CURRENT_STATE, '.', flag, '=', NEXT, ';') | |
refresh(block) | |
poll( | |
'if(', NEXT, '!==', CURRENT_STATE, '.', flag, '){', | |
block, | |
'}') | |
}) | |
Object.keys(GL_VARIABLES).forEach(function (name) { | |
var func = GL_VARIABLES[name] | |
var init = currentState[name] | |
var NEXT, CURRENT | |
var block = env.block() | |
block(GL, '.', func, '(') | |
if (isArrayLike(init)) { | |
var n = init.length | |
NEXT = env.global.def(NEXT_STATE, '.', name) | |
CURRENT = env.global.def(CURRENT_STATE, '.', name) | |
block( | |
loop(n, function (i) { | |
return NEXT + '[' + i + ']' | |
}), ');', | |
loop(n, function (i) { | |
return CURRENT + '[' + i + ']=' + NEXT + '[' + i + '];' | |
}).join('')) | |
poll( | |
'if(', loop(n, function (i) { | |
return NEXT + '[' + i + ']!==' + CURRENT + '[' + i + ']' | |
}).join('||'), '){', | |
block, | |
'}') | |
} else { | |
NEXT = common.def(NEXT_STATE, '.', name) | |
CURRENT = common.def(CURRENT_STATE, '.', name) | |
block( | |
NEXT, ');', | |
CURRENT_STATE, '.', name, '=', NEXT, ';') | |
poll( | |
'if(', NEXT, '!==', CURRENT, '){', | |
block, | |
'}') | |
} | |
refresh(block) | |
}) | |
return env.compile() | |
})(), | |
compile: compileCommand | |
} | |
} | |
},{"./constants/dtypes.json":4,"./constants/primitives.json":5,"./dynamic":8,"./util/check":20,"./util/codegen":22,"./util/is-array-like":24,"./util/is-ndarray":25,"./util/is-typed-array":26,"./util/loop":27}],8:[function(require,module,exports){ | |
var VARIABLE_COUNTER = 0 | |
var DYN_FUNC = 0 | |
function DynamicVariable (type, data) { | |
this.id = (VARIABLE_COUNTER++) | |
this.type = type | |
this.data = data | |
} | |
function escapeStr (str) { | |
return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"') | |
} | |
function splitParts (str) { | |
if (str.length === 0) { | |
return [] | |
} | |
var firstChar = str.charAt(0) | |
var lastChar = str.charAt(str.length - 1) | |
if (str.length > 1 && | |
firstChar === lastChar && | |
(firstChar === '"' || firstChar === "'")) { | |
return ['"' + escapeStr(str.substr(1, str.length - 2)) + '"'] | |
} | |
var parts = /\[(false|true|null|\d+|'[^']*'|"[^"]*")\]/.exec(str) | |
if (parts) { | |
return ( | |
splitParts(str.substr(0, parts.index)) | |
.concat(splitParts(parts[1])) | |
.concat(splitParts(str.substr(parts.index + parts[0].length))) | |
) | |
} | |
var subparts = str.split('.') | |
if (subparts.length === 1) { | |
return ['"' + escapeStr(str) + '"'] | |
} | |
var result = [] | |
for (var i = 0; i < subparts.length; ++i) { | |
result = result.concat(splitParts(subparts[i])) | |
} | |
return result | |
} | |
function toAccessorString (str) { | |
return '[' + splitParts(str).join('][') + ']' | |
} | |
function defineDynamic (type, data) { | |
return new DynamicVariable(type, toAccessorString(data + '')) | |
} | |
function isDynamic (x) { | |
return (typeof x === 'function' && !x._reglType) || | |
x instanceof DynamicVariable | |
} | |
function unbox (x, path) { | |
if (typeof x === 'function') { | |
return new DynamicVariable(DYN_FUNC, x) | |
} | |
return x | |
} | |
module.exports = { | |
DynamicVariable: DynamicVariable, | |
define: defineDynamic, | |
isDynamic: isDynamic, | |
unbox: unbox, | |
accessor: toAccessorString | |
} | |
},{}],9:[function(require,module,exports){ | |
var check = require('./util/check') | |
var isTypedArray = require('./util/is-typed-array') | |
var isNDArrayLike = require('./util/is-ndarray') | |
var values = require('./util/values') | |
var primTypes = require('./constants/primitives.json') | |
var usageTypes = require('./constants/usage.json') | |
var GL_POINTS = 0 | |
var GL_LINES = 1 | |
var GL_TRIANGLES = 4 | |
var GL_BYTE = 5120 | |
var GL_UNSIGNED_BYTE = 5121 | |
var GL_SHORT = 5122 | |
var GL_UNSIGNED_SHORT = 5123 | |
var GL_INT = 5124 | |
var GL_UNSIGNED_INT = 5125 | |
var GL_ELEMENT_ARRAY_BUFFER = 34963 | |
var GL_STREAM_DRAW = 0x88E0 | |
var GL_STATIC_DRAW = 0x88E4 | |
module.exports = function wrapElementsState (gl, extensions, bufferState, stats) { | |
var elementSet = {} | |
var elementCount = 0 | |
var elementTypes = { | |
'uint8': GL_UNSIGNED_BYTE, | |
'uint16': GL_UNSIGNED_SHORT | |
} | |
if (extensions.oes_element_index_uint) { | |
elementTypes.uint32 = GL_UNSIGNED_INT | |
} | |
function REGLElementBuffer (buffer) { | |
this.id = elementCount++ | |
elementSet[this.id] = this | |
this.buffer = buffer | |
this.primType = GL_TRIANGLES | |
this.vertCount = 0 | |
this.type = 0 | |
} | |
REGLElementBuffer.prototype.bind = function () { | |
this.buffer.bind() | |
} | |
var bufferPool = [] | |
function createElementStream (data) { | |
var result = bufferPool.pop() | |
if (!result) { | |
result = new REGLElementBuffer(bufferState.create( | |
null, | |
GL_ELEMENT_ARRAY_BUFFER, | |
true)._buffer) | |
} | |
initElements(result, data, GL_STREAM_DRAW, -1, -1, 0, 0) | |
return result | |
} | |
function destroyElementStream (elements) { | |
bufferPool.push(elements) | |
} | |
function initElements ( | |
elements, | |
data, | |
usage, | |
prim, | |
count, | |
byteLength, | |
type) { | |
var predictedType = type | |
if (!type && ( | |
!isTypedArray(data) || | |
(isNDArrayLike(data) && !isTypedArray(data.data)))) { | |
predictedType = extensions.oes_element_index_uint | |
? GL_UNSIGNED_INT | |
: GL_UNSIGNED_SHORT | |
} | |
elements.buffer.bind() | |
bufferState._initBuffer( | |
elements.buffer, | |
data, | |
usage, | |
predictedType, | |
3) | |
var dtype = type | |
if (!type) { | |
switch (elements.buffer.dtype) { | |
case GL_UNSIGNED_BYTE: | |
case GL_BYTE: | |
dtype = GL_UNSIGNED_BYTE | |
break | |
case GL_UNSIGNED_SHORT: | |
case GL_SHORT: | |
dtype = GL_UNSIGNED_SHORT | |
break | |
case GL_UNSIGNED_INT: | |
case GL_INT: | |
dtype = GL_UNSIGNED_INT | |
break | |
default: | |
check.raise('unsupported type for element array') | |
} | |
elements.buffer.dtype = dtype | |
} | |
elements.type = dtype | |
// Check oes_element_index_uint extension | |
check( | |
dtype !== GL_UNSIGNED_INT || | |
!!extensions.oes_element_index_uint, | |
'32 bit element buffers not supported, enable oes_element_index_uint first') | |
// try to guess default primitive type and arguments | |
var vertCount = count | |
if (vertCount < 0) { | |
vertCount = elements.buffer.byteLength | |
if (dtype === GL_UNSIGNED_SHORT) { | |
vertCount >>= 1 | |
} else if (dtype === GL_UNSIGNED_INT) { | |
vertCount >>= 2 | |
} | |
} | |
elements.vertCount = vertCount | |
// try to guess primitive type from cell dimension | |
var primType = prim | |
if (prim < 0) { | |
primType = GL_TRIANGLES | |
var dimension = elements.buffer.dimension | |
if (dimension === 1) primType = GL_POINTS | |
if (dimension === 2) primType = GL_LINES | |
if (dimension === 3) primType = GL_TRIANGLES | |
} | |
elements.primType = primType | |
} | |
function destroyElements (elements) { | |
stats.elementsCount-- | |
check(elements.buffer !== null, 'must not double destroy elements') | |
delete elementSet[elements.id] | |
elements.buffer.destroy() | |
elements.buffer = null | |
} | |
function createElements (options) { | |
var buffer = bufferState.create(null, GL_ELEMENT_ARRAY_BUFFER, true) | |
var elements = new REGLElementBuffer(buffer._buffer) | |
stats.elementsCount++ | |
function reglElements (options) { | |
if (!options) { | |
buffer() | |
elements.primType = GL_TRIANGLES | |
elements.vertCount = 0 | |
elements.type = GL_UNSIGNED_BYTE | |
} else if (typeof options === 'number') { | |
buffer(options) | |
elements.primType = GL_TRIANGLES | |
elements.vertCount = options | 0 | |
elements.type = GL_UNSIGNED_BYTE | |
} else { | |
var data = null | |
var usage = GL_STATIC_DRAW | |
var primType = -1 | |
var vertCount = -1 | |
var byteLength = 0 | |
var dtype = 0 | |
if (Array.isArray(options) || | |
isTypedArray(options) || | |
isNDArrayLike(options)) { | |
data = options | |
} else { | |
check.type(options, 'object', 'invalid arguments for elements') | |
if ('data' in options) { | |
data = options.data | |
check( | |
Array.isArray(data) || | |
isTypedArray(data) || | |
isNDArrayLike(data), | |
'invalid data for element buffer') | |
} | |
if ('usage' in options) { | |
check.parameter( | |
options.usage, | |
usageTypes, | |
'invalid element buffer usage') | |
usage = usageTypes[options.usage] | |
} | |
if ('primitive' in options) { | |
check.parameter( | |
options.primitive, | |
primTypes, | |
'invalid element buffer primitive') | |
primType = primTypes[options.primitive] | |
} | |
if ('count' in options) { | |
check( | |
typeof options.count === 'number' && options.count >= 0, | |
'invalid vertex count for elements') | |
vertCount = options.count | 0 | |
} | |
if ('length' in options) { | |
byteLength = options.length | 0 | |
} | |
if ('type' in options) { | |
check.parameter( | |
options.type, | |
elementTypes, | |
'invalid buffer type') | |
dtype = elementTypes[options.type] | |
} | |
} | |
if (data) { | |
initElements( | |
elements, | |
data, | |
usage, | |
primType, | |
vertCount, | |
byteLength, | |
dtype) | |
} else { | |
var _buffer = elements.buffer | |
_buffer.bind() | |
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, byteLength, usage) | |
_buffer.dtype = dtype || GL_UNSIGNED_BYTE | |
_buffer.usage = usage | |
_buffer.dimension = 3 | |
_buffer.byteLength = byteLength | |
elements.primType = primType < 0 ? GL_TRIANGLES : primType | |
elements.vertCount = vertCount < 0 ? 0 : vertCount | |
elements.type = _buffer.dtype | |
} | |
} | |
return reglElements | |
} | |
reglElements(options) | |
reglElements._reglType = 'elements' | |
reglElements._elements = elements | |
reglElements.subdata = function (data, offset) { | |
buffer.subdata(data, offset) | |
return reglElements | |
} | |
reglElements.destroy = function () { | |
destroyElements(elements) | |
} | |
return reglElements | |
} | |
return { | |
create: createElements, | |
createStream: createElementStream, | |
destroyStream: destroyElementStream, | |
getElements: function (elements) { | |
if (typeof elements === 'function' && | |
elements._elements instanceof REGLElementBuffer) { | |
return elements._elements | |
} | |
return null | |
}, | |
clear: function () { | |
values(elementSet).forEach(destroyElements) | |
} | |
} | |
} | |
},{"./constants/primitives.json":5,"./constants/usage.json":6,"./util/check":20,"./util/is-ndarray":25,"./util/is-typed-array":26,"./util/values":31}],10:[function(require,module,exports){ | |
var check = require('./util/check') | |
module.exports = function createExtensionCache (gl, config) { | |
var extensions = {} | |
function tryLoadExtension (name_) { | |
check.type(name_, 'string', 'extension name must be string') | |
var name = name_.toLowerCase() | |
var ext | |
try { | |
ext = extensions[name] = gl.getExtension(name) | |
} catch (e) {} | |
return !!ext | |
} | |
for (var i = 0; i < config.extensions.length; ++i) { | |
var name = config.extensions[i] | |
if (!tryLoadExtension(name)) { | |
config.onDestroy() | |
config.onDone('"' + name + '" extension is not supported by the current WebGL context, try upgrading your system or a different browser') | |
return null | |
} | |
} | |
config.optionalExtensions.forEach(tryLoadExtension) | |
return { | |
extensions: extensions | |
} | |
} | |
},{"./util/check":20}],11:[function(require,module,exports){ | |
var check = require('./util/check') | |
var values = require('./util/values') | |
var extend = require('./util/extend') | |
// We store these constants so that the minifier can inline them | |
var GL_FRAMEBUFFER = 0x8D40 | |
var GL_RENDERBUFFER = 0x8D41 | |
var GL_TEXTURE_2D = 0x0DE1 | |
var GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515 | |
var GL_COLOR_ATTACHMENT0 = 0x8CE0 | |
var GL_DEPTH_ATTACHMENT = 0x8D00 | |
var GL_STENCIL_ATTACHMENT = 0x8D20 | |
var GL_DEPTH_STENCIL_ATTACHMENT = 0x821A | |
var GL_FRAMEBUFFER_COMPLETE = 0x8CD5 | |
var GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6 | |
var GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7 | |
var GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9 | |
var GL_FRAMEBUFFER_UNSUPPORTED = 0x8CDD | |
var GL_HALF_FLOAT_OES = 0x8D61 | |
var GL_UNSIGNED_BYTE = 0x1401 | |
var GL_FLOAT = 0x1406 | |
var GL_RGBA = 0x1908 | |
var GL_DEPTH_COMPONENT = 0x1902 | |
var colorTextureFormatEnums = [ | |
GL_RGBA | |
] | |
// for every texture format, store | |
// the number of channels | |
var textureFormatChannels = [] | |
textureFormatChannels[GL_RGBA] = 4 | |
// for every texture type, store | |
// the size in bytes. | |
var textureTypeSizes = [] | |
textureTypeSizes[GL_UNSIGNED_BYTE] = 1 | |
textureTypeSizes[GL_FLOAT] = 4 | |
textureTypeSizes[GL_HALF_FLOAT_OES] = 2 | |
var GL_RGBA4 = 0x8056 | |
var GL_RGB5_A1 = 0x8057 | |
var GL_RGB565 = 0x8D62 | |
var GL_DEPTH_COMPONENT16 = 0x81A5 | |
var GL_STENCIL_INDEX8 = 0x8D48 | |
var GL_DEPTH_STENCIL = 0x84F9 | |
var GL_SRGB8_ALPHA8_EXT = 0x8C43 | |
var GL_RGBA32F_EXT = 0x8814 | |
var GL_RGBA16F_EXT = 0x881A | |
var GL_RGB16F_EXT = 0x881B | |
var colorRenderbufferFormatEnums = [ | |
GL_RGBA4, | |
GL_RGB5_A1, | |
GL_RGB565, | |
GL_SRGB8_ALPHA8_EXT, | |
GL_RGBA16F_EXT, | |
GL_RGB16F_EXT, | |
GL_RGBA32F_EXT | |
] | |
var statusCode = {} | |
statusCode[GL_FRAMEBUFFER_COMPLETE] = 'complete' | |
statusCode[GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT] = 'incomplete attachment' | |
statusCode[GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS] = 'incomplete dimensions' | |
statusCode[GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT] = 'incomplete, missing attachment' | |
statusCode[GL_FRAMEBUFFER_UNSUPPORTED] = 'unsupported' | |
module.exports = function wrapFBOState ( | |
gl, | |
extensions, | |
limits, | |
textureState, | |
renderbufferState, | |
stats) { | |
var framebufferState = { | |
cur: null, | |
next: null, | |
dirty: false | |
} | |
var colorTextureFormats = ['rgba'] | |
var colorRenderbufferFormats = ['rgba4', 'rgb565', 'rgb5 a1'] | |
if (extensions.ext_srgb) { | |
colorRenderbufferFormats.push('srgba') | |
} | |
if (extensions.ext_color_buffer_half_float) { | |
colorRenderbufferFormats.push('rgba16f', 'rgb16f') | |
} | |
if (extensions.webgl_color_buffer_float) { | |
colorRenderbufferFormats.push('rgba32f') | |
} | |
var colorTypes = ['uint8'] | |
if (extensions.oes_texture_half_float) { | |
colorTypes.push('half float', 'float16') | |
} | |
if (extensions.oes_texture_float) { | |
colorTypes.push('float', 'float32') | |
} | |
function FramebufferAttachment (target, texture, renderbuffer) { | |
this.target = target | |
this.texture = texture | |
this.renderbuffer = renderbuffer | |
var w = 0 | |
var h = 0 | |
if (texture) { | |
w = texture.width | |
h = texture.height | |
} else if (renderbuffer) { | |
w = renderbuffer.width | |
h = renderbuffer.height | |
} | |
this.width = w | |
this.height = h | |
} | |
function decRef (attachment) { | |
if (attachment) { | |
if (attachment.texture) { | |
attachment.texture._texture.decRef() | |
} | |
if (attachment.renderbuffer) { | |
attachment.renderbuffer._renderbuffer.decRef() | |
} | |
} | |
} | |
function incRefAndCheckShape (attachment, width, height) { | |
if (!attachment) { | |
return | |
} | |
if (attachment.texture) { | |
var texture = attachment.texture._texture | |
var tw = Math.max(1, texture.width) | |
var th = Math.max(1, texture.height) | |
check(tw === width && th === height, | |
'inconsistent width/height for supplied texture') | |
texture.refCount += 1 | |
} else { | |
var renderbuffer = attachment.renderbuffer._renderbuffer | |
check( | |
renderbuffer.width === width && renderbuffer.height === height, | |
'inconsistent width/height for renderbuffer') | |
renderbuffer.refCount += 1 | |
} | |
} | |
function attach (location, attachment) { | |
if (attachment) { | |
if (attachment.texture) { | |
gl.framebufferTexture2D( | |
GL_FRAMEBUFFER, | |
location, | |
attachment.target, | |
attachment.texture._texture.texture, | |
0) | |
} else { | |
gl.framebufferRenderbuffer( | |
GL_FRAMEBUFFER, | |
location, | |
GL_RENDERBUFFER, | |
attachment.renderbuffer._renderbuffer.renderbuffer) | |
} | |
} else { | |
gl.framebufferTexture2D( | |
GL_FRAMEBUFFER, | |
location, | |
GL_TEXTURE_2D, | |
null, | |
0) | |
} | |
} | |
function parseAttachment (attachment) { | |
var target = GL_TEXTURE_2D | |
var texture = null | |
var renderbuffer = null | |
var data = attachment | |
if (typeof attachment === 'object') { | |
data = attachment.data | |
if ('target' in attachment) { | |
target = attachment.target | 0 | |
} | |
} | |
check.type(data, 'function', 'invalid attachment data') | |
var type = data._reglType | |
if (type === 'texture2d') { | |
texture = data | |
check(target === GL_TEXTURE_2D) | |
} else if (type === 'textureCube') { | |
texture = data | |
check( | |
target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && | |
target < GL_TEXTURE_CUBE_MAP_POSITIVE_X + 6, | |
'invalid cube map target') | |
} else if (type === 'renderbuffer') { | |
renderbuffer = data | |
target = GL_RENDERBUFFER | |
} else { | |
check.raise('invalid regl object for attachment') | |
} | |
return new FramebufferAttachment(target, texture, renderbuffer) | |
} | |
function allocAttachment ( | |
width, | |
height, | |
isTexture, | |
format, | |
type) { | |
if (isTexture) { | |
var texture = textureState.create2D({ | |
width: width, | |
height: height, | |
format: format, | |
type: type | |
}) | |
texture._texture.refCount = 0 | |
return new FramebufferAttachment(GL_TEXTURE_2D, texture, null) | |
} else { | |
var rb = renderbufferState.create({ | |
width: width, | |
height: height, | |
format: format | |
}) | |
rb._renderbuffer.refCount = 0 | |
return new FramebufferAttachment(GL_RENDERBUFFER, null, rb) | |
} | |
} | |
function unwrapAttachment (attachment) { | |
return attachment && (attachment.texture || attachment.renderbuffer) | |
} | |
function resizeAttachment (attachment, w, h) { | |
if (attachment) { | |
if (attachment.texture) { | |
attachment.texture.resize(w, h) | |
} else if (attachment.renderbuffer) { | |
attachment.renderbuffer.resize(w, h) | |
} | |
} | |
} | |
var framebufferCount = 0 | |
var framebufferSet = {} | |
function REGLFramebuffer () { | |
this.id = framebufferCount++ | |
framebufferSet[this.id] = this | |
this.framebuffer = gl.createFramebuffer() | |
this.width = 0 | |
this.height = 0 | |
this.colorAttachments = [] | |
this.depthAttachment = null | |
this.stencilAttachment = null | |
this.depthStencilAttachment = null | |
} | |
function decFBORefs (framebuffer) { | |
framebuffer.colorAttachments.forEach(decRef) | |
decRef(framebuffer.depthAttachment) | |
decRef(framebuffer.stencilAttachment) | |
decRef(framebuffer.depthStencilAttachment) | |
} | |
function destroy (framebuffer) { | |
var handle = framebuffer.framebuffer | |
check(handle, 'must not double destroy framebuffer') | |
gl.deleteFramebuffer(handle) | |
framebuffer.framebuffer = null | |
stats.framebufferCount-- | |
delete framebufferSet[framebuffer.id] | |
} | |
function updateFramebuffer (framebuffer) { | |
var i | |
gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer.framebuffer) | |
var colorAttachments = framebuffer.colorAttachments | |
for (i = 0; i < colorAttachments.length; ++i) { | |
attach(GL_COLOR_ATTACHMENT0 + i, colorAttachments[i]) | |
} | |
for (i = colorAttachments.length; i < limits.maxColorAttachments; ++i) { | |
attach(GL_COLOR_ATTACHMENT0 + i, null) | |
} | |
attach(GL_DEPTH_ATTACHMENT, framebuffer.depthAttachment) | |
attach(GL_STENCIL_ATTACHMENT, framebuffer.stencilAttachment) | |
attach(GL_DEPTH_STENCIL_ATTACHMENT, framebuffer.depthStencilAttachment) | |
// Check status code | |
var status = gl.checkFramebufferStatus(GL_FRAMEBUFFER) | |
if (status !== GL_FRAMEBUFFER_COMPLETE) { | |
check.raise('framebuffer configuration not supported, status = ' + | |
statusCode[status]) | |
} | |
gl.bindFramebuffer(GL_FRAMEBUFFER, framebufferState.next) | |
framebufferState.cur = framebufferState.next | |
// FIXME: Clear error code here. This is a work around for a bug in | |
// headless-gl | |
gl.getError() | |
} | |
function createFBO (a0, a1) { | |
var framebuffer = new REGLFramebuffer() | |
stats.framebufferCount++ | |
function reglFramebuffer (a, b) { | |
var i | |
check(framebufferState.next !== framebuffer, | |
'can not update framebuffer which is currently in use') | |
var extDrawBuffers = extensions.webgl_draw_buffers | |
var width = 0 | |
var height = 0 | |
var needsDepth = true | |
var needsStencil = true | |
var colorBuffer = null | |
var colorTexture = true | |
var colorFormat = 'rgba' | |
var colorType = 'uint8' | |
var colorCount = 1 | |
var depthBuffer = null | |
var stencilBuffer = null | |
var depthStencilBuffer = null | |
var depthStencilTexture = false | |
if (typeof a === 'number') { | |
width = a | 0 | |
height = (b | 0) || width | |
} else if (!a) { | |
width = height = 1 | |
} else { | |
check.type(a, 'object', 'invalid arguments for framebuffer') | |
var options = a | |
if ('shape' in options) { | |
var shape = options.shape | |
check(Array.isArray(shape) && shape.length >= 2, | |
'invalid shape for framebuffer') | |
width = shape[0] | |
height = shape[1] | |
} else { | |
if ('radius' in options) { | |
width = height = options.radius | |
} | |
if ('width' in options) { | |
width = options.width | |
} | |
if ('height' in options) { | |
height = options.height | |
} | |
} | |
if ('color' in options || | |
'colors' in options) { | |
colorBuffer = | |
options.color || | |
options.colors | |
if (Array.isArray(colorBuffer)) { | |
check( | |
colorBuffer.length === 1 || extDrawBuffers, | |
'multiple render targets not supported') | |
} | |
} | |
if (!colorBuffer) { | |
if ('colorCount' in options) { | |
colorCount = options.colorCount | 0 | |
check(colorCount > 0, 'invalid color buffer count') | |
} | |
if ('colorTexture' in options) { | |
colorTexture = !!options.colorTexture | |
colorFormat = 'rgba4' | |
} | |
if ('colorType' in options) { | |
colorType = options.colorType | |
if (!colorTexture) { | |
if (colorType === 'half float' || colorType === 'float16') { | |
check(extensions.ext_color_buffer_half_float, | |
'you must enable EXT_color_buffer_half_float to use 16-bit render buffers') | |
colorFormat = 'rgba16f' | |
} else if (colorType === 'float' || colorType === 'float32') { | |
check(extensions.webgl_color_buffer_float, | |
'you must enable WEBGL_color_buffer_float in order to use 32-bit floating point renderbuffers') | |
colorFormat = 'rgba32f' | |
} | |
} else { | |
check(extensions.oes_texture_float || | |
!(colorType === 'float' || colorType === 'float32'), | |
'you must enable OES_texture_float in order to use floating point framebuffer objects') | |
check(extensions.oes_texture_half_float || | |
!(colorType === 'half float' || colorType === 'float16'), | |
'you must enable OES_texture_half_float in order to use 16-bit floating point framebuffer objects') | |
} | |
check.oneOf(colorType, colorTypes, 'invalid color type') | |
} | |
if ('colorFormat' in options) { | |
colorFormat = options.colorFormat | |
if (colorTextureFormats.indexOf(colorFormat) >= 0) { | |
colorTexture = true | |
} else if (colorRenderbufferFormats.indexOf(colorFormat) >= 0) { | |
colorTexture = false | |
} else { | |
if (colorTexture) { | |
check.oneOf( | |
options.colorFormat, colorTextureFormats, | |
'invalid color format for texture') | |
} else { | |
check.oneOf( | |
options.colorFormat, colorRenderbufferFormats, | |
'invalid color format for renderbuffer') | |
} | |
} | |
} | |
} | |
if ('depthTexture' in options || 'depthStencilTexture' in options) { | |
depthStencilTexture = !!(options.depthTexture || | |
options.depthStencilTexture) | |
check(!depthStencilTexture || extensions.webgl_depth_texture, | |
'webgl_depth_texture extension not supported') | |
} | |
if ('depth' in options) { | |
if (typeof options.depth === 'boolean') { | |
needsDepth = options.depth | |
} else { | |
depthBuffer = options.depth | |
needsStencil = false | |
} | |
} | |
if ('stencil' in options) { | |
if (typeof options.stencil === 'boolean') { | |
needsStencil = options.stencil | |
} else { | |
stencilBuffer = options.stencil | |
needsDepth = false | |
} | |
} | |
if ('depthStencil' in options) { | |
if (typeof options.depthStencil === 'boolean') { | |
needsDepth = needsStencil = options.depthStencil | |
} else { | |
depthStencilBuffer = options.depthStencil | |
needsDepth = false | |
needsStencil = false | |
} | |
} | |
} | |
// parse attachments | |
var colorAttachments = null | |
var depthAttachment = null | |
var stencilAttachment = null | |
var depthStencilAttachment = null | |
// Set up color attachments | |
if (Array.isArray(colorBuffer)) { | |
colorAttachments = colorBuffer.map(parseAttachment) | |
} else if (colorBuffer) { | |
colorAttachments = [parseAttachment(colorBuffer)] | |
} else { | |
colorAttachments = new Array(colorCount) | |
for (i = 0; i < colorCount; ++i) { | |
colorAttachments[i] = allocAttachment( | |
width, | |
height, | |
colorTexture, | |
colorFormat, | |
colorType) | |
} | |
} | |
check(extensions.webgl_draw_buffers || colorAttachments.length <= 1, | |
'you must enable the WEBGL_draw_buffers extension in order to use multiple color buffers.') | |
check(colorAttachments.length <= limits.maxColorAttachments, | |
'too many color attachments, not supported') | |
width = width || colorAttachments[0].width | |
height = height || colorAttachments[0].height | |
if (depthBuffer) { | |
depthAttachment = parseAttachment(depthBuffer) | |
} else if (needsDepth && !needsStencil) { | |
depthAttachment = allocAttachment( | |
width, | |
height, | |
depthStencilTexture, | |
'depth', | |
'uint32') | |
} | |
if (stencilBuffer) { | |
stencilAttachment = parseAttachment(stencilBuffer) | |
} else if (needsStencil && !needsDepth) { | |
stencilAttachment = allocAttachment( | |
width, | |
height, | |
false, | |
'stencil', | |
'uint8') | |
} | |
if (depthStencilBuffer) { | |
depthStencilAttachment = parseAttachment(depthStencilBuffer) | |
} else if (!depthBuffer && !stencilBuffer && needsStencil && needsDepth) { | |
depthStencilAttachment = allocAttachment( | |
width, | |
height, | |
depthStencilTexture, | |
'depth stencil', | |
'depth stencil') | |
} | |
check( | |
(!!depthBuffer) + (!!stencilBuffer) + (!!depthStencilBuffer) <= 1, | |
'invalid framebuffer configuration, can specify exactly one depth/stencil attachment') | |
var commonColorAttachmentSize = null | |
for (i = 0; i < colorAttachments.length; ++i) { | |
incRefAndCheckShape(colorAttachments[i], width, height) | |
check(!colorAttachments[i] || | |
(colorAttachments[i].texture && | |
colorTextureFormatEnums.indexOf(colorAttachments[i].texture._texture.format) >= 0) || | |
(colorAttachments[i].renderbuffer && | |
colorRenderbufferFormatEnums.indexOf(colorAttachments[i].renderbuffer._renderbuffer.format) >= 0), | |
'framebuffer color attachment ' + i + ' is invalid') | |
if (colorAttachments[i] && colorAttachments[i].texture) { | |
var colorAttachmentSize = | |
textureFormatChannels[colorAttachments[i].texture._texture.format] * | |
textureTypeSizes[colorAttachments[i].texture._texture.type] | |
if (commonColorAttachmentSize === null) { | |
commonColorAttachmentSize = colorAttachmentSize | |
} else { | |
// We need to make sure that all color attachments have the same number of bitplanes | |
// (that is, the same numer of bits per pixel) | |
// This is required by the GLES2.0 standard. See the beginning of Chapter 4 in that document. | |
check(commonColorAttachmentSize === colorAttachmentSize, | |
'all color attachments much have the same number of bits per pixel.') | |
} | |
} | |
} | |
incRefAndCheckShape(depthAttachment, width, height) | |
check(!depthAttachment || | |
(depthAttachment.texture && | |
depthAttachment.texture._texture.format === GL_DEPTH_COMPONENT) || | |
(depthAttachment.renderbuffer && | |
depthAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_COMPONENT16), | |
'invalid depth attachment for framebuffer object') | |
incRefAndCheckShape(stencilAttachment, width, height) | |
check(!stencilAttachment || | |
(stencilAttachment.renderbuffer && | |
stencilAttachment.renderbuffer._renderbuffer.format === GL_STENCIL_INDEX8), | |
'invalid stencil attachment for framebuffer object') | |
incRefAndCheckShape(depthStencilAttachment, width, height) | |
check(!depthStencilAttachment || | |
(depthStencilAttachment.texture && | |
depthStencilAttachment.texture._texture.format === GL_DEPTH_STENCIL) || | |
(depthStencilAttachment.renderbuffer && | |
depthStencilAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_STENCIL), | |
'invalid depth-stencil attachment for framebuffer object') | |
// decrement references | |
decFBORefs(framebuffer) | |
framebuffer.width = width | |
framebuffer.height = height | |
framebuffer.colorAttachments = colorAttachments | |
framebuffer.depthAttachment = depthAttachment | |
framebuffer.stencilAttachment = stencilAttachment | |
framebuffer.depthStencilAttachment = depthStencilAttachment | |
reglFramebuffer.color = colorAttachments.map(unwrapAttachment) | |
reglFramebuffer.depth = unwrapAttachment(depthAttachment) | |
reglFramebuffer.stencil = unwrapAttachment(stencilAttachment) | |
reglFramebuffer.depthStencil = unwrapAttachment(depthStencilAttachment) | |
reglFramebuffer.width = framebuffer.width | |
reglFramebuffer.height = framebuffer.height | |
updateFramebuffer(framebuffer) | |
return reglFramebuffer | |
} | |
function resize (w_, h_) { | |
check(framebufferState.next !== framebuffer, | |
'can not resize a framebuffer which is currently in use') | |
var w = w_ | 0 | |
var h = (h_ | 0) || w | |
if (w === framebuffer.width && h === framebuffer.height) { | |
return reglFramebuffer | |
} | |
// resize all buffers | |
var colorAttachments = framebuffer.colorAttachments | |
for (var i = 0; i < colorAttachments.length; ++i) { | |
resizeAttachment(colorAttachments[i], w, h) | |
} | |
resizeAttachment(framebuffer.depthAttachment, w, h) | |
resizeAttachment(framebuffer.stencilAttachment, w, h) | |
resizeAttachment(framebuffer.depthStencilAttachment, w, h) | |
framebuffer.width = reglFramebuffer.width = w | |
framebuffer.height = reglFramebuffer.height = h | |
updateFramebuffer(framebuffer) | |
return reglFramebuffer | |
} | |
reglFramebuffer(a0, a1) | |
return extend(reglFramebuffer, { | |
resize: resize, | |
_reglType: 'framebuffer', | |
_framebuffer: framebuffer, | |
destroy: function () { | |
destroy(framebuffer) | |
decFBORefs(framebuffer) | |
} | |
}) | |
} | |
function createCubeFBO (options) { | |
var faces = Array(6) | |
function reglFramebufferCube (a) { | |
var i | |
check(faces.indexOf(framebufferState.next) < 0, | |
'can not update framebuffer which is currently in use') | |
var extDrawBuffers = extensions.webgl_draw_buffers | |
var params = { | |
color: null | |
} | |
var radius = 0 | |
var colorBuffer = null | |
var colorFormat = 'rgba' | |
var colorType = 'uint8' | |
var colorCount = 1 | |
if (typeof a === 'number') { | |
radius = a | 0 | |
} else if (!a) { | |
radius = 1 | |
} else { | |
check.type(a, 'object', 'invalid arguments for framebuffer') | |
var options = a | |
if ('shape' in options) { | |
var shape = options.shape | |
check( | |
Array.isArray(shape) && shape.length >= 2, | |
'invalid shape for framebuffer') | |
check( | |
shape[0] === shape[1], | |
'cube framebuffer must be square') | |
radius = shape[0] | |
} else { | |
if ('radius' in options) { | |
radius = options.radius | 0 | |
} | |
if ('width' in options) { | |
radius = options.width | 0 | |
if ('height' in options) { | |
check(options.height === radius, 'must be square') | |
} | |
} else if ('height' in options) { | |
radius = options.height | 0 | |
} | |
} | |
if ('color' in options || | |
'colors' in options) { | |
colorBuffer = | |
options.color || | |
options.colors | |
if (Array.isArray(colorBuffer)) { | |
check( | |
colorBuffer.length === 1 || extDrawBuffers, | |
'multiple render targets not supported') | |
} | |
} | |
if (!colorBuffer) { | |
if ('colorCount' in options) { | |
colorCount = options.colorCount | 0 | |
check(colorCount > 0, 'invalid color buffer count') | |
} | |
if ('colorType' in options) { | |
check.oneOf( | |
options.colorType, colorTypes, | |
'invalid color type') | |
colorType = options.colorType | |
} | |
if ('colorFormat' in options) { | |
colorFormat = options.colorFormat | |
check.oneOf( | |
options.colorFormat, colorTextureFormats, | |
'invalid color format for texture') | |
} | |
} | |
if ('depth' in options) { | |
params.depth = options.depth | |
} | |
if ('stencil' in options) { | |
params.stencil = options.stencil | |
} | |
if ('depthStencil' in options) { | |
params.depthStencil = options.depthStencil | |
} | |
} | |
var colorCubes | |
if (colorBuffer) { | |
if (Array.isArray(colorBuffer)) { | |
colorCubes = [] | |
for (i = 0; i < colorBuffer.length; ++i) { | |
colorCubes[i] = colorBuffer[i] | |
} | |
} else { | |
colorCubes = [ colorBuffer ] | |
} | |
} else { | |
colorCubes = Array(colorCount) | |
var cubeMapParams = { | |
radius: radius, | |
format: colorFormat, | |
type: colorType | |
} | |
for (i = 0; i < colorCount; ++i) { | |
colorCubes[i] = textureState.createCube(cubeMapParams) | |
} | |
} | |
// Check color cubes | |
params.color = Array(colorCubes.length) | |
for (i = 0; i < colorCubes.length; ++i) { | |
var cube = colorCubes[i] | |
check( | |
typeof cube === 'function' && cube._reglType === 'textureCube', | |
'invalid cube map') | |
radius = radius || cube.width | |
check( | |
cube.width === radius && cube.height === radius, | |
'invalid cube map shape') | |
params.color[i] = { | |
target: GL_TEXTURE_CUBE_MAP_POSITIVE_X, | |
data: colorCubes[i] | |
} | |
} | |
for (i = 0; i < 6; ++i) { | |
for (var j = 0; j < colorCubes.length; ++j) { | |
params.color[j].target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i | |
} | |
// reuse depth-stencil attachments across all cube maps | |
if (i > 0) { | |
params.depth = faces[0].depth | |
params.stencil = faces[0].stencil | |
params.depthStencil = faces[0].depthStencil | |
} | |
if (faces[i]) { | |
(faces[i])(params) | |
} else { | |
faces[i] = createFBO(params) | |
} | |
} | |
return extend(reglFramebufferCube, { | |
width: radius, | |
height: radius, | |
color: colorCubes | |
}) | |
} | |
function resize (radius_) { | |
var i | |
var radius = radius_ | 0 | |
check(radius > 0 && radius <= limits.maxCubeMapSize, | |
'invalid radius for cube fbo') | |
if (radius === reglFramebufferCube.width) { | |
return reglFramebufferCube | |
} | |
var colors = reglFramebufferCube.color | |
for (i = 0; i < colors.length; ++i) { | |
colors[i].resize(radius) | |
} | |
for (i = 0; i < 6; ++i) { | |
faces[i].resize(radius) | |
} | |
reglFramebufferCube.width = reglFramebufferCube.height = radius | |
return reglFramebufferCube | |
} | |
reglFramebufferCube(options) | |
return extend(reglFramebufferCube, { | |
faces: faces, | |
resize: resize, | |
_reglType: 'framebufferCube', | |
destroy: function () { | |
faces.forEach(function (f) { | |
f.destroy() | |
}) | |
} | |
}) | |
} | |
return extend(framebufferState, { | |
getFramebuffer: function (object) { | |
if (typeof object === 'function' && object._reglType === 'framebuffer') { | |
var fbo = object._framebuffer | |
if (fbo instanceof REGLFramebuffer) { | |
return fbo | |
} | |
} | |
return null | |
}, | |
create: createFBO, | |
createCube: createCubeFBO, | |
clear: function () { | |
values(framebufferSet).forEach(destroy) | |
} | |
}) | |
} | |
},{"./util/check":20,"./util/extend":23,"./util/values":31}],12:[function(require,module,exports){ | |
var GL_SUBPIXEL_BITS = 0x0D50 | |
var GL_RED_BITS = 0x0D52 | |
var GL_GREEN_BITS = 0x0D53 | |
var GL_BLUE_BITS = 0x0D54 | |
var GL_ALPHA_BITS = 0x0D55 | |
var GL_DEPTH_BITS = 0x0D56 | |
var GL_STENCIL_BITS = 0x0D57 | |
var GL_ALIASED_POINT_SIZE_RANGE = 0x846D | |
var GL_ALIASED_LINE_WIDTH_RANGE = 0x846E | |
var GL_MAX_TEXTURE_SIZE = 0x0D33 | |
var GL_MAX_VIEWPORT_DIMS = 0x0D3A | |
var GL_MAX_VERTEX_ATTRIBS = 0x8869 | |
var GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB | |
var GL_MAX_VARYING_VECTORS = 0x8DFC | |
var GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D | |
var GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C | |
var GL_MAX_TEXTURE_IMAGE_UNITS = 0x8872 | |
var GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD | |
var GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C | |
var GL_MAX_RENDERBUFFER_SIZE = 0x84E8 | |
var GL_VENDOR = 0x1F00 | |
var GL_RENDERER = 0x1F01 | |
var GL_VERSION = 0x1F02 | |
var GL_SHADING_LANGUAGE_VERSION = 0x8B8C | |
var GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF | |
var GL_MAX_COLOR_ATTACHMENTS_WEBGL = 0x8CDF | |
var GL_MAX_DRAW_BUFFERS_WEBGL = 0x8824 | |
module.exports = function (gl, extensions) { | |
var maxAnisotropic = 1 | |
if (extensions.ext_texture_filter_anisotropic) { | |
maxAnisotropic = gl.getParameter(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) | |
} | |
var maxDrawbuffers = 1 | |
var maxColorAttachments = 1 | |
if (extensions.webgl_draw_buffers) { | |
maxDrawbuffers = gl.getParameter(GL_MAX_DRAW_BUFFERS_WEBGL) | |
maxColorAttachments = gl.getParameter(GL_MAX_COLOR_ATTACHMENTS_WEBGL) | |
} | |
return { | |
// drawing buffer bit depth | |
colorBits: [ | |
gl.getParameter(GL_RED_BITS), | |
gl.getParameter(GL_GREEN_BITS), | |
gl.getParameter(GL_BLUE_BITS), | |
gl.getParameter(GL_ALPHA_BITS) | |
], | |
depthBits: gl.getParameter(GL_DEPTH_BITS), | |
stencilBits: gl.getParameter(GL_STENCIL_BITS), | |
subpixelBits: gl.getParameter(GL_SUBPIXEL_BITS), | |
// supported extensions | |
extensions: Object.keys(extensions).filter(function (ext) { | |
return !!extensions[ext] | |
}), | |
// max aniso samples | |
maxAnisotropic: maxAnisotropic, | |
// max draw buffers | |
maxDrawbuffers: maxDrawbuffers, | |
maxColorAttachments: maxColorAttachments, | |
// point and line size ranges | |
pointSizeDims: gl.getParameter(GL_ALIASED_POINT_SIZE_RANGE), | |
lineWidthDims: gl.getParameter(GL_ALIASED_LINE_WIDTH_RANGE), | |
maxViewportDims: gl.getParameter(GL_MAX_VIEWPORT_DIMS), | |
maxCombinedTextureUnits: gl.getParameter(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS), | |
maxCubeMapSize: gl.getParameter(GL_MAX_CUBE_MAP_TEXTURE_SIZE), | |
maxRenderbufferSize: gl.getParameter(GL_MAX_RENDERBUFFER_SIZE), | |
maxTextureUnits: gl.getParameter(GL_MAX_TEXTURE_IMAGE_UNITS), | |
maxTextureSize: gl.getParameter(GL_MAX_TEXTURE_SIZE), | |
maxAttributes: gl.getParameter(GL_MAX_VERTEX_ATTRIBS), | |
maxVertexUniforms: gl.getParameter(GL_MAX_VERTEX_UNIFORM_VECTORS), | |
maxVertexTextureUnits: gl.getParameter(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS), | |
maxVaryingVectors: gl.getParameter(GL_MAX_VARYING_VECTORS), | |
maxFragmentUniforms: gl.getParameter(GL_MAX_FRAGMENT_UNIFORM_VECTORS), | |
// vendor info | |
glsl: gl.getParameter(GL_SHADING_LANGUAGE_VERSION), | |
renderer: gl.getParameter(GL_RENDERER), | |
vendor: gl.getParameter(GL_VENDOR), | |
version: gl.getParameter(GL_VERSION) | |
} | |
} | |
},{}],13:[function(require,module,exports){ | |
var check = require('./util/check') | |
var isTypedArray = require('./util/is-typed-array') | |
var GL_RGBA = 6408 | |
var GL_UNSIGNED_BYTE = 5121 | |
var GL_PACK_ALIGNMENT = 0x0D05 | |
var GL_FLOAT = 0x1406 // 5126 | |
module.exports = function wrapReadPixels ( | |
gl, | |
framebufferState, | |
reglPoll, | |
context, | |
glAttributes, | |
extensions) { | |
function readPixels (input) { | |
var type | |
if (framebufferState.next === null) { | |
check( | |
glAttributes.preserveDrawingBuffer, | |
'you must create a webgl context with "preserveDrawingBuffer":true in order to read pixels from the drawing buffer') | |
type = GL_UNSIGNED_BYTE | |
} else { | |
check( | |
framebufferState.next.colorAttachments[0].texture !== null, | |
'You cannot read from a renderbuffer') | |
type = framebufferState.next.colorAttachments[0].texture._texture.type | |
if (extensions.oes_texture_float) { | |
check( | |
type === GL_UNSIGNED_BYTE || type === GL_FLOAT, | |
'Reading from a framebuffer is only allowed for the types \'uint8\' and \'float\'') | |
} else { | |
check( | |
type === GL_UNSIGNED_BYTE, | |
'Reading from a framebuffer is only allowed for the type \'uint8\'') | |
} | |
} | |
var x = 0 | |
var y = 0 | |
var width = context.framebufferWidth | |
var height = context.framebufferHeight | |
var data = null | |
if (isTypedArray(input)) { | |
data = input | |
} else if (input) { | |
check.type(input, 'object', 'invalid arguments to regl.read()') | |
x = input.x | 0 | |
y = input.y | 0 | |
check( | |
x >= 0 && x < context.framebufferWidth, | |
'invalid x offset for regl.read') | |
check( | |
y >= 0 && y < context.framebufferHeight, | |
'invalid y offset for regl.read') | |
width = (input.width || (context.framebufferWidth - x)) | 0 | |
height = (input.height || (context.framebufferHeight - y)) | 0 | |
data = input.data || null | |
} | |
// sanity check input.data | |
if (data) { | |
if (type === GL_UNSIGNED_BYTE) { | |
check( | |
data instanceof Uint8Array, | |
'buffer must be \'Uint8Array\' when reading from a framebuffer of type \'uint8\'') | |
} else if (type === GL_FLOAT) { | |
check( | |
data instanceof Float32Array, | |
'buffer must be \'Float32Array\' when reading from a framebuffer of type \'float\'') | |
} | |
} | |
check( | |
width > 0 && width + x <= context.framebufferWidth, | |
'invalid width for read pixels') | |
check( | |
height > 0 && height + y <= context.framebufferHeight, | |
'invalid height for read pixels') | |
// Update WebGL state | |
reglPoll() | |
// Compute size | |
var size = width * height * 4 | |
// Allocate data | |
if (!data) { | |
if (type === GL_UNSIGNED_BYTE) { | |
data = new Uint8Array(size) | |
} else if (type === GL_FLOAT) { | |
data = data || new Float32Array(size) | |
} | |
} | |
// Type check | |
check.isTypedArray(data, 'data buffer for regl.read() must be a typedarray') | |
check(data.byteLength >= size, 'data buffer for regl.read() too small') | |
// Run read pixels | |
gl.pixelStorei(GL_PACK_ALIGNMENT, 4) | |
gl.readPixels(x, y, width, height, GL_RGBA, | |
type, | |
data) | |
return data | |
} | |
return readPixels | |
} | |
},{"./util/check":20,"./util/is-typed-array":26}],14:[function(require,module,exports){ | |
var check = require('./util/check') | |
var values = require('./util/values') | |
var GL_RENDERBUFFER = 0x8D41 | |
var GL_RGBA4 = 0x8056 | |
var GL_RGB5_A1 = 0x8057 | |
var GL_RGB565 = 0x8D62 | |
var GL_DEPTH_COMPONENT16 = 0x81A5 | |
var GL_STENCIL_INDEX8 = 0x8D48 | |
var GL_DEPTH_STENCIL = 0x84F9 | |
var GL_SRGB8_ALPHA8_EXT = 0x8C43 | |
var GL_RGBA32F_EXT = 0x8814 | |
var GL_RGBA16F_EXT = 0x881A | |
var GL_RGB16F_EXT = 0x881B | |
var FORMAT_SIZES = [] | |
FORMAT_SIZES[GL_RGBA4] = 2 | |
FORMAT_SIZES[GL_RGB5_A1] = 2 | |
FORMAT_SIZES[GL_RGB565] = 2 | |
FORMAT_SIZES[GL_DEPTH_COMPONENT16] = 2 | |
FORMAT_SIZES[GL_STENCIL_INDEX8] = 1 | |
FORMAT_SIZES[GL_DEPTH_STENCIL] = 4 | |
FORMAT_SIZES[GL_SRGB8_ALPHA8_EXT] = 4 | |
FORMAT_SIZES[GL_RGBA32F_EXT] = 16 | |
FORMAT_SIZES[GL_RGBA16F_EXT] = 8 | |
FORMAT_SIZES[GL_RGB16F_EXT] = 6 | |
function getRenderbufferSize (format, width, height) { | |
return FORMAT_SIZES[format] * width * height | |
} | |
module.exports = function (gl, extensions, limits, stats, config) { | |
var formatTypes = { | |
'rgba4': GL_RGBA4, | |
'rgb565': GL_RGB565, | |
'rgb5 a1': GL_RGB5_A1, | |
'depth': GL_DEPTH_COMPONENT16, | |
'stencil': GL_STENCIL_INDEX8, | |
'depth stencil': GL_DEPTH_STENCIL | |
} | |
if (extensions.ext_srgb) { | |
formatTypes['srgba'] = GL_SRGB8_ALPHA8_EXT | |
} | |
if (extensions.ext_color_buffer_half_float) { | |
formatTypes['rgba16f'] = GL_RGBA16F_EXT | |
formatTypes['rgb16f'] = GL_RGB16F_EXT | |
} | |
if (extensions.webgl_color_buffer_float) { | |
formatTypes['rgba32f'] = GL_RGBA32F_EXT | |
} | |
var renderbufferCount = 0 | |
var renderbufferSet = {} | |
function REGLRenderbuffer (renderbuffer) { | |
this.id = renderbufferCount++ | |
this.refCount = 1 | |
this.renderbuffer = renderbuffer | |
this.format = GL_RGBA4 | |
this.width = 0 | |
this.height = 0 | |
if (config.profile) { | |
this.stats = {size: 0} | |
} | |
} | |
REGLRenderbuffer.prototype.decRef = function () { | |
if (--this.refCount <= 0) { | |
destroy(this) | |
} | |
} | |
function destroy (rb) { | |
var handle = rb.renderbuffer | |
check(handle, 'must not double destroy renderbuffer') | |
gl.bindRenderbuffer(GL_RENDERBUFFER, null) | |
gl.deleteRenderbuffer(handle) | |
rb.renderbuffer = null | |
rb.refCount = 0 | |
delete renderbufferSet[rb.id] | |
stats.renderbufferCount-- | |
} | |
function createRenderbuffer (a, b) { | |
var renderbuffer = new REGLRenderbuffer(gl.createRenderbuffer()) | |
renderbufferSet[renderbuffer.id] = renderbuffer | |
stats.renderbufferCount++ | |
function reglRenderbuffer (a, b) { | |
var w = 0 | |
var h = 0 | |
var format = GL_RGBA4 | |
if (typeof a === 'object' && a) { | |
var options = a | |
if ('shape' in options) { | |
var shape = options.shape | |
check(Array.isArray(shape) && shape.length >= 2, | |
'invalid renderbuffer shape') | |
w = shape[0] | 0 | |
h = shape[1] | 0 | |
} else { | |
if ('radius' in options) { | |
w = h = options.radius | 0 | |
} | |
if ('width' in options) { | |
w = options.width | 0 | |
} | |
if ('height' in options) { | |
h = options.height | 0 | |
} | |
} | |
if ('format' in options) { | |
check.parameter(options.format, formatTypes, | |
'invalid renderbuffer format') | |
format = formatTypes[options.format] | |
} | |
} else if (typeof a === 'number') { | |
w = a | 0 | |
if (typeof b === 'number') { | |
h = b | 0 | |
} else { | |
h = w | |
} | |
} else if (!a) { | |
w = h = 1 | |
} else { | |
check.raise('invalid arguments to renderbuffer constructor') | |
} | |
// check shape | |
check( | |
w > 0 && h > 0 && | |
w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize, | |
'invalid renderbuffer size') | |
if (w === renderbuffer.width && | |
h === renderbuffer.height && | |
format === renderbuffer.format) { | |
return | |
} | |
reglRenderbuffer.width = renderbuffer.width = w | |
reglRenderbuffer.height = renderbuffer.height = h | |
renderbuffer.format = format | |
gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer) | |
gl.renderbufferStorage(GL_RENDERBUFFER, format, w, h) | |
if (config.profile) { | |
renderbuffer.stats.size = getRenderbufferSize(renderbuffer.format, renderbuffer.width, renderbuffer.height) | |
} | |
return reglRenderbuffer | |
} | |
function resize (w_, h_) { | |
var w = w_ | 0 | |
var h = (h_ | 0) || w | |
if (w === renderbuffer.width && h === renderbuffer.height) { | |
return reglRenderbuffer | |
} | |
// check shape | |
check( | |
w > 0 && h > 0 && | |
w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize, | |
'invalid renderbuffer size') | |
reglRenderbuffer.width = renderbuffer.width = w | |
reglRenderbuffer.height = renderbuffer.height = h | |
gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer) | |
gl.renderbufferStorage(GL_RENDERBUFFER, renderbuffer.format, w, h) | |
// also, recompute size. | |
if (config.profile) { | |
renderbuffer.stats.size = getRenderbufferSize( | |
renderbuffer.format, renderbuffer.width, renderbuffer.height) | |
} | |
return reglRenderbuffer | |
} | |
reglRenderbuffer(a, b) | |
reglRenderbuffer.resize = resize | |
reglRenderbuffer._reglType = 'renderbuffer' | |
reglRenderbuffer._renderbuffer = renderbuffer | |
if (config.profile) { | |
reglRenderbuffer.stats = renderbuffer.stats | |
} | |
reglRenderbuffer.destroy = function () { | |
renderbuffer.decRef() | |
} | |
return reglRenderbuffer | |
} | |
if (config.profile) { | |
stats.getTotalRenderbufferSize = function () { | |
var total = 0 | |
Object.keys(renderbufferSet).forEach(function (key) { | |
total += renderbufferSet[key].stats.size | |
}) | |
return total | |
} | |
} | |
return { | |
create: createRenderbuffer, | |
clear: function () { | |
values(renderbufferSet).forEach(destroy) | |
} | |
} | |
} | |
},{"./util/check":20,"./util/values":31}],15:[function(require,module,exports){ | |
var check = require('./util/check') | |
var values = require('./util/values') | |
var GL_FRAGMENT_SHADER = 35632 | |
var GL_VERTEX_SHADER = 35633 | |
var GL_ACTIVE_UNIFORMS = 0x8B86 | |
var GL_ACTIVE_ATTRIBUTES = 0x8B89 | |
module.exports = function wrapShaderState (gl, stringStore, stats, config) { | |
// =================================================== | |
// glsl compilation and linking | |
// =================================================== | |
var fragShaders = {} | |
var vertShaders = {} | |
function ActiveInfo (name, id, location, info) { | |
this.name = name | |
this.id = id | |
this.location = location | |
this.info = info | |
} | |
function insertActiveInfo (list, info) { | |
for (var i = 0; i < list.length; ++i) { | |
if (list[i].id === info.id) { | |
list[i].location = info.location | |
return | |
} | |
} | |
list.push(info) | |
} | |
function getShader (type, id, command) { | |
var cache = type === GL_FRAGMENT_SHADER ? fragShaders : vertShaders | |
var shader = cache[id] | |
if (!shader) { | |
var source = stringStore.str(id) | |
shader = gl.createShader(type) | |
gl.shaderSource(shader, source) | |
gl.compileShader(shader) | |
check.shaderError(gl, shader, source, type, command) | |
cache[id] = shader | |
} | |
return shader | |
} | |
// =================================================== | |
// program linking | |
// =================================================== | |
var programCache = {} | |
var programList = [] | |
var PROGRAM_COUNTER = 0 | |
function REGLProgram (fragId, vertId) { | |
this.id = PROGRAM_COUNTER++ | |
this.fragId = fragId | |
this.vertId = vertId | |
this.program = null | |
this.uniforms = [] | |
this.attributes = [] | |
if (config.profile) { | |
this.stats = { | |
uniformsCount: 0, | |
attributesCount: 0 | |
} | |
} | |
} | |
function linkProgram (desc, command) { | |
var i, info | |
// ------------------------------- | |
// compile & link | |
// ------------------------------- | |
var fragShader = getShader(GL_FRAGMENT_SHADER, desc.fragId) | |
var vertShader = getShader(GL_VERTEX_SHADER, desc.vertId) | |
var program = desc.program = gl.createProgram() | |
gl.attachShader(program, fragShader) | |
gl.attachShader(program, vertShader) | |
gl.linkProgram(program) | |
check.linkError( | |
gl, | |
program, | |
stringStore.str(desc.fragId), | |
stringStore.str(desc.vertId), | |
command) | |
// ------------------------------- | |
// grab uniforms | |
// ------------------------------- | |
var numUniforms = gl.getProgramParameter(program, GL_ACTIVE_UNIFORMS) | |
if (config.profile) { | |
desc.stats.uniformsCount = numUniforms | |
} | |
var uniforms = desc.uniforms | |
for (i = 0; i < numUniforms; ++i) { | |
info = gl.getActiveUniform(program, i) | |
if (info) { | |
if (info.size > 1) { | |
for (var j = 0; j < info.size; ++j) { | |
var name = info.name.replace('[0]', '[' + j + ']') | |
insertActiveInfo(uniforms, new ActiveInfo( | |
name, | |
stringStore.id(name), | |
gl.getUniformLocation(program, name), | |
info)) | |
} | |
} else { | |
insertActiveInfo(uniforms, new ActiveInfo( | |
info.name, | |
stringStore.id(info.name), | |
gl.getUniformLocation(program, info.name), | |
info)) | |
} | |
} | |
} | |
// ------------------------------- | |
// grab attributes | |
// ------------------------------- | |
var numAttributes = gl.getProgramParameter(program, GL_ACTIVE_ATTRIBUTES) | |
if (config.profile) { | |
desc.stats.attributesCount = numAttributes | |
} | |
var attributes = desc.attributes | |
for (i = 0; i < numAttributes; ++i) { | |
info = gl.getActiveAttrib(program, i) | |
if (info) { | |
insertActiveInfo(attributes, new ActiveInfo( | |
info.name, | |
stringStore.id(info.name), | |
gl.getAttribLocation(program, info.name), | |
info)) | |
} | |
} | |
} | |
if (config.profile) { | |
stats.getMaxUniformsCount = function () { | |
var m = 0 | |
programList.forEach(function (desc) { | |
if (desc.stats.uniformsCount > m) { | |
m = desc.stats.uniformsCount | |
} | |
}) | |
return m | |
} | |
stats.getMaxAttributesCount = function () { | |
var m = 0 | |
programList.forEach(function (desc) { | |
if (desc.stats.attributesCount > m) { | |
m = desc.stats.attributesCount | |
} | |
}) | |
return m | |
} | |
} | |
return { | |
clear: function () { | |
var deleteShader = gl.deleteShader.bind(gl) | |
values(fragShaders).forEach(deleteShader) | |
fragShaders = {} | |
values(vertShaders).forEach(deleteShader) | |
vertShaders = {} | |
programList.forEach(function (desc) { | |
gl.deleteProgram(desc.program) | |
}) | |
programList.length = 0 | |
programCache = {} | |
stats.shaderCount = 0 | |
}, | |
program: function (vertId, fragId, command) { | |
check.command(vertId >= 0, 'missing vertex shader', command) | |
check.command(fragId >= 0, 'missing fragment shader', command) | |
stats.shaderCount++ | |
var cache = programCache[fragId] | |
if (!cache) { | |
cache = programCache[fragId] = {} | |
} | |
var program = cache[vertId] | |
if (!program) { | |
program = new REGLProgram(fragId, vertId) | |
linkProgram(program, command) | |
cache[vertId] = program | |
programList.push(program) | |
} | |
return program | |
}, | |
shader: getShader, | |
frag: -1, | |
vert: -1 | |
} | |
} | |
},{"./util/check":20,"./util/values":31}],16:[function(require,module,exports){ | |
module.exports = function stats () { | |
return { | |
bufferCount: 0, | |
elementsCount: 0, | |
framebufferCount: 0, | |
shaderCount: 0, | |
textureCount: 0, | |
cubeCount: 0, | |
renderbufferCount: 0, | |
maxTextureUnits: 0 | |
} | |
} | |
},{}],17:[function(require,module,exports){ | |
module.exports = function createStringStore () { | |
var stringIds = {'': 0} | |
var stringValues = [''] | |
return { | |
id: function (str) { | |
var result = stringIds[str] | |
if (result) { | |
return result | |
} | |
result = stringIds[str] = stringValues.length | |
stringValues.push(str) | |
return result | |
}, | |
str: function (id) { | |
return stringValues[id] | |
} | |
} | |
} | |
},{}],18:[function(require,module,exports){ | |
var check = require('./util/check') | |
var extend = require('./util/extend') | |
var values = require('./util/values') | |
var isTypedArray = require('./util/is-typed-array') | |
var isNDArrayLike = require('./util/is-ndarray') | |
var pool = require('./util/pool') | |
var convertToHalfFloat = require('./util/to-half-float') | |
var isArrayLike = require('./util/is-array-like') | |
var dtypes = require('./constants/arraytypes.json') | |
var arrayTypes = require('./constants/arraytypes.json') | |
var GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3 | |
var GL_TEXTURE_2D = 0x0DE1 | |
var GL_TEXTURE_CUBE_MAP = 0x8513 | |
var GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515 | |
var GL_RGBA = 0x1908 | |
var GL_ALPHA = 0x1906 | |
var GL_RGB = 0x1907 | |
var GL_LUMINANCE = 0x1909 | |
var GL_LUMINANCE_ALPHA = 0x190A | |
var GL_RGBA4 = 0x8056 | |
var GL_RGB5_A1 = 0x8057 | |
var GL_RGB565 = 0x8D62 | |
var GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033 | |
var GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034 | |
var GL_UNSIGNED_SHORT_5_6_5 = 0x8363 | |
var GL_UNSIGNED_INT_24_8_WEBGL = 0x84FA | |
var GL_DEPTH_COMPONENT = 0x1902 | |
var GL_DEPTH_STENCIL = 0x84F9 | |
var GL_SRGB_EXT = 0x8C40 | |
var GL_SRGB_ALPHA_EXT = 0x8C42 | |
var GL_HALF_FLOAT_OES = 0x8D61 | |
var GL_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0 | |
var GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1 | |
var GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2 | |
var GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3 | |
var GL_COMPRESSED_RGB_ATC_WEBGL = 0x8C92 | |
var GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL = 0x8C93 | |
var GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE | |
var GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00 | |
var GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01 | |
var GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02 | |
var GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03 | |
var GL_COMPRESSED_RGB_ETC1_WEBGL = 0x8D64 | |
var GL_UNSIGNED_BYTE = 0x1401 | |
var GL_UNSIGNED_SHORT = 0x1403 | |
var GL_UNSIGNED_INT = 0x1405 | |
var GL_FLOAT = 0x1406 | |
var GL_TEXTURE_WRAP_S = 0x2802 | |
var GL_TEXTURE_WRAP_T = 0x2803 | |
var GL_REPEAT = 0x2901 | |
var GL_CLAMP_TO_EDGE = 0x812F | |
var GL_MIRRORED_REPEAT = 0x8370 | |
var GL_TEXTURE_MAG_FILTER = 0x2800 | |
var GL_TEXTURE_MIN_FILTER = 0x2801 | |
var GL_NEAREST = 0x2600 | |
var GL_LINEAR = 0x2601 | |
var GL_NEAREST_MIPMAP_NEAREST = 0x2700 | |
var GL_LINEAR_MIPMAP_NEAREST = 0x2701 | |
var GL_NEAREST_MIPMAP_LINEAR = 0x2702 | |
var GL_LINEAR_MIPMAP_LINEAR = 0x2703 | |
var GL_GENERATE_MIPMAP_HINT = 0x8192 | |
var GL_DONT_CARE = 0x1100 | |
var GL_FASTEST = 0x1101 | |
var GL_NICEST = 0x1102 | |
var GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE | |
var GL_UNPACK_ALIGNMENT = 0x0CF5 | |
var GL_UNPACK_FLIP_Y_WEBGL = 0x9240 | |
var GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241 | |
var GL_UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243 | |
var GL_BROWSER_DEFAULT_WEBGL = 0x9244 | |
var GL_TEXTURE0 = 0x84C0 | |
var MIPMAP_FILTERS = [ | |
GL_NEAREST_MIPMAP_NEAREST, | |
GL_NEAREST_MIPMAP_LINEAR, | |
GL_LINEAR_MIPMAP_NEAREST, | |
GL_LINEAR_MIPMAP_LINEAR | |
] | |
var CHANNELS_FORMAT = [ | |
0, | |
GL_LUMINANCE, | |
GL_LUMINANCE_ALPHA, | |
GL_RGB, | |
GL_RGBA | |
] | |
var FORMAT_CHANNELS = {} | |
FORMAT_CHANNELS[GL_LUMINANCE] = | |
FORMAT_CHANNELS[GL_ALPHA] = | |
FORMAT_CHANNELS[GL_DEPTH_COMPONENT] = 1 | |
FORMAT_CHANNELS[GL_DEPTH_STENCIL] = | |
FORMAT_CHANNELS[GL_LUMINANCE_ALPHA] = 2 | |
FORMAT_CHANNELS[GL_RGB] = | |
FORMAT_CHANNELS[GL_SRGB_EXT] = 3 | |
FORMAT_CHANNELS[GL_RGBA] = | |
FORMAT_CHANNELS[GL_SRGB_ALPHA_EXT] = 4 | |
var formatTypes = {} | |
formatTypes[GL_RGBA4] = GL_UNSIGNED_SHORT_4_4_4_4 | |
formatTypes[GL_RGB565] = GL_UNSIGNED_SHORT_5_6_5 | |
formatTypes[GL_RGB5_A1] = GL_UNSIGNED_SHORT_5_5_5_1 | |
formatTypes[GL_DEPTH_COMPONENT] = GL_UNSIGNED_INT | |
formatTypes[GL_DEPTH_STENCIL] = GL_UNSIGNED_INT_24_8_WEBGL | |
function objectName (str) { | |
return '[object ' + str + ']' | |
} | |
var CANVAS_CLASS = objectName('HTMLCanvasElement') | |
var CONTEXT2D_CLASS = objectName('CanvasRenderingContext2D') | |
var IMAGE_CLASS = objectName('HTMLImageElement') | |
var VIDEO_CLASS = objectName('HTMLVideoElement') | |
var PIXEL_CLASSES = Object.keys(dtypes).concat([ | |
CANVAS_CLASS, | |
CONTEXT2D_CLASS, | |
IMAGE_CLASS, | |
VIDEO_CLASS | |
]) | |
// for every texture type, store | |
// the size in bytes. | |
var TYPE_SIZES = [] | |
TYPE_SIZES[GL_UNSIGNED_BYTE] = 1 | |
TYPE_SIZES[GL_FLOAT] = 4 | |
TYPE_SIZES[GL_HALF_FLOAT_OES] = 2 | |
TYPE_SIZES[GL_UNSIGNED_SHORT] = 2 | |
TYPE_SIZES[GL_UNSIGNED_INT] = 4 | |
var FORMAT_SIZES_SPECIAL = [] | |
FORMAT_SIZES_SPECIAL[GL_RGBA4] = 2 | |
FORMAT_SIZES_SPECIAL[GL_RGB5_A1] = 2 | |
FORMAT_SIZES_SPECIAL[GL_RGB565] = 2 | |
FORMAT_SIZES_SPECIAL[GL_DEPTH_STENCIL] = 4 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_S3TC_DXT1_EXT] = 0.5 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT1_EXT] = 0.5 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT3_EXT] = 1 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT5_EXT] = 1 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ATC_WEBGL] = 0.5 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL] = 1 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL] = 1 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG] = 0.5 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG] = 0.25 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG] = 0.5 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG] = 0.25 | |
FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ETC1_WEBGL] = 0.5 | |
function isNumericArray (arr) { | |
return ( | |
Array.isArray(arr) && | |
(arr.length === 0 || | |
typeof arr[0] === 'number')) | |
} | |
function isRectArray (arr) { | |
if (!Array.isArray(arr)) { | |
return false | |
} | |
var width = arr.length | |
if (width === 0 || !isArrayLike(arr[0])) { | |
return false | |
} | |
return true | |
} | |
function classString (x) { | |
return Object.prototype.toString.call(x) | |
} | |
function isCanvasElement (object) { | |
return classString(object) === CANVAS_CLASS | |
} | |
function isContext2D (object) { | |
return classString(object) === CONTEXT2D_CLASS | |
} | |
function isImageElement (object) { | |
return classString(object) === IMAGE_CLASS | |
} | |
function isVideoElement (object) { | |
return classString(object) === VIDEO_CLASS | |
} | |
function isPixelData (object) { | |
if (!object) { | |
return false | |
} | |
var className = classString(object) | |
if (PIXEL_CLASSES.indexOf(className) >= 0) { | |
return true | |
} | |
return ( | |
isNumericArray(object) || | |
isRectArray(object) || | |
isNDArrayLike(object)) | |
} | |
function typedArrayCode (data) { | |
return arrayTypes[Object.prototype.toString.call(data)] | 0 | |
} | |
function convertData (result, data) { | |
var n = result.width * result.height * result.channels | |
check(data.length === n, 'inconsistent array length for texture') | |
switch (result.type) { | |
case GL_UNSIGNED_BYTE: | |
case GL_UNSIGNED_SHORT: | |
case GL_UNSIGNED_INT: | |
case GL_FLOAT: | |
var converted = pool.allocType(result.type, n) | |
converted.set(data) | |
result.data = converted | |
break | |
case GL_HALF_FLOAT_OES: | |
result.data = convertToHalfFloat(data) | |
break | |
default: | |
check.raise('unsupported texture type, must specify a typed array') | |
} | |
} | |
function preConvert (image, n) { | |
return pool.allocType( | |
image.type === GL_HALF_FLOAT_OES | |
? GL_FLOAT | |
: image.type, n) | |
} | |
function postConvert (image, data) { | |
if (image.type === GL_HALF_FLOAT_OES) { | |
image.data = convertToHalfFloat(data) | |
pool.freeType(data) | |
} else { | |
image.data = data | |
} | |
} | |
function transposeData (image, array, strideX, strideY, strideC, offset) { | |
var w = image.width | |
var h = image.height | |
var c = image.channels | |
var n = w * h * c | |
var data = preConvert(image, n) | |
var p = 0 | |
for (var i = 0; i < h; ++i) { | |
for (var j = 0; j < w; ++j) { | |
for (var k = 0; k < c; ++k) { | |
data[p++] = array[strideX * j + strideY * i + strideC * k + offset] | |
} | |
} | |
} | |
postConvert(image, data) | |
} | |
function flatten2DData (image, array, w, h) { | |
var n = w * h | |
var data = preConvert(image, n) | |
var p = 0 | |
for (var i = 0; i < h; ++i) { | |
var row = array[i] | |
for (var j = 0; j < w; ++j) { | |
data[p++] = row[j] | |
} | |
} | |
postConvert(image, data) | |
} | |
function flatten3DData (image, array, w, h, c) { | |
var n = w * h * c | |
var data = preConvert(image, n) | |
var p = 0 | |
for (var i = 0; i < h; ++i) { | |
var row = array[i] | |
for (var j = 0; j < w; ++j) { | |
var pixel = row[j] | |
for (var k = 0; k < c; ++k) { | |
data[p++] = pixel[k] | |
} | |
} | |
} | |
postConvert(image, data) | |
} | |
function getTextureSize (format, type, width, height, isMipmap, isCube) { | |
var s | |
if (typeof FORMAT_SIZES_SPECIAL[format] !== 'undefined') { | |
// we have a special array for dealing with weird color formats such as RGB5A1 | |
s = FORMAT_SIZES_SPECIAL[format] | |
} else { | |
s = FORMAT_CHANNELS[format] * TYPE_SIZES[type] | |
} | |
if (isCube) { | |
s *= 6 | |
} | |
if (isMipmap) { | |
// compute the total size of all the mipmaps. | |
var total = 0 | |
var w = width | |
while (w >= 1) { | |
// we can only use mipmaps on a square image, | |
// so we can simply use the width and ignore the height: | |
total += s * w * w | |
w /= 2 | |
} | |
return total | |
} else { | |
return s * width * height | |
} | |
} | |
module.exports = function createTextureSet ( | |
gl, extensions, limits, reglPoll, contextState, stats, config) { | |
// ------------------------------------------------------- | |
// Initialize constants and parameter tables here | |
// ------------------------------------------------------- | |
var mipmapHint = { | |
"don't care": GL_DONT_CARE, | |
'dont care': GL_DONT_CARE, | |
'nice': GL_NICEST, | |
'fast': GL_FASTEST | |
} | |
var wrapModes = { | |
'repeat': GL_REPEAT, | |
'clamp': GL_CLAMP_TO_EDGE, | |
'mirror': GL_MIRRORED_REPEAT | |
} | |
var magFilters = { | |
'nearest': GL_NEAREST, | |
'linear': GL_LINEAR | |
} | |
var minFilters = extend({ | |
'nearest mipmap nearest': GL_NEAREST_MIPMAP_NEAREST, | |
'linear mipmap nearest': GL_LINEAR_MIPMAP_NEAREST, | |
'nearest mipmap linear': GL_NEAREST_MIPMAP_LINEAR, | |
'linear mipmap linear': GL_LINEAR_MIPMAP_LINEAR, | |
'mipmap': GL_LINEAR_MIPMAP_LINEAR | |
}, magFilters) | |
var colorSpace = { | |
'none': 0, | |
'browser': GL_BROWSER_DEFAULT_WEBGL | |
} | |
var textureTypes = { | |
'uint8': GL_UNSIGNED_BYTE, | |
'rgba4': GL_UNSIGNED_SHORT_4_4_4_4, | |
'rgb565': GL_UNSIGNED_SHORT_5_6_5, | |
'rgb5 a1': GL_UNSIGNED_SHORT_5_5_5_1 | |
} | |
var textureFormats = { | |
'alpha': GL_ALPHA, | |
'luminance': GL_LUMINANCE, | |
'luminance alpha': GL_LUMINANCE_ALPHA, | |
'rgb': GL_RGB, | |
'rgba': GL_RGBA, | |
'rgba4': GL_RGBA4, | |
'rgb5 a1': GL_RGB5_A1, | |
'rgb565': GL_RGB565 | |
} | |
var compressedTextureFormats = {} | |
if (extensions.ext_srgb) { | |
textureFormats.srgb = GL_SRGB_EXT | |
textureFormats.srgba = GL_SRGB_ALPHA_EXT | |
} | |
if (extensions.oes_texture_float) { | |
textureTypes.float32 = textureTypes.float = GL_FLOAT | |
} | |
if (extensions.oes_texture_half_float) { | |
textureTypes['float16'] = textureTypes['half float'] = GL_HALF_FLOAT_OES | |
} | |
if (extensions.webgl_depth_texture) { | |
extend(textureFormats, { | |
'depth': GL_DEPTH_COMPONENT, | |
'depth stencil': GL_DEPTH_STENCIL | |
}) | |
extend(textureTypes, { | |
'uint16': GL_UNSIGNED_SHORT, | |
'uint32': GL_UNSIGNED_INT, | |
'depth stencil': GL_UNSIGNED_INT_24_8_WEBGL | |
}) | |
} | |
if (extensions.webgl_compressed_texture_s3tc) { | |
extend(compressedTextureFormats, { | |
'rgb s3tc dxt1': GL_COMPRESSED_RGB_S3TC_DXT1_EXT, | |
'rgba s3tc dxt1': GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, | |
'rgba s3tc dxt3': GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, | |
'rgba s3tc dxt5': GL_COMPRESSED_RGBA_S3TC_DXT5_EXT | |
}) | |
} | |
if (extensions.webgl_compressed_texture_atc) { | |
extend(compressedTextureFormats, { | |
'rgb atc': GL_COMPRESSED_RGB_ATC_WEBGL, | |
'rgba atc explicit alpha': GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL, | |
'rgba atc interpolated alpha': GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL | |
}) | |
} | |
if (extensions.webgl_compressed_texture_pvrtc) { | |
extend(compressedTextureFormats, { | |
'rgb pvrtc 4bppv1': GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, | |
'rgb pvrtc 2bppv1': GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, | |
'rgba pvrtc 4bppv1': GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, | |
'rgba pvrtc 2bppv1': GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG | |
}) | |
} | |
if (extensions.webgl_compressed_texture_etc1) { | |
compressedTextureFormats['rgb etc1'] = GL_COMPRESSED_RGB_ETC1_WEBGL | |
} | |
// Copy over all texture formats | |
var supportedCompressedFormats = Array.prototype.slice.call( | |
gl.getParameter(GL_COMPRESSED_TEXTURE_FORMATS)) | |
Object.keys(compressedTextureFormats).forEach(function (name) { | |
var format = compressedTextureFormats[name] | |
if (supportedCompressedFormats.indexOf(format) >= 0) { | |
textureFormats[name] = format | |
} | |
}) | |
var supportedFormats = Object.keys(textureFormats) | |
limits.textureFormats = supportedFormats | |
// colorFormats[] gives the format (channels) associated to an | |
// internalformat | |
var colorFormats = supportedFormats.reduce(function (color, key) { | |
var glenum = textureFormats[key] | |
if (glenum === GL_LUMINANCE || | |
glenum === GL_ALPHA || | |
glenum === GL_LUMINANCE || | |
glenum === GL_LUMINANCE_ALPHA || | |
glenum === GL_DEPTH_COMPONENT || | |
glenum === GL_DEPTH_STENCIL) { | |
color[glenum] = glenum | |
} else if (glenum === GL_RGB5_A1 || key.indexOf('rgba') >= 0) { | |
color[glenum] = GL_RGBA | |
} else { | |
color[glenum] = GL_RGB | |
} | |
return color | |
}, {}) | |
function TexFlags () { | |
// format info | |
this.internalformat = GL_RGBA | |
this.format = GL_RGBA | |
this.type = GL_UNSIGNED_BYTE | |
this.compressed = false | |
// pixel storage | |
this.premultiplyAlpha = false | |
this.flipY = false | |
this.unpackAlignment = 1 | |
this.colorSpace = 0 | |
// shape info | |
this.width = 0 | |
this.height = 0 | |
this.channels = 4 | |
} | |
function copyFlags (result, other) { | |
result.internalformat = other.internalformat | |
result.format = other.format | |
result.type = other.type | |
result.compressed = other.compressed | |
result.premultiplyAlpha = other.premultiplyAlpha | |
result.flipY = other.flipY | |
result.unpackAlignment = other.unpackAlignment | |
result.colorSpace = other.colorSpace | |
result.width = other.width | |
result.height = other.height | |
result.channels = other.channels | |
} | |
function parseFlags (flags, options) { | |
if (typeof options !== 'object' || !options) { | |
return | |
} | |
if ('premultiplyAlpha' in options) { | |
check.type(options.premultiplyAlpha, 'boolean', | |
'invalid premultiplyAlpha') | |
flags.premultiplyAlpha = options.premultiplyAlpha | |
} | |
if ('flipY' in options) { | |
check.type(options.flipY, 'boolean', | |
'invalid texture flip') | |
flags.flipY = options.flipY | |
} | |
if ('alignment' in options) { | |
check.oneOf(options.alignment, [1, 2, 4, 8], | |
'invalid texture unpack alignment') | |
flags.unpackAlignment = options.alignment | |
} | |
if ('colorSpace' in options) { | |
check.parameter(options.colorSpace, colorSpace, | |
'invalid colorSpace') | |
flags.colorSpace = colorSpace[options.colorSpace] | |
} | |
if ('type' in options) { | |
var type = options.type | |
check(extensions.oes_texture_float || | |
!(type === 'float' || type === 'float32'), | |
'you must enable the OES_texture_float extension in order to use floating point textures.') | |
check(extensions.oes_texture_half_float || | |
!(type === 'half float' || type === 'float16'), | |
'you must enable the OES_texture_half_float extension in order to use 16-bit floating point textures.') | |
check(extensions.webgl_depth_texture || | |
!(type === 'depth' || type === 'depth stencil'), | |
'you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.') | |
check.parameter(type, textureTypes, | |
'invalid texture type') | |
flags.type = textureTypes[type] | |
} | |
var w = flags.width | |
var h = flags.height | |
var c = flags.channels | |
var hasChannels = false | |
if ('shape' in options) { | |
check(Array.isArray(options.shape) && options.shape.length >= 2, | |
'shape must be an array') | |
w = options.shape[0] | |
h = options.shape[1] | |
if (options.shape.length === 3) { | |
c = options.shape[2] | |
check(c > 0 && c <= 4, 'invalid number of channels') | |
hasChannels = true | |
} | |
check(w >= 0 && w <= limits.maxTextureSize, 'invalid width') | |
check(h >= 0 && h <= limits.maxTextureSize, 'invalid height') | |
} else { | |
if ('radius' in options) { | |
w = h = options.radius | |
check(w >= 0 && w <= limits.maxTextureSize, 'invalid radius') | |
} | |
if ('width' in options) { | |
w = options.width | |
check(w >= 0 && w <= limits.maxTextureSize, 'invalid width') | |
} | |
if ('height' in options) { | |
h = options.height | |
check(h >= 0 && h <= limits.maxTextureSize, 'invalid height') | |
} | |
if ('channels' in options) { | |
c = options.channels | |
check(c > 0 && c <= 4, 'invalid number of channels') | |
hasChannels = true | |
} | |
} | |
flags.width = w | 0 | |
flags.height = h | 0 | |
flags.channels = c | 0 | |
var hasFormat = false | |
if ('format' in options) { | |
var formatStr = options.format | |
check(extensions.webgl_depth_texture || | |
!(formatStr === 'depth' || formatStr === 'depth stencil'), | |
'you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.') | |
check.parameter(formatStr, textureFormats, | |
'invalid texture format') | |
var internalformat = flags.internalformat = textureFormats[formatStr] | |
flags.format = colorFormats[internalformat] | |
if (formatStr in textureTypes) { | |
if (!('type' in options)) { | |
flags.type = textureTypes[formatStr] | |
} | |
} | |
if (formatStr in compressedTextureFormats) { | |
flags.compressed = true | |
} | |
hasFormat = true | |
} | |
// Reconcile channels and format | |
if (!hasChannels && hasFormat) { | |
flags.channels = FORMAT_CHANNELS[flags.format] | |
} else if (hasChannels && !hasFormat) { | |
if (flags.channels !== CHANNELS_FORMAT[flags.format]) { | |
flags.format = flags.internalformat = CHANNELS_FORMAT[flags.channels] | |
} | |
} else if (hasFormat && hasChannels) { | |
check( | |
flags.channels === FORMAT_CHANNELS[flags.format], | |
'number of channels inconsistent with specified format') | |
} | |
} | |
function setFlags (flags) { | |
gl.pixelStorei(GL_UNPACK_FLIP_Y_WEBGL, flags.flipY) | |
gl.pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL, flags.premultiplyAlpha) | |
gl.pixelStorei(GL_UNPACK_COLORSPACE_CONVERSION_WEBGL, flags.colorSpace) | |
gl.pixelStorei(GL_UNPACK_ALIGNMENT, flags.unpackAlignment) | |
} | |
// ------------------------------------------------------- | |
// Tex image data | |
// ------------------------------------------------------- | |
function TexImage () { | |
TexFlags.call(this) | |
this.xOffset = 0 | |
this.yOffset = 0 | |
// data | |
this.data = null | |
this.needsFree = false | |
// html element | |
this.element = null | |
// copyTexImage info | |
this.needsCopy = false | |
} | |
function parseImage (image, options) { | |
var data = null | |
if (isPixelData(options)) { | |
data = options | |
} else if (options) { | |
check.type(options, 'object', 'invalid pixel data type') | |
parseFlags(image, options) | |
if ('x' in options) { | |
image.xOffset = options.x | 0 | |
} | |
if ('y' in options) { | |
image.yOffset = options.y | 0 | |
} | |
if (isPixelData(options.data)) { | |
data = options.data | |
} | |
} | |
check( | |
!image.compressed || | |
data instanceof Uint8Array, | |
'compressed texture data must be stored in a uint8array') | |
if (options.copy) { | |
check(!data, 'can not specify copy and data field for the same texture') | |
var viewW = contextState.viewportWidth | |
var viewH = contextState.viewportHeight | |
image.width = image.width || (viewW - image.xOffset) | |
image.height = image.height || (viewH - image.yOffset) | |
image.needsCopy = true | |
check(image.xOffset >= 0 && image.xOffset < viewW && | |
image.yOffset >= 0 && image.yOffset < viewH && | |
image.width > 0 && image.width <= viewW && | |
image.height > 0 && image.height <= viewH, | |
'copy texture read out of bounds') | |
} else if (!data) { | |
image.width = image.width || 1 | |
image.height = image.height || 1 | |
} else if (isTypedArray(data)) { | |
image.data = data | |
if (!('type' in options) && image.type === GL_UNSIGNED_BYTE) { | |
image.type = typedArrayCode(data) | |
} | |
} else if (isNumericArray(data)) { | |
convertData(image, data) | |
image.alignment = 1 | |
image.needsFree = true | |
} else if (isNDArrayLike(data)) { | |
var array = data.data | |
if (!Array.isArray(array) && image.type === GL_UNSIGNED_BYTE) { | |
image.type = typedArrayCode(array) | |
} | |
var shape = data.shape | |
var stride = data.stride | |
var shapeX, shapeY, shapeC, strideX, strideY, strideC | |
if (shape.length === 3) { | |
shapeC = shape[2] | |
strideC = stride[2] | |
} else { | |
check(shape.length === 2, 'invalid ndarray pixel data, must be 2 or 3D') | |
shapeC = 1 | |
strideC = 1 | |
} | |
shapeX = shape[0] | |
shapeY = shape[1] | |
strideX = stride[0] | |
strideY = stride[1] | |
image.alignment = 1 | |
image.width = shapeX | |
image.height = shapeY | |
image.channels = shapeC | |
image.format = image.internalformat = CHANNELS_FORMAT[shapeC] | |
image.needsFree = true | |
transposeData(image, array, strideX, strideY, strideC, data.offset) | |
} else if (isCanvasElement(data) || isContext2D(data)) { | |
if (isCanvasElement(data)) { | |
image.element = data | |
} else { | |
image.element = data.canvas | |
} | |
image.width = image.element.width | |
image.height = image.element.height | |
} else if (isImageElement(data)) { | |
image.element = data | |
image.width = data.naturalWidth | |
image.height = data.naturalHeight | |
} else if (isVideoElement(data)) { | |
image.element = data | |
image.width = data.videoWidth | |
image.height = data.videoHeight | |
image.needsPoll = true | |
} else if (isRectArray(data)) { | |
var w = data[0].length | |
var h = data.length | |
var c = 1 | |
if (isArrayLike(data[0][0])) { | |
c = data[0][0].length | |
flatten3DData(image, data, w, h, c) | |
} else { | |
flatten2DData(image, data, w, h) | |
} | |
image.alignment = 1 | |
image.width = w | |
image.height = h | |
image.channels = c | |
image.format = image.internalformat = CHANNELS_FORMAT[c] | |
image.needsFree = true | |
} | |
if (image.type === GL_FLOAT) { | |
check(limits.extensions.indexOf('oes_texture_float') >= 0, | |
'oes_texture_float extension not enabled') | |
} else if (image.type === GL_HALF_FLOAT_OES) { | |
check(limits.extensions.indexOf('oes_texture_half_float') >= 0, | |
'oes_texture_half_float extension not enabled') | |
} | |
// do compressed texture validation here. | |
} | |
function setImage (info, target, miplevel) { | |
var element = info.element | |
var data = info.data | |
var internalformat = info.internalformat | |
var format = info.format | |
var type = info.type | |
var width = info.width | |
var height = info.height | |
setFlags(info) | |
if (element) { | |
gl.texImage2D(target, miplevel, format, format, type, element) | |
} else if (info.compressed) { | |
gl.compressedTexImage2D(target, miplevel, internalformat, width, height, 0, data) | |
} else if (info.needsCopy) { | |
reglPoll() | |
gl.copyTexImage2D( | |
target, miplevel, format, info.xOffset, info.yOffset, width, height, 0) | |
} else { | |
gl.texImage2D( | |
target, miplevel, format, width, height, 0, format, type, data) | |
} | |
} | |
function setSubImage (info, target, x, y, miplevel) { | |
var element = info.element | |
var data = info.data | |
var internalformat = info.internalformat | |
var format = info.format | |
var type = info.type | |
var width = info.width | |
var height = info.height | |
setFlags(info) | |
if (element) { | |
gl.texSubImage2D( | |
target, miplevel, x, y, format, type, element) | |
} else if (info.compressed) { | |
gl.compressedTexSubImage2D( | |
target, miplevel, x, y, internalformat, width, height, data) | |
} else if (info.needsCopy) { | |
reglPoll() | |
gl.copyTexSubImage2D( | |
target, miplevel, x, y, info.xOffset, info.yOffset, width, height) | |
} else { | |
gl.texSubImage2D( | |
target, miplevel, x, y, width, height, format, type, data) | |
} | |
} | |
// texImage pool | |
var imagePool = [] | |
function allocImage () { | |
return imagePool.pop() || new TexImage() | |
} | |
function freeImage (image) { | |
if (image.needsFree) { | |
pool.freeType(image.data) | |
} | |
TexImage.call(image) | |
imagePool.push(image) | |
} | |
// ------------------------------------------------------- | |
// Mip map | |
// ------------------------------------------------------- | |
function MipMap () { | |
TexFlags.call(this) | |
this.genMipmaps = false | |
this.mipmapHint = GL_DONT_CARE | |
this.mipmask = 0 | |
this.images = Array(16) | |
} | |
function parseMipMapFromShape (mipmap, width, height) { | |
var img = mipmap.images[0] = allocImage() | |
mipmap.mipmask = 1 | |
img.width = mipmap.width = width | |
img.height = mipmap.height = height | |
} | |
function parseMipMapFromObject (mipmap, options) { | |
var imgData = null | |
if (isPixelData(options)) { | |
imgData = mipmap.images[0] = allocImage() | |
copyFlags(imgData, mipmap) | |
parseImage(imgData, options) | |
mipmap.mipmask = 1 | |
} else { | |
parseFlags(mipmap, options) | |
if (Array.isArray(options.mipmap)) { | |
var mipData = options.mipmap | |
for (var i = 0; i < mipData.length; ++i) { | |
imgData = mipmap.images[i] = allocImage() | |
copyFlags(imgData, mipmap) | |
imgData.width >>= i | |
imgData.height >>= i | |
parseImage(imgData, mipData[i]) | |
mipmap.mipmask |= (1 << i) | |
} | |
} else { | |
imgData = mipmap.images[0] = allocImage() | |
copyFlags(imgData, mipmap) | |
parseImage(imgData, options) | |
mipmap.mipmask = 1 | |
} | |
} | |
copyFlags(mipmap, mipmap.images[0]) | |
// For textures of the compressed format WEBGL_compressed_texture_s3tc | |
// we must have that | |
// | |
// "When level equals zero width and height must be a multiple of 4. | |
// When level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4. " | |
// | |
// but we do not yet support having multiple mipmap levels for compressed textures, | |
// so we only test for level zero. | |
if (mipmap.compressed && | |
(mipmap.internalformat === GL_COMPRESSED_RGB_S3TC_DXT1_EXT) || | |
(mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) || | |
(mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) || | |
(mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)) { | |
check(mipmap.width % 4 === 0 && | |
mipmap.height % 4 === 0, | |
'for compressed texture formats, mipmap level 0 must have width and height that are a multiple of 4') | |
} | |
} | |
function setMipMap (mipmap, target) { | |
var images = mipmap.images | |
for (var i = 0; i < images.length; ++i) { | |
if (!images[i]) { | |
return | |
} | |
setImage(images[i], target, i) | |
} | |
} | |
var mipPool = [] | |
function allocMipMap () { | |
var result = mipPool.pop() || new MipMap() | |
TexFlags.call(result) | |
result.mipmask = 0 | |
for (var i = 0; i < 16; ++i) { | |
result.images[i] = null | |
} | |
return result | |
} | |
function freeMipMap (mipmap) { | |
var images = mipmap.images | |
for (var i = 0; i < images.length; ++i) { | |
if (images[i]) { | |
freeImage(images[i]) | |
} | |
images[i] = null | |
} | |
mipPool.push(mipmap) | |
} | |
// ------------------------------------------------------- | |
// Tex info | |
// ------------------------------------------------------- | |
function TexInfo () { | |
this.minFilter = GL_NEAREST | |
this.magFilter = GL_NEAREST | |
this.wrapS = GL_CLAMP_TO_EDGE | |
this.wrapT = GL_CLAMP_TO_EDGE | |
this.anisotropic = 1 | |
this.genMipmaps = false | |
this.mipmapHint = GL_DONT_CARE | |
} | |
function parseTexInfo (info, options) { | |
if ('min' in options) { | |
var minFilter = options.min | |
check.parameter(minFilter, minFilters) | |
info.minFilter = minFilters[minFilter] | |
if (MIPMAP_FILTERS.indexOf(info.minFilter) >= 0) { | |
info.genMipmaps = true | |
} | |
} | |
if ('mag' in options) { | |
var magFilter = options.mag | |
check.parameter(magFilter, magFilters) | |
info.magFilter = magFilters[magFilter] | |
} | |
var wrapS = info.wrapS | |
var wrapT = info.wrapT | |
if ('wrap' in options) { | |
var wrap = options.wrap | |
if (typeof wrap === 'string') { | |
check.parameter(wrap, wrapModes) | |
wrapS = wrapT = wrapModes[wrap] | |
} else if (Array.isArray(wrap)) { | |
check.parameter(wrap[0], wrapModes) | |
check.parameter(wrap[1], wrapModes) | |
wrapS = wrapModes[wrap[0]] | |
wrapT = wrapModes[wrap[1]] | |
} | |
} else { | |
if ('wrapS' in options) { | |
var optWrapS = options.wrapS | |
check.parameter(optWrapS, wrapModes) | |
wrapS = wrapModes[optWrapS] | |
} | |
if ('wrapT' in options) { | |
var optWrapT = options.wrapT | |
check.parameter(optWrapT, wrapModes) | |
wrapT = wrapModes[optWrapT] | |
} | |
} | |
info.wrapS = wrapS | |
info.wrapT = wrapT | |
if ('anisotropic' in options) { | |
var anisotropic = options.anisotropic | |
check(typeof anisotropic === 'number' && | |
anisotropic >= 1 && anisotropic <= limits.maxAnisotropic, | |
'aniso samples must be between 1 and ') | |
info.anisotropic = options.anisotropic | |
} | |
if ('mipmap' in options) { | |
var hasMipMap = false | |
switch (typeof options.mipmap) { | |
case 'string': | |
check.parameter(options.mipmap, mipmapHint, | |
'invalid mipmap hint') | |
info.mipmapHint = mipmapHint[options.mipmap] | |
info.genMipmaps = true | |
hasMipMap = true | |
break | |
case 'boolean': | |
hasMipMap = info.genMipmaps = options.mipmap | |
break | |
case 'object': | |
check(Array.isArray(options.mipmap), 'invalid mipmap type') | |
info.genMipmaps = false | |
hasMipMap = true | |
break | |
default: | |
check.raise('invalid mipmap type') | |
} | |
if (hasMipMap && !('min' in options)) { | |
info.minFilter = GL_NEAREST_MIPMAP_NEAREST | |
} | |
} | |
} | |
function setTexInfo (info, target) { | |
gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, info.minFilter) | |
gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, info.magFilter) | |
gl.texParameteri(target, GL_TEXTURE_WRAP_S, info.wrapS) | |
gl.texParameteri(target, GL_TEXTURE_WRAP_T, info.wrapT) | |
if (extensions.ext_texture_filter_anisotropic) { | |
gl.texParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, info.anisotropic) | |
} | |
if (info.genMipmaps) { | |
gl.hint(GL_GENERATE_MIPMAP_HINT, info.mipmapHint) | |
gl.generateMipmap(target) | |
} | |
} | |
var infoPool = [] | |
function allocInfo () { | |
var result = infoPool.pop() || new TexInfo() | |
TexInfo.call(result) | |
return result | |
} | |
function freeInfo (info) { | |
infoPool.push(info) | |
} | |
// ------------------------------------------------------- | |
// Full texture object | |
// ------------------------------------------------------- | |
var textureCount = 0 | |
var textureSet = {} | |
var numTexUnits = limits.maxTextureUnits | |
var textureUnits = Array(numTexUnits).map(function () { | |
return null | |
}) | |
function REGLTexture (target) { | |
TexFlags.call(this) | |
this.mipmask = 0 | |
this.internalformat = GL_RGBA | |
this.id = textureCount++ | |
this.refCount = 1 | |
this.target = target | |
this.texture = gl.createTexture() | |
this.unit = -1 | |
this.bindCount = 0 | |
if (config.profile) { | |
this.stats = {size: 0} | |
} | |
} | |
function tempBind (texture) { | |
gl.activeTexture(GL_TEXTURE0) | |
gl.bindTexture(texture.target, texture.texture) | |
} | |
function tempRestore () { | |
var prev = textureUnits[0] | |
if (prev) { | |
gl.bindTexture(prev.target, prev.texture) | |
} else { | |
gl.bindTexture(GL_TEXTURE_2D, null) | |
} | |
} | |
function destroy (texture) { | |
var handle = texture.texture | |
check(handle, 'must not double destroy texture') | |
var unit = texture.unit | |
var target = texture.target | |
if (unit >= 0) { | |
gl.activeTexture(GL_TEXTURE0 + unit) | |
gl.bindTexture(target, null) | |
textureUnits[unit] = null | |
} | |
gl.deleteTexture(handle) | |
texture.texture = null | |
texture.params = null | |
texture.pixels = null | |
texture.refCount = 0 | |
delete textureSet[texture.id] | |
stats.textureCount-- | |
} | |
extend(REGLTexture.prototype, { | |
bind: function () { | |
var texture = this | |
texture.bindCount += 1 | |
var unit = texture.unit | |
if (unit < 0) { | |
for (var i = 0; i < numTexUnits; ++i) { | |
var other = textureUnits[i] | |
if (other) { | |
if (other.bindCount > 0) { | |
continue | |
} | |
other.unit = -1 | |
} | |
textureUnits[i] = texture | |
unit = i | |
break | |
} | |
if (unit >= numTexUnits) { | |
check.raise('insufficient number of texture units') | |
} | |
if (config.profile && stats.maxTextureUnits < (unit + 1)) { | |
stats.maxTextureUnits = unit + 1 // +1, since the units are zero-based | |
} | |
texture.unit = unit | |
gl.activeTexture(GL_TEXTURE0 + unit) | |
gl.bindTexture(texture.target, texture.texture) | |
} | |
return unit | |
}, | |
unbind: function () { | |
this.bindCount -= 1 | |
}, | |
decRef: function () { | |
if (--this.refCount <= 0) { | |
destroy(this) | |
} | |
} | |
}) | |
function createTexture2D (a, b) { | |
var texture = new REGLTexture(GL_TEXTURE_2D) | |
textureSet[texture.id] = texture | |
stats.textureCount++ | |
function reglTexture2D (a, b) { | |
var texInfo = allocInfo() | |
var mipData = allocMipMap() | |
if (typeof a === 'number') { | |
if (typeof b === 'number') { | |
parseMipMapFromShape(mipData, a | 0, b | 0) | |
} else { | |
parseMipMapFromShape(mipData, a | 0, a | 0) | |
} | |
} else if (a) { | |
check.type(a, 'object', 'invalid arguments to regl.texture') | |
parseTexInfo(texInfo, a) | |
parseMipMapFromObject(mipData, a) | |
} else { | |
// empty textures get assigned a default shape of 1x1 | |
parseMipMapFromShape(mipData, 1, 1) | |
} | |
if (texInfo.genMipmaps) { | |
mipData.mipmask = (mipData.width << 1) - 1 | |
} | |
texture.mipmask = mipData.mipmask | |
copyFlags(texture, mipData) | |
check.texture2D(texInfo, mipData, limits) | |
texture.internalformat = mipData.internalformat | |
reglTexture2D.width = mipData.width | |
reglTexture2D.height = mipData.height | |
tempBind(texture) | |
setMipMap(mipData, GL_TEXTURE_2D) | |
setTexInfo(texInfo, GL_TEXTURE_2D) | |
tempRestore() | |
freeInfo(texInfo) | |
freeMipMap(mipData) | |
if (config.profile) { | |
texture.stats.size = getTextureSize( | |
texture.internalformat, | |
texture.type, | |
mipData.width, | |
mipData.height, | |
texInfo.genMipmaps, | |
false) | |
} | |
return reglTexture2D | |
} | |
function subimage (image, x_, y_, level_) { | |
check(!!image, 'must specify image data') | |
var x = x_ | 0 | |
var y = y_ | 0 | |
var level = level_ | 0 | |
var imageData = allocImage() | |
copyFlags(imageData, texture) | |
imageData.width >>= level | |
imageData.height >>= level | |
imageData.width -= x | |
imageData.height -= y | |
parseImage(imageData, image) | |
check( | |
texture.type === imageData.type && | |
texture.format === imageData.format && | |
texture.internalformat === imageData.internalformat, | |
'incompatible format for texture.subimage') | |
check( | |
x >= 0 && y >= 0 && | |
x + imageData.width <= texture.width && | |
y + imageData.height <= texture.height, | |
'texture.subimage write out of bounds') | |
check( | |
texture.mipmask & (1 << level), | |
'missing mipmap data') | |
check( | |
imageData.data || imageData.element || imageData.needsCopy, | |
'missing image data') | |
tempBind(texture) | |
setSubImage(imageData, GL_TEXTURE_2D, x, y, level) | |
tempRestore() | |
freeImage(imageData) | |
return reglTexture2D | |
} | |
function resize (w_, h_) { | |
var w = w_ | 0 | |
var h = (h_ | 0) || w | |
if (w === texture.width && h === texture.height) { | |
return reglTexture2D | |
} | |
reglTexture2D.width = texture.width = w | |
reglTexture2D.height = texture.height = h | |
tempBind(texture) | |
for (var i = 0; texture.mipmask >> i; ++i) { | |
gl.texImage2D( | |
GL_TEXTURE_2D, | |
i, | |
texture.format, | |
w >> i, | |
h >> i, | |
0, | |
texture.format, | |
texture.type, | |
null) | |
} | |
tempRestore() | |
// also, recompute the texture size. | |
if (config.profile) { | |
texture.stats.size = getTextureSize( | |
texture.internalformat, | |
texture.type, | |
w, | |
h, | |
false, | |
false) | |
} | |
return reglTexture2D | |
} | |
reglTexture2D(a, b) | |
reglTexture2D.subimage = subimage | |
reglTexture2D.resize = resize | |
reglTexture2D._reglType = 'texture2d' | |
reglTexture2D._texture = texture | |
if (config.profile) { | |
reglTexture2D.stats = texture.stats | |
} | |
reglTexture2D.destroy = function () { | |
texture.decRef() | |
} | |
return reglTexture2D | |
} | |
function createTextureCube (a0, a1, a2, a3, a4, a5) { | |
var texture = new REGLTexture(GL_TEXTURE_CUBE_MAP) | |
textureSet[texture.id] = texture | |
stats.cubeCount++ | |
var faces = new Array(6) | |
function reglTextureCube (a0, a1, a2, a3, a4, a5) { | |
var i | |
var texInfo = allocInfo() | |
for (i = 0; i < 6; ++i) { | |
faces[i] = allocMipMap() | |
} | |
if (typeof a0 === 'number' || !a0) { | |
var s = (a0 | 0) || 1 | |
for (i = 0; i < 6; ++i) { | |
parseMipMapFromShape(faces[i], s, s) | |
} | |
} else if (typeof a0 === 'object') { | |
if (a1) { | |
parseMipMapFromObject(faces[0], a0) | |
parseMipMapFromObject(faces[1], a1) | |
parseMipMapFromObject(faces[2], a2) | |
parseMipMapFromObject(faces[3], a3) | |
parseMipMapFromObject(faces[4], a4) | |
parseMipMapFromObject(faces[5], a5) | |
} else { | |
parseTexInfo(texInfo, a0) | |
parseFlags(texture, a0) | |
if ('faces' in a0) { | |
var face_input = a0.faces | |
check(Array.isArray(face_input) && face_input.length === 6, | |
'cube faces must be a length 6 array') | |
for (i = 0; i < 6; ++i) { | |
check(typeof face_input[i] === 'object' && !!face_input[i], | |
'invalid input for cube map face') | |
copyFlags(faces[i], texture) | |
parseMipMapFromObject(faces[i], face_input[i]) | |
} | |
} else { | |
for (i = 0; i < 6; ++i) { | |
parseMipMapFromObject(faces[i], a0) | |
} | |
} | |
} | |
} else { | |
check.raise('invalid arguments to cube map') | |
} | |
copyFlags(texture, faces[0]) | |
if (texInfo.genMipmaps) { | |
texture.mipmask = (faces[0].width << 1) - 1 | |
} else { | |
texture.mipmask = faces[0].mipmask | |
} | |
check.textureCube(texture, texInfo, faces, limits) | |
texture.internalformat = faces[0].internalformat | |
reglTextureCube.width = faces[0].width | |
reglTextureCube.height = faces[0].height | |
tempBind(texture) | |
for (i = 0; i < 6; ++i) { | |
setMipMap(faces[i], GL_TEXTURE_CUBE_MAP_POSITIVE_X + i) | |
} | |
setTexInfo(texInfo, GL_TEXTURE_CUBE_MAP) | |
tempRestore() | |
if (config.profile) { | |
texture.stats.size = getTextureSize( | |
texture.internalformat, | |
texture.type, | |
reglTextureCube.width, | |
reglTextureCube.height, | |
texInfo.genMipmaps, | |
true) | |
} | |
freeInfo(texInfo) | |
for (i = 0; i < 6; ++i) { | |
freeMipMap(faces[i]) | |
} | |
return reglTextureCube | |
} | |
function subimage (face, image, x_, y_, level_) { | |
check(!!image, 'must specify image data') | |
check(typeof face === 'number' && face === (face | 0) && | |
face >= 0 && face < 6, 'invalid face') | |
var x = x_ | 0 | |
var y = y_ | 0 | |
var level = level_ | 0 | |
var imageData = allocImage() | |
copyFlags(imageData, texture) | |
imageData.width >>= level | |
imageData.height >>= level | |
imageData.width -= x | |
imageData.height -= y | |
parseImage(imageData, image) | |
check( | |
texture.type === imageData.type && | |
texture.format === imageData.format && | |
texture.internalformat === imageData.internalformat, | |
'incompatible format for texture.subimage') | |
check( | |
x >= 0 && y >= 0 && | |
x + imageData.width <= texture.width && | |
y + imageData.height <= texture.height, | |
'texture.subimage write out of bounds') | |
check( | |
texture.mipmask & (1 << level), | |
'missing mipmap data') | |
check( | |
imageData.data || imageData.element || imageData.needsCopy, | |
'missing image data') | |
tempBind(texture) | |
setSubImage(imageData, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, x, y, level) | |
tempRestore() | |
freeImage(imageData) | |
return reglTextureCube | |
} | |
function resize (radius_) { | |
var radius = radius_ | 0 | |
if (radius === texture.width) { | |
return | |
} | |
reglTextureCube.width = texture.width = radius | |
reglTextureCube.height = texture.height = radius | |
tempBind(texture) | |
for (var i = 0; i < 6; ++i) { | |
for (var j = 0; texture.mipmask >> j; ++j) { | |
gl.texImage2D( | |
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, | |
j, | |
texture.format, | |
radius >> j, | |
radius >> j, | |
0, | |
texture.format, | |
texture.type, | |
null) | |
} | |
} | |
tempRestore() | |
if (config.profile) { | |
texture.stats.size = getTextureSize( | |
texture.internalformat, | |
texture.type, | |
reglTextureCube.width, | |
reglTextureCube.height, | |
false, | |
true) | |
} | |
return reglTextureCube | |
} | |
reglTextureCube(a0, a1, a2, a3, a4, a5) | |
reglTextureCube.subimage = subimage | |
reglTextureCube.resize = resize | |
reglTextureCube._reglType = 'textureCube' | |
reglTextureCube._texture = texture | |
if (config.profile) { | |
reglTextureCube.stats = texture.stats | |
} | |
reglTextureCube.destroy = function () { | |
texture.decRef() | |
} | |
return reglTextureCube | |
} | |
// Called when regl is destroyed | |
function destroyTextures () { | |
for (var i = 0; i < numTexUnits; ++i) { | |
gl.activeTexture(GL_TEXTURE0 + i) | |
gl.bindTexture(GL_TEXTURE_2D, null) | |
textureUnits[i] = null | |
} | |
values(textureSet).forEach(destroy) | |
stats.cubeCount = 0 | |
stats.textureCount = 0 | |
} | |
if (config.profile) { | |
stats.getTotalTextureSize = function () { | |
var total = 0 | |
Object.keys(textureSet).forEach(function (key) { | |
total += textureSet[key].stats.size | |
}) | |
return total | |
} | |
} | |
return { | |
create2D: createTexture2D, | |
createCube: createTextureCube, | |
clear: destroyTextures, | |
getTexture: function (wrapper) { | |
return null | |
} | |
} | |
} | |
},{"./constants/arraytypes.json":3,"./util/check":20,"./util/extend":23,"./util/is-array-like":24,"./util/is-ndarray":25,"./util/is-typed-array":26,"./util/pool":28,"./util/to-half-float":30,"./util/values":31}],19:[function(require,module,exports){ | |
var GL_QUERY_RESULT_EXT = 0x8866 | |
var GL_QUERY_RESULT_AVAILABLE_EXT = 0x8867 | |
var GL_TIME_ELAPSED_EXT = 0x88BF | |
module.exports = function (gl, extensions) { | |
var extTimer = extensions.ext_disjoint_timer_query | |
if (!extTimer) { | |
return null | |
} | |
// QUERY POOL BEGIN | |
var queryPool = [] | |
function allocQuery () { | |
return queryPool.pop() || extTimer.createQueryEXT() | |
} | |
function freeQuery (query) { | |
queryPool.push(query) | |
} | |
// QUERY POOL END | |
var pendingQueries = [] | |
function beginQuery (stats) { | |
var query = allocQuery() | |
extTimer.beginQueryEXT(GL_TIME_ELAPSED_EXT, query) | |
pendingQueries.push(query) | |
pushScopeStats(pendingQueries.length - 1, pendingQueries.length, stats) | |
} | |
function endQuery () { | |
extTimer.endQueryEXT(GL_TIME_ELAPSED_EXT) | |
} | |
// | |
// Pending stats pool. | |
// | |
function PendingStats () { | |
this.startQueryIndex = -1 | |
this.endQueryIndex = -1 | |
this.sum = 0 | |
this.stats = null | |
} | |
var pendingStatsPool = [] | |
function allocPendingStats () { | |
return pendingStatsPool.pop() || new PendingStats() | |
} | |
function freePendingStats (pendingStats) { | |
pendingStatsPool.push(pendingStats) | |
} | |
// Pending stats pool end | |
var pendingStats = [] | |
function pushScopeStats (start, end, stats) { | |
var ps = allocPendingStats() | |
ps.startQueryIndex = start | |
ps.endQueryIndex = end | |
ps.sum = 0 | |
ps.stats = stats | |
pendingStats.push(ps) | |
} | |
// we should call this at the beginning of the frame, | |
// in order to update gpuTime | |
var timeSum = [] | |
var queryPtr = [] | |
function update () { | |
var ptr, i | |
var n = pendingQueries.length | |
if (n === 0) { | |
return | |
} | |
// Reserve space | |
queryPtr.length = Math.max(queryPtr.length, n + 1) | |
timeSum.length = Math.max(timeSum.length, n + 1) | |
timeSum[0] = 0 | |
queryPtr[0] = 0 | |
// Update all pending timer queries | |
var queryTime = 0 | |
ptr = 0 | |
for (i = 0; i < pendingQueries.length; ++i) { | |
var query = pendingQueries[i] | |
if (extTimer.getQueryObjectEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT)) { | |
queryTime += extTimer.getQueryObjectEXT(query, GL_QUERY_RESULT_EXT) | |
freeQuery(query) | |
} else { | |
pendingQueries[ptr++] = query | |
} | |
timeSum[i + 1] = queryTime | |
queryPtr[i + 1] = ptr | |
} | |
pendingQueries.length = ptr | |
// Update all pending stat queries | |
ptr = 0 | |
for (i = 0; i < pendingStats.length; ++i) { | |
var stats = pendingStats[i] | |
var start = stats.startQueryIndex | |
var end = stats.endQueryIndex | |
stats.sum += timeSum[end] - timeSum[start] | |
var startPtr = queryPtr[start] | |
var endPtr = queryPtr[end] | |
if (endPtr === startPtr) { | |
stats.stats.gpuTime += stats.sum / 1e6 | |
freePendingStats(stats) | |
} else { | |
stats.startQueryIndex = startPtr | |
stats.endQueryIndex = endPtr | |
pendingStats[ptr++] = stats | |
} | |
} | |
pendingStats.length = ptr | |
} | |
return { | |
beginQuery: beginQuery, | |
endQuery: endQuery, | |
pushScopeStats: pushScopeStats, | |
update: update, | |
getNumPendingQueries: function () { | |
return pendingQueries.length | |
}, | |
clear: function () { | |
queryPool.push.apply(queryPool, pendingQueries) | |
for (var i = 0; i < queryPool.length; i++) { | |
extTimer.deleteQueryEXT(queryPool[i]) | |
} | |
pendingQueries.length = 0 | |
queryPool.length = 0 | |
} | |
} | |
} | |
},{}],20:[function(require,module,exports){ | |
// Error checking and parameter validation. | |
// | |
// Statements for the form `check.someProcedure(...)` get removed by | |
// a browserify transform for optimized/minified bundles. | |
// | |
/* globals btoa */ | |
var isTypedArray = require('./is-typed-array') | |
var extend = require('./extend') | |
// only used for extracting shader names. if btoa not present, then errors | |
// will be slightly crappier | |
function decodeB64 (str) { | |
if (typeof btoa !== 'undefined') { | |
return btoa(str) | |
} | |
return 'base64:' + str | |
} | |
function raise (message) { | |
var error = new Error('(regl) ' + message) | |
console.error(error) | |
throw error | |
} | |
function check (pred, message) { | |
if (!pred) { | |
raise(message) | |
} | |
} | |
function encolon (message) { | |
if (message) { | |
return ': ' + message | |
} | |
return '' | |
} | |
function checkParameter (param, possibilities, message) { | |
if (!(param in possibilities)) { | |
raise('unknown parameter (' + param + ')' + encolon(message) + | |
'. possible values: ' + Object.keys(possibilities).join()) | |
} | |
} | |
function checkIsTypedArray (data, message) { | |
if (!isTypedArray(data)) { | |
raise( | |
'invalid parameter type' + encolon(message) + | |
'. must be a typed array') | |
} | |
} | |
function checkTypeOf (value, type, message) { | |
if (typeof value !== type) { | |
raise( | |
'invalid parameter type' + encolon(message) + | |
'. expected ' + type + ', got ' + (typeof value)) | |
} | |
} | |
function checkNonNegativeInt (value, message) { | |
if (!((value >= 0) && | |
((value | 0) === value))) { | |
raise('invalid parameter type, (' + value + ')' + encolon(message) + | |
'. must be a nonnegative integer') | |
} | |
} | |
function checkOneOf (value, list, message) { | |
if (list.indexOf(value) < 0) { | |
raise('invalid value' + encolon(message) + '. must be one of: ' + list) | |
} | |
} | |
var constructorKeys = [ | |
'gl', | |
'canvas', | |
'container', | |
'attributes', | |
'pixelRatio', | |
'extensions', | |
'optionalExtensions', | |
'profile', | |
'onDone' | |
] | |
function checkConstructor (obj) { | |
Object.keys(obj).forEach(function (key) { | |
if (constructorKeys.indexOf(key) < 0) { | |
raise('invalid regl constructor argument "' + key + '". must be one of ' + constructorKeys) | |
} | |
}) | |
} | |
function leftPad (str, n) { | |
str = str + '' | |
while (str.length < n) { | |
str = ' ' + str | |
} | |
return str | |
} | |
function ShaderFile () { | |
this.name = 'unknown' | |
this.lines = [] | |
this.index = {} | |
this.hasErrors = false | |
} | |
function ShaderLine (number, line) { | |
this.number = number | |
this.line = line | |
this.errors = [] | |
} | |
function ShaderError (fileNumber, lineNumber, message) { | |
this.file = fileNumber | |
this.line = lineNumber | |
this.message = message | |
} | |
function guessCommand () { | |
var error = new Error() | |
var stack = (error.stack || error).toString() | |
var pat = /compileProcedure.*\n\s*at.*\((.*)\)/.exec(stack) | |
if (pat) { | |
return pat[1] | |
} | |
var pat2 = /compileProcedure.*\n\s*at\s+(.*)(\n|$)/.exec(stack) | |
if (pat2) { | |
return pat2[1] | |
} | |
return 'unknown' | |
} | |
function guessCallSite () { | |
var error = new Error() | |
var stack = (error.stack || error).toString() | |
var pat = /at REGLCommand.*\n\s+at.*\((.*)\)/.exec(stack) | |
if (pat) { | |
return pat[1] | |
} | |
var pat2 = /at REGLCommand.*\n\s+at\s+(.*)\n/.exec(stack) | |
if (pat2) { | |
return pat2[1] | |
} | |
return 'unknown' | |
} | |
function parseSource (source, command) { | |
var lines = source.split('\n') | |
var lineNumber = 1 | |
var fileNumber = 0 | |
var files = { | |
unknown: new ShaderFile(), | |
0: new ShaderFile() | |
} | |
files.unknown.name = files[0].name = command || guessCommand() | |
files.unknown.lines.push(new ShaderLine(0, '')) | |
for (var i = 0; i < lines.length; ++i) { | |
var line = lines[i] | |
var parts = /^\s*\#\s*(\w+)\s+(.+)\s*$/.exec(line) | |
if (parts) { | |
switch (parts[1]) { | |
case 'line': | |
var lineNumberInfo = /(\d+)(\s+\d+)?/.exec(parts[2]) | |
if (lineNumberInfo) { | |
lineNumber = lineNumberInfo[1] | 0 | |
if (lineNumberInfo[2]) { | |
fileNumber = lineNumberInfo[2] | 0 | |
if (!(fileNumber in files)) { | |
files[fileNumber] = new ShaderFile() | |
} | |
} | |
} | |
break | |
case 'define': | |
var nameInfo = /SHADER_NAME(_B64)?\s+(.*)$/.exec(parts[2]) | |
if (nameInfo) { | |
files[fileNumber].name = (nameInfo[1] | |
? decodeB64(nameInfo[2]) | |
: nameInfo[2]) | |
} | |
break | |
} | |
} | |
files[fileNumber].lines.push(new ShaderLine(lineNumber++, line)) | |
} | |
Object.keys(files).forEach(function (fileNumber) { | |
var file = files[fileNumber] | |
file.lines.forEach(function (line) { | |
file.index[line.number] = line | |
}) | |
}) | |
return files | |
} | |
function parseErrorLog (errLog) { | |
var result = [] | |
errLog.split('\n').forEach(function (errMsg) { | |
if (errMsg.length < 5) { | |
return | |
} | |
var parts = /^ERROR\:\s+(\d+)\:(\d+)\:\s*(.*)$/.exec(errMsg) | |
if (parts) { | |
result.push(new ShaderError( | |
parts[1] | 0, | |
parts[2] | 0, | |
parts[3].trim())) | |
} else if (errMsg.length > 0) { | |
result.push(new ShaderError('unknown', 0, errMsg)) | |
} | |
}) | |
return result | |
} | |
function annotateFiles (files, errors) { | |
errors.forEach(function (error) { | |
var file = files[error.file] | |
if (file) { | |
var line = file.index[error.line] | |
if (line) { | |
line.errors.push(error) | |
file.hasErrors = true | |
return | |
} | |
} | |
files.unknown.hasErrors = true | |
files.unknown.lines[0].errors.push(error) | |
}) | |
} | |
function checkShaderError (gl, shader, source, type, command) { | |
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { | |
var errLog = gl.getShaderInfoLog(shader) | |
var typeName = type === gl.FRAGMENT_SHADER ? 'fragment' : 'vertex' | |
var files = parseSource(source, command) | |
var errors = parseErrorLog(errLog) | |
annotateFiles(files, errors) | |
Object.keys(files).forEach(function (fileNumber) { | |
var file = files[fileNumber] | |
if (!file.hasErrors) { | |
return | |
} | |
var strings = [''] | |
var styles = [''] | |
function push (str, style) { | |
strings.push(str) | |
styles.push(style || '') | |
} | |
push('file number ' + fileNumber + ': ' + file.name + '\n', 'color:red;text-decoration:underline;font-weight:bold') | |
file.lines.forEach(function (line) { | |
if (line.errors.length > 0) { | |
push(leftPad(line.number, 4) + '| ', 'background-color:yellow; font-weight:bold') | |
push(line.line + '\n', 'color:red; background-color:yellow; font-weight:bold') | |
// try to guess token | |
var offset = 0 | |
line.errors.forEach(function (error) { | |
var message = error.message | |
var token = /^\s*\'(.*)\'\s*\:\s*(.*)$/.exec(message) | |
if (token) { | |
var tokenPat = token[1] | |
message = token[2] | |
switch (tokenPat) { | |
case 'assign': | |
tokenPat = '=' | |
break | |
} | |
offset = Math.max(line.line.indexOf(tokenPat, offset), 0) | |
} else { | |
offset = 0 | |
} | |
push(leftPad('| ', 6)) | |
push(leftPad('^^^', offset + 3) + '\n', 'font-weight:bold') | |
push(leftPad('| ', 6)) | |
push(message + '\n', 'font-weight:bold') | |
}) | |
push(leftPad('| ', 6) + '\n') | |
} else { | |
push(leftPad(line.number, 4) + '| ') | |
push(line.line + '\n', 'color:red') | |
} | |
}) | |
if (typeof document !== 'undefined') { | |
styles[0] = strings.join('%c') | |
console.log.apply(console, styles) | |
} else { | |
console.log(strings.join('')) | |
} | |
}) | |
check.raise('Error compiling ' + typeName + ' shader, ' + files[0].name) | |
} | |
} | |
function checkLinkError (gl, program, fragShader, vertShader, command) { | |
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { | |
var errLog = gl.getProgramInfoLog(program) | |
var fragParse = parseSource(fragShader, command) | |
var vertParse = parseSource(vertShader, command) | |
var header = 'Error linking program with vertex shader, "' + | |
vertParse[0].name + '", and fragment shader "' + fragParse[0].name + '"' | |
if (typeof document !== 'undefined') { | |
console.log('%c' + header + '\n%c' + errLog, | |
'color:red;text-decoration:underline;font-weight:bold', | |
'color:red') | |
} else { | |
console.log(header + '\n' + errLog) | |
} | |
check.raise(header) | |
} | |
} | |
function saveCommandRef (object) { | |
object._commandRef = guessCommand() | |
} | |
function saveDrawCommandInfo (opts, uniforms, attributes, stringStore) { | |
saveCommandRef(opts) | |
function id (str) { | |
if (str) { | |
return stringStore.id(str) | |
} | |
return 0 | |
} | |
opts._fragId = id(opts.static.frag) | |
opts._vertId = id(opts.static.vert) | |
function addProps (dict, set) { | |
Object.keys(set).forEach(function (u) { | |
dict[stringStore.id(u)] = true | |
}) | |
} | |
var uniformSet = opts._uniformSet = {} | |
addProps(uniformSet, uniforms.static) | |
addProps(uniformSet, uniforms.dynamic) | |
var attributeSet = opts._attributeSet = {} | |
addProps(attributeSet, attributes.static) | |
addProps(attributeSet, attributes.dynamic) | |
opts._hasCount = ( | |
'count' in opts.static || | |
'count' in opts.dynamic || | |
'elements' in opts.static || | |
'elements' in opts.dynamic) | |
} | |
function commandRaise (message, command) { | |
var callSite = guessCallSite() | |
raise(message + | |
' in command ' + (command || guessCommand()) + | |
(callSite === 'unknown' ? '' : ' called from ' + callSite)) | |
} | |
function checkCommand (pred, message, command) { | |
if (!pred) { | |
commandRaise(message, command || guessCommand()) | |
} | |
} | |
function checkParameterCommand (param, possibilities, message, command) { | |
if (!(param in possibilities)) { | |
commandRaise( | |
'unknown parameter (' + param + ')' + encolon(message) + | |
'. possible values: ' + Object.keys(possibilities).join(), | |
command || guessCommand()) | |
} | |
} | |
function checkCommandType (value, type, message, command) { | |
if (typeof value !== type) { | |
commandRaise( | |
'invalid parameter type' + encolon(message) + | |
'. expected ' + type + ', got ' + (typeof value), | |
command || guessCommand()) | |
} | |
} | |
function checkOptional (block) { | |
block() | |
} | |
function checkFramebufferFormat (attachment, texFormats, rbFormats) { | |
if (attachment.texture) { | |
checkOneOf( | |
attachment.texture._texture.internalformat, | |
texFormats, | |
'unsupported texture format for attachment') | |
} else { | |
checkOneOf( | |
attachment.renderbuffer._renderbuffer.format, | |
rbFormats, | |
'unsupported renderbuffer format for attachment') | |
} | |
} | |
var GL_CLAMP_TO_EDGE = 0x812F | |
var GL_NEAREST = 0x2600 | |
var GL_NEAREST_MIPMAP_NEAREST = 0x2700 | |
var GL_LINEAR_MIPMAP_NEAREST = 0x2701 | |
var GL_NEAREST_MIPMAP_LINEAR = 0x2702 | |
var GL_LINEAR_MIPMAP_LINEAR = 0x2703 | |
var GL_BYTE = 5120 | |
var GL_UNSIGNED_BYTE = 5121 | |
var GL_SHORT = 5122 | |
var GL_UNSIGNED_SHORT = 5123 | |
var GL_INT = 5124 | |
var GL_UNSIGNED_INT = 5125 | |
var GL_FLOAT = 5126 | |
var GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033 | |
var GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034 | |
var GL_UNSIGNED_SHORT_5_6_5 = 0x8363 | |
var GL_UNSIGNED_INT_24_8_WEBGL = 0x84FA | |
var GL_HALF_FLOAT_OES = 0x8D61 | |
var TYPE_SIZE = {} | |
TYPE_SIZE[GL_BYTE] = | |
TYPE_SIZE[GL_UNSIGNED_BYTE] = 1 | |
TYPE_SIZE[GL_SHORT] = | |
TYPE_SIZE[GL_UNSIGNED_SHORT] = | |
TYPE_SIZE[GL_HALF_FLOAT_OES] = | |
TYPE_SIZE[GL_UNSIGNED_SHORT_5_6_5] = | |
TYPE_SIZE[GL_UNSIGNED_SHORT_4_4_4_4] = | |
TYPE_SIZE[GL_UNSIGNED_SHORT_5_5_5_1] = 2 | |
TYPE_SIZE[GL_INT] = | |
TYPE_SIZE[GL_UNSIGNED_INT] = | |
TYPE_SIZE[GL_FLOAT] = | |
TYPE_SIZE[GL_UNSIGNED_INT_24_8_WEBGL] = 4 | |
function pixelSize (type, channels) { | |
if (type === GL_UNSIGNED_SHORT_5_5_5_1 || | |
type === GL_UNSIGNED_SHORT_4_4_4_4 || | |
type === GL_UNSIGNED_SHORT_5_6_5) { | |
return 2 | |
} else if (type === GL_UNSIGNED_INT_24_8_WEBGL) { | |
return 4 | |
} else { | |
return TYPE_SIZE[type] * channels | |
} | |
} | |
function isPow2 (v) { | |
return !(v & (v - 1)) && (!!v) | |
} | |
function checkTexture2D (info, mipData, limits) { | |
var i | |
var w = mipData.width | |
var h = mipData.height | |
var c = mipData.channels | |
// Check texture shape | |
check(w > 0 && w <= limits.maxTextureSize && | |
h > 0 && h <= limits.maxTextureSize, | |
'invalid texture shape') | |
// check wrap mode | |
if (info.wrapS !== GL_CLAMP_TO_EDGE || info.wrapT !== GL_CLAMP_TO_EDGE) { | |
check(isPow2(w) && isPow2(h), | |
'incompatible wrap mode for texture, both width and height must be power of 2') | |
} | |
if (mipData.mipmask === 1) { | |
if (w !== 1 && h !== 1) { | |
check( | |
info.minFilter !== GL_NEAREST_MIPMAP_NEAREST && | |
info.minFilter !== GL_NEAREST_MIPMAP_LINEAR && | |
info.minFilter !== GL_LINEAR_MIPMAP_NEAREST && | |
info.minFilter !== GL_LINEAR_MIPMAP_LINEAR, | |
'min filter requires mipmap') | |
} | |
} else { | |
// texture must be power of 2 | |
check(isPow2(w) && isPow2(h), | |
'texture must be a square power of 2 to support mipmapping') | |
check(mipData.mipmask === (w << 1) - 1, | |
'missing or incomplete mipmap data') | |
} | |
if (mipData.type === GL_FLOAT) { | |
if (limits.extensions.indexOf('oes_texture_float_linear') < 0) { | |
check(info.minFilter === GL_NEAREST && info.magFilter === GL_NEAREST, | |
'filter not supported, must enable oes_texture_float_linear') | |
} | |
check(!info.genMipmaps, | |
'mipmap generation not supported with float textures') | |
} | |
// check image complete | |
var mipimages = mipData.images | |
for (i = 0; i < 16; ++i) { | |
if (mipimages[i]) { | |
var mw = w >> i | |
var mh = h >> i | |
check(mipData.mipmask & (1 << i), 'missing mipmap data') | |
var img = mipimages[i] | |
check( | |
img.width === mw && | |
img.height === mh, | |
'invalid shape for mip images') | |
check( | |
img.format === mipData.format && | |
img.internalformat === mipData.internalformat && | |
img.type === mipData.type, | |
'incompatible type for mip image') | |
if (img.compressed) { | |
// TODO: check size for compressed images | |
} else if (img.data) { | |
check(img.data.byteLength === mw * mh * | |
Math.max(pixelSize(img.type, c), img.unpackAlignment), | |
'invalid data for image, buffer size is inconsistent with image format') | |
} else if (img.element) { | |
// TODO: check element can be loaded | |
} else if (img.copy) { | |
// TODO: check compatible format and type | |
} | |
} else if (!info.genMipmaps) { | |
check((mipData.mipmask & (1 << i)) === 0, 'extra mipmap data') | |
} | |
} | |
if (mipData.compressed) { | |
check(!info.genMipmaps, | |
'mipmap generation for compressed images not supported') | |
} | |
} | |
function checkTextureCube (texture, info, faces, limits) { | |
var w = texture.width | |
var h = texture.height | |
var c = texture.channels | |
// Check texture shape | |
check( | |
w > 0 && w <= limits.maxTextureSize && h > 0 && h <= limits.maxTextureSize, | |
'invalid texture shape') | |
check( | |
w === h, | |
'cube map must be square') | |
check( | |
info.wrapS === GL_CLAMP_TO_EDGE && info.wrapT === GL_CLAMP_TO_EDGE, | |
'wrap mode not supported by cube map') | |
for (var i = 0; i < faces.length; ++i) { | |
var face = faces[i] | |
check( | |
face.width === w && face.height === h, | |
'inconsistent cube map face shape') | |
if (info.genMipmaps) { | |
check(!face.compressed, | |
'can not generate mipmap for compressed textures') | |
check(face.mipmask === 1, | |
'can not specify mipmaps and generate mipmaps') | |
} else { | |
// TODO: check mip and filter mode | |
} | |
var mipmaps = face.images | |
for (var j = 0; j < 16; ++j) { | |
var img = mipmaps[j] | |
if (img) { | |
var mw = w >> j | |
var mh = h >> j | |
check(face.mipmask & (1 << j), 'missing mipmap data') | |
check( | |
img.width === mw && | |
img.height === mh, | |
'invalid shape for mip images') | |
check( | |
img.format === texture.format && | |
img.internalformat === texture.internalformat && | |
img.type === texture.type, | |
'incompatible type for mip image') | |
if (img.compressed) { | |
// TODO: check size for compressed images | |
} else if (img.data) { | |
check(img.data.byteLength === mw * mh * | |
Math.max(pixelSize(img.type, c), img.unpackAlignment), | |
'invalid data for image, buffer size is inconsistent with image format') | |
} else if (img.element) { | |
// TODO: check element can be loaded | |
} else if (img.copy) { | |
// TODO: check compatible format and type | |
} | |
} | |
} | |
} | |
} | |
module.exports = extend(check, { | |
optional: checkOptional, | |
raise: raise, | |
commandRaise: commandRaise, | |
command: checkCommand, | |
parameter: checkParameter, | |
commandParameter: checkParameterCommand, | |
constructor: checkConstructor, | |
type: checkTypeOf, | |
commandType: checkCommandType, | |
isTypedArray: checkIsTypedArray, | |
nni: checkNonNegativeInt, | |
oneOf: checkOneOf, | |
shaderError: checkShaderError, | |
linkError: checkLinkError, | |
callSite: guessCallSite, | |
saveCommandRef: saveCommandRef, | |
saveDrawInfo: saveDrawCommandInfo, | |
framebufferFormat: checkFramebufferFormat, | |
guessCommand: guessCommand, | |
texture2D: checkTexture2D, | |
textureCube: checkTextureCube | |
}) | |
},{"./extend":23,"./is-typed-array":26}],21:[function(require,module,exports){ | |
/* globals performance */ | |
module.exports = | |
(typeof performance !== 'undefined' && performance.now) | |
? function () { return performance.now() } | |
: function () { return +(new Date()) } | |
},{}],22:[function(require,module,exports){ | |
var extend = require('./extend') | |
function slice (x) { | |
return Array.prototype.slice.call(x) | |
} | |
function join (x) { | |
return slice(x).join('') | |
} | |
module.exports = function createEnvironment () { | |
// Unique variable id counter | |
var varCounter = 0 | |
// Linked values are passed from this scope into the generated code block | |
// Calling link() passes a value into the generated scope and returns | |
// the variable name which it is bound to | |
var linkedNames = [] | |
var linkedValues = [] | |
function link (value) { | |
for (var i = 0; i < linkedValues.length; ++i) { | |
if (linkedValues[i] === value) { | |
return linkedNames[i] | |
} | |
} | |
var name = 'g' + (varCounter++) | |
linkedNames.push(name) | |
linkedValues.push(value) | |
return name | |
} | |
// create a code block | |
function block () { | |
var code = [] | |
function push () { | |
code.push.apply(code, slice(arguments)) | |
} | |
var vars = [] | |
function def () { | |
var name = 'v' + (varCounter++) | |
vars.push(name) | |
if (arguments.length > 0) { | |
code.push(name, '=') | |
code.push.apply(code, slice(arguments)) | |
code.push(';') | |
} | |
return name | |
} | |
return extend(push, { | |
def: def, | |
toString: function () { | |
return join([ | |
(vars.length > 0 ? 'var ' + vars + ';' : ''), | |
join(code) | |
]) | |
} | |
}) | |
} | |
function scope () { | |
var entry = block() | |
var exit = block() | |
var entryToString = entry.toString | |
var exitToString = exit.toString | |
function save (object, prop) { | |
exit(object, prop, '=', entry.def(object, prop), ';') | |
} | |
return extend(function () { | |
entry.apply(entry, slice(arguments)) | |
}, { | |
def: entry.def, | |
entry: entry, | |
exit: exit, | |
save: save, | |
set: function (object, prop, value) { | |
save(object, prop) | |
entry(object, prop, '=', value, ';') | |
}, | |
toString: function () { | |
return entryToString() + exitToString() | |
} | |
}) | |
} | |
function conditional () { | |
var pred = join(arguments) | |
var thenBlock = scope() | |
var elseBlock = scope() | |
var thenToString = thenBlock.toString | |
var elseToString = elseBlock.toString | |
return extend(thenBlock, { | |
then: function () { | |
thenBlock.apply(thenBlock, slice(arguments)) | |
return this | |
}, | |
else: function () { | |
elseBlock.apply(elseBlock, slice(arguments)) | |
return this | |
}, | |
toString: function () { | |
var elseClause = elseToString() | |
if (elseClause) { | |
elseClause = 'else{' + elseClause + '}' | |
} | |
return join([ | |
'if(', pred, '){', | |
thenToString(), | |
'}', elseClause | |
]) | |
} | |
}) | |
} | |
// procedure list | |
var globalBlock = block() | |
var procedures = {} | |
function proc (name, count) { | |
var args = [] | |
function arg () { | |
var name = 'a' + args.length | |
args.push(name) | |
return name | |
} | |
count = count || 0 | |
for (var i = 0; i < count; ++i) { | |
arg() | |
} | |
var body = scope() | |
var bodyToString = body.toString | |
var result = procedures[name] = extend(body, { | |
arg: arg, | |
toString: function () { | |
return join([ | |
'function(', args.join(), '){', | |
bodyToString(), | |
'}' | |
]) | |
} | |
}) | |
return result | |
} | |
function compile () { | |
var code = ['"use strict";', | |
globalBlock, | |
'return {'] | |
Object.keys(procedures).forEach(function (name) { | |
code.push('"', name, '":', procedures[name].toString(), ',') | |
}) | |
code.push('}') | |
var src = join(code) | |
.replace(/;/g, ';\n') | |
.replace(/}/g, '}\n') | |
.replace(/{/g, '{\n') | |
var proc = Function.apply(null, linkedNames.concat(src)) | |
return proc.apply(null, linkedValues) | |
} | |
return { | |
global: globalBlock, | |
link: link, | |
block: block, | |
proc: proc, | |
scope: scope, | |
cond: conditional, | |
compile: compile | |
} | |
} | |
},{"./extend":23}],23:[function(require,module,exports){ | |
module.exports = function (base, opts) { | |
var keys = Object.keys(opts) | |
for (var i = 0; i < keys.length; ++i) { | |
base[keys[i]] = opts[keys[i]] | |
} | |
return base | |
} | |
},{}],24:[function(require,module,exports){ | |
var isTypedArray = require('./is-typed-array') | |
module.exports = function isArrayLike (s) { | |
return Array.isArray(s) || isTypedArray(s) | |
} | |
},{"./is-typed-array":26}],25:[function(require,module,exports){ | |
var isTypedArray = require('./is-typed-array') | |
module.exports = function isNDArrayLike (obj) { | |
return ( | |
!!obj && | |
typeof obj === 'object' && | |
Array.isArray(obj.shape) && | |
Array.isArray(obj.stride) && | |
typeof obj.offset === 'number' && | |
obj.shape.length === obj.stride.length && | |
(Array.isArray(obj.data) || | |
isTypedArray(obj.data))) | |
} | |
},{"./is-typed-array":26}],26:[function(require,module,exports){ | |
var dtypes = require('../constants/arraytypes.json') | |
module.exports = function (x) { | |
return Object.prototype.toString.call(x) in dtypes | |
} | |
},{"../constants/arraytypes.json":3}],27:[function(require,module,exports){ | |
module.exports = function loop (n, f) { | |
var result = Array(n) | |
for (var i = 0; i < n; ++i) { | |
result[i] = f(i) | |
} | |
return result | |
} | |
},{}],28:[function(require,module,exports){ | |
var loop = require('./loop') | |
var GL_BYTE = 5120 | |
var GL_UNSIGNED_BYTE = 5121 | |
var GL_SHORT = 5122 | |
var GL_UNSIGNED_SHORT = 5123 | |
var GL_INT = 5124 | |
var GL_UNSIGNED_INT = 5125 | |
var GL_FLOAT = 5126 | |
var bufferPool = loop(8, function () { | |
return [] | |
}) | |
function nextPow16 (v) { | |
for (var i = 16; i <= (1 << 28); i *= 16) { | |
if (v <= i) { | |
return i | |
} | |
} | |
return 0 | |
} | |
function log2 (v) { | |
var r, shift | |
r = (v > 0xFFFF) << 4 | |
v >>>= r | |
shift = (v > 0xFF) << 3 | |
v >>>= shift; r |= shift | |
shift = (v > 0xF) << 2 | |
v >>>= shift; r |= shift | |
shift = (v > 0x3) << 1 | |
v >>>= shift; r |= shift | |
return r | (v >> 1) | |
} | |
function alloc (n) { | |
var sz = nextPow16(n) | |
var bin = bufferPool[log2(sz) >> 2] | |
if (bin.length > 0) { | |
return bin.pop() | |
} | |
return new ArrayBuffer(sz) | |
} | |
function free (buf) { | |
bufferPool[log2(buf.byteLength) >> 2].push(buf) | |
} | |
function allocType (type, n) { | |
var result = null | |
switch (type) { | |
case GL_BYTE: | |
result = new Int8Array(alloc(n), 0, n) | |
break | |
case GL_UNSIGNED_BYTE: | |
result = new Uint8Array(alloc(n), 0, n) | |
break | |
case GL_SHORT: | |
result = new Int16Array(alloc(2 * n), 0, n) | |
break | |
case GL_UNSIGNED_SHORT: | |
result = new Uint16Array(alloc(2 * n), 0, n) | |
break | |
case GL_INT: | |
result = new Int32Array(alloc(4 * n), 0, n) | |
break | |
case GL_UNSIGNED_INT: | |
result = new Uint32Array(alloc(4 * n), 0, n) | |
break | |
case GL_FLOAT: | |
result = new Float32Array(alloc(4 * n), 0, n) | |
break | |
default: | |
return null | |
} | |
if (result.length !== n) { | |
return result.subarray(0, n) | |
} | |
return result | |
} | |
function freeType (array) { | |
free(array.buffer) | |
} | |
module.exports = { | |
alloc: alloc, | |
free: free, | |
allocType: allocType, | |
freeType: freeType | |
} | |
},{"./loop":27}],29:[function(require,module,exports){ | |
/* globals requestAnimationFrame, cancelAnimationFrame */ | |
if (typeof requestAnimationFrame === 'function' && | |
typeof cancelAnimationFrame === 'function') { | |
module.exports = { | |
next: function (x) { return requestAnimationFrame(x) }, | |
cancel: function (x) { return cancelAnimationFrame(x) } | |
} | |
} else { | |
module.exports = { | |
next: function (cb) { | |
return setTimeout(cb, 16) | |
}, | |
cancel: clearTimeout | |
} | |
} | |
},{}],30:[function(require,module,exports){ | |
var pool = require('./pool') | |
var FLOAT = new Float32Array(1) | |
var INT = new Uint32Array(FLOAT.buffer) | |
var GL_UNSIGNED_SHORT = 5123 | |
module.exports = function convertToHalfFloat (array) { | |
var ushorts = pool.allocType(GL_UNSIGNED_SHORT, array.length) | |
for (var i = 0; i < array.length; ++i) { | |
if (isNaN(array[i])) { | |
ushorts[i] = 0xffff | |
} else if (array[i] === Infinity) { | |
ushorts[i] = 0x7c00 | |
} else if (array[i] === -Infinity) { | |
ushorts[i] = 0xfc00 | |
} else { | |
FLOAT[0] = array[i] | |
var x = INT[0] | |
var sgn = (x >>> 31) << 15 | |
var exp = ((x << 1) >>> 24) - 127 | |
var frac = (x >> 13) & ((1 << 10) - 1) | |
if (exp < -24) { | |
// round non-representable denormals to 0 | |
ushorts[i] = sgn | |
} else if (exp < -14) { | |
// handle denormals | |
var s = -14 - exp | |
ushorts[i] = sgn + ((frac + (1 << 10)) >> s) | |
} else if (exp > 15) { | |
// round overflow to +/- Infinity | |
ushorts[i] = sgn + 0x7c00 | |
} else { | |
// otherwise convert directly | |
ushorts[i] = sgn + ((exp + 15) << 10) + frac | |
} | |
} | |
} | |
return ushorts | |
} | |
},{"./pool":28}],31:[function(require,module,exports){ | |
module.exports = function (obj) { | |
return Object.keys(obj).map(function (key) { return obj[key] }) | |
} | |
},{}],32:[function(require,module,exports){ | |
// Context and canvas creation helper functions | |
var check = require('./util/check') | |
var extend = require('./util/extend') | |
function createCanvas (element, onDone, pixelRatio) { | |
var canvas = document.createElement('canvas') | |
extend(canvas.style, { | |
border: 0, | |
margin: 0, | |
padding: 0, | |
top: 0, | |
left: 0 | |
}) | |
element.appendChild(canvas) | |
if (element === document.body) { | |
canvas.style.position = 'absolute' | |
extend(element.style, { | |
margin: 0, | |
padding: 0 | |
}) | |
} | |
function resize () { | |
var w = window.innerWidth | |
var h = window.innerHeight | |
if (element !== document.body) { | |
var bounds = element.getBoundingClientRect() | |
w = bounds.right - bounds.left | |
h = bounds.top - bounds.bottom | |
} | |
canvas.width = pixelRatio * w | |
canvas.height = pixelRatio * h | |
extend(canvas.style, { | |
width: w + 'px', | |
height: h + 'px' | |
}) | |
} | |
window.addEventListener('resize', resize, false) | |
function onDestroy () { | |
window.removeEventListener('resize', resize) | |
element.removeChild(canvas) | |
} | |
resize() | |
return { | |
canvas: canvas, | |
onDestroy: onDestroy | |
} | |
} | |
function createContext (canvas, contexAttributes) { | |
function get (name) { | |
try { | |
return canvas.getContext(name, contexAttributes) | |
} catch (e) { | |
return null | |
} | |
} | |
return ( | |
get('webgl') || | |
get('experimental-webgl') || | |
get('webgl-experimental') | |
) | |
} | |
function isHTMLElement (obj) { | |
return ( | |
typeof obj.nodeName === 'string' && | |
typeof obj.appendChild === 'function' && | |
typeof obj.getBoundingClientRect === 'function' | |
) | |
} | |
function isWebGLContext (obj) { | |
return ( | |
typeof obj.drawArrays === 'function' || | |
typeof obj.drawElements === 'function' | |
) | |
} | |
function parseExtensions (input) { | |
if (typeof input === 'string') { | |
return input.split() | |
} | |
check(Array.isArray(input), 'invalid extension array') | |
return input | |
} | |
function getElement (desc) { | |
if (typeof desc === 'string') { | |
check(typeof document !== 'undefined', 'not supported outside of DOM') | |
return document.querySelector(desc) | |
} | |
return desc | |
} | |
module.exports = function parseArgs (args_) { | |
var args = args_ || {} | |
var element, container, canvas, gl | |
var contextAttributes = {} | |
var extensions = [] | |
var optionalExtensions = [] | |
var pixelRatio = (typeof window === 'undefined' ? 1 : window.devicePixelRatio) | |
var profile = false | |
var onDone = function (err) { | |
if (err) { | |
check.raise(err) | |
} | |
} | |
var onDestroy = function () {} | |
if (typeof args === 'string') { | |
check( | |
typeof document !== 'undefined', | |
'selector queries only supported in DOM enviroments') | |
element = document.querySelector(args) | |
check(element, 'invalid query string for element') | |
} else if (typeof args === 'object') { | |
if (isHTMLElement(args)) { | |
element = args | |
} else if (isWebGLContext(args)) { | |
gl = args | |
canvas = gl.canvas | |
} else { | |
check.constructor(args) | |
if ('gl' in args) { | |
gl = args.gl | |
} else if ('canvas' in args) { | |
canvas = getElement(args.canvas) | |
} else if ('container' in args) { | |
container = getElement(args.container) | |
} | |
if ('attributes' in args) { | |
contextAttributes = args.attributes | |
check.type(contextAttributes, 'object', 'invalid context attributes') | |
} | |
if ('extensions' in args) { | |
extensions = parseExtensions(args.extensions) | |
} | |
if ('optionalExtensions' in args) { | |
optionalExtensions = parseExtensions(args.optionalExtensions) | |
} | |
if ('onDone' in args) { | |
check.type( | |
args.onDone, 'function', | |
'invalid or missing onDone callback') | |
onDone = args.onDone | |
} | |
if ('profile' in args) { | |
profile = !!args.profile | |
} | |
if ('pixelRatio' in args) { | |
pixelRatio = +args.pixelRatio | |
check(pixelRatio > 0, 'invalid pixel ratio') | |
} | |
} | |
} else { | |
check.raise('invalid arguments to regl') | |
} | |
if (element) { | |
if (element.nodeName.toLowerCase() === 'canvas') { | |
canvas = element | |
} else { | |
container = element | |
} | |
} | |
if (!gl) { | |
if (!canvas) { | |
check( | |
typeof document !== 'undefined', | |
'must manually specify webgl context outside of DOM environments') | |
var result = createCanvas(container || document.body, onDone, pixelRatio) | |
if (!result) { | |
return null | |
} | |
canvas = result.canvas | |
onDestroy = result.onDestroy | |
} | |
gl = createContext(canvas, contextAttributes) | |
} | |
if (!gl) { | |
onDestroy() | |
onDone('webgl not supported, try upgrading your browser or graphics drivers http://get.webgl.org') | |
return null | |
} | |
return { | |
gl: gl, | |
canvas: canvas, | |
container: container, | |
extensions: extensions, | |
optionalExtensions: optionalExtensions, | |
pixelRatio: pixelRatio, | |
profile: profile, | |
onDone: onDone, | |
onDestroy: onDestroy | |
} | |
} | |
},{"./util/check":20,"./util/extend":23}],"regl":[function(require,module,exports){ | |
var check = require('./lib/util/check') | |
var extend = require('./lib/util/extend') | |
var dynamic = require('./lib/dynamic') | |
var raf = require('./lib/util/raf') | |
var clock = require('./lib/util/clock') | |
var createStringStore = require('./lib/strings') | |
var initWebGL = require('./lib/webgl') | |
var wrapExtensions = require('./lib/extension') | |
var wrapLimits = require('./lib/limits') | |
var wrapBuffers = require('./lib/buffer') | |
var wrapElements = require('./lib/elements') | |
var wrapTextures = require('./lib/texture') | |
var wrapRenderbuffers = require('./lib/renderbuffer') | |
var wrapFramebuffers = require('./lib/framebuffer') | |
var wrapAttributes = require('./lib/attribute') | |
var wrapShaders = require('./lib/shader') | |
var wrapRead = require('./lib/read') | |
var createCore = require('./lib/core') | |
var createStats = require('./lib/stats') | |
var createTimer = require('./lib/timer') | |
var GL_COLOR_BUFFER_BIT = 16384 | |
var GL_DEPTH_BUFFER_BIT = 256 | |
var GL_STENCIL_BUFFER_BIT = 1024 | |
var GL_ARRAY_BUFFER = 34962 | |
var CONTEXT_LOST_EVENT = 'webglcontextlost' | |
var CONTEXT_RESTORED_EVENT = 'webglcontextrestored' | |
var DYN_PROP = 1 | |
var DYN_CONTEXT = 2 | |
var DYN_STATE = 3 | |
function find (haystack, needle) { | |
for (var i = 0; i < haystack.length; ++i) { | |
if (haystack[i] === needle) { | |
return i | |
} | |
} | |
return -1 | |
} | |
module.exports = function wrapREGL (args) { | |
var config = initWebGL(args) | |
if (!config) { | |
return null | |
} | |
var gl = config.gl | |
var glAttributes = gl.getContextAttributes() | |
var extensionState = wrapExtensions(gl, config) | |
if (!extensionState) { | |
return null | |
} | |
var stringStore = createStringStore() | |
var stats = createStats() | |
var extensions = extensionState.extensions | |
var timer = createTimer(gl, extensions) | |
var START_TIME = clock() | |
var WIDTH = gl.drawingBufferWidth | |
var HEIGHT = gl.drawingBufferHeight | |
var contextState = { | |
tick: 0, | |
time: 0, | |
viewportWidth: WIDTH, | |
viewportHeight: HEIGHT, | |
framebufferWidth: WIDTH, | |
framebufferHeight: HEIGHT, | |
drawingBufferWidth: WIDTH, | |
drawingBufferHeight: HEIGHT, | |
pixelRatio: config.pixelRatio | |
} | |
var uniformState = {} | |
var drawState = { | |
elements: null, | |
primitive: 4, // GL_TRIANGLES | |
count: -1, | |
offset: 0, | |
instances: -1 | |
} | |
var limits = wrapLimits(gl, extensions) | |
var bufferState = wrapBuffers(gl, stats, config) | |
var elementState = wrapElements(gl, extensions, bufferState, stats) | |
var attributeState = wrapAttributes( | |
gl, | |
extensions, | |
limits, | |
bufferState, | |
stringStore) | |
var shaderState = wrapShaders(gl, stringStore, stats, config) | |
var textureState = wrapTextures( | |
gl, | |
extensions, | |
limits, | |
function () { core.procs.poll() }, | |
contextState, | |
stats, | |
config) | |
var renderbufferState = wrapRenderbuffers(gl, extensions, limits, stats, config) | |
var framebufferState = wrapFramebuffers( | |
gl, | |
extensions, | |
limits, | |
textureState, | |
renderbufferState, | |
stats) | |
var core = createCore( | |
gl, | |
stringStore, | |
extensions, | |
limits, | |
bufferState, | |
elementState, | |
textureState, | |
framebufferState, | |
uniformState, | |
attributeState, | |
shaderState, | |
drawState, | |
contextState, | |
timer, | |
config) | |
var readPixels = wrapRead( | |
gl, | |
framebufferState, | |
core.procs.poll, | |
contextState, | |
glAttributes, extensions) | |
var nextState = core.next | |
var canvas = gl.canvas | |
var rafCallbacks = [] | |
var activeRAF = null | |
function handleRAF () { | |
if (rafCallbacks.length === 0) { | |
if (timer) { | |
timer.update() | |
} | |
activeRAF = null | |
return | |
} | |
// schedule next animation frame | |
activeRAF = raf.next(handleRAF) | |
// poll for changes | |
poll() | |
// fire a callback for all pending rafs | |
for (var i = rafCallbacks.length - 1; i >= 0; --i) { | |
var cb = rafCallbacks[i] | |
if (cb) { | |
cb(contextState, null, 0) | |
} | |
} | |
// flush all pending webgl calls | |
gl.flush() | |
// poll GPU timers *after* gl.flush so we don't delay command dispatch | |
if (timer) { | |
timer.update() | |
} | |
} | |
function startRAF () { | |
if (!activeRAF && rafCallbacks.length > 0) { | |
activeRAF = raf.next(handleRAF) | |
} | |
} | |
function stopRAF () { | |
if (activeRAF) { | |
raf.cancel(handleRAF) | |
activeRAF = null | |
} | |
} | |
function handleContextLoss (event) { | |
// TODO | |
} | |
function handleContextRestored (event) { | |
// TODO | |
} | |
if (canvas) { | |
canvas.addEventListener(CONTEXT_LOST_EVENT, handleContextLoss, false) | |
canvas.addEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored, false) | |
} | |
function destroy () { | |
rafCallbacks.length = 0 | |
stopRAF() | |
if (canvas) { | |
canvas.removeEventListener(CONTEXT_LOST_EVENT, handleContextLoss) | |
canvas.removeEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored) | |
} | |
shaderState.clear() | |
framebufferState.clear() | |
renderbufferState.clear() | |
textureState.clear() | |
elementState.clear() | |
bufferState.clear() | |
if (timer) { | |
timer.clear() | |
} | |
config.onDestroy() | |
} | |
function compileProcedure (options) { | |
check(!!options, 'invalid args to regl({...})') | |
check.type(options, 'object', 'invalid args to regl({...})') | |
function flattenNestedOptions (options) { | |
var result = extend({}, options) | |
delete result.uniforms | |
delete result.attributes | |
delete result.context | |
function merge (name) { | |
if (name in result) { | |
var child = result[name] | |
delete result[name] | |
Object.keys(child).forEach(function (prop) { | |
result[name + '.' + prop] = child[prop] | |
}) | |
} | |
} | |
merge('blend') | |
merge('depth') | |
merge('cull') | |
merge('stencil') | |
merge('polygonOffset') | |
merge('scissor') | |
merge('sample') | |
return result | |
} | |
function separateDynamic (object) { | |
var staticItems = {} | |
var dynamicItems = {} | |
Object.keys(object).forEach(function (option) { | |
var value = object[option] | |
if (dynamic.isDynamic(value)) { | |
dynamicItems[option] = dynamic.unbox(value, option) | |
} else { | |
staticItems[option] = value | |
} | |
}) | |
return { | |
dynamic: dynamicItems, | |
static: staticItems | |
} | |
} | |
// Treat context variables separate from other dynamic variables | |
var context = separateDynamic(options.context || {}) | |
var uniforms = separateDynamic(options.uniforms || {}) | |
var attributes = separateDynamic(options.attributes || {}) | |
var opts = separateDynamic(flattenNestedOptions(options)) | |
var stats = { | |
gpuTime: 0.0, | |
cpuTime: 0.0, | |
count: 0 | |
} | |
var compiled = core.compile(opts, attributes, uniforms, context, stats) | |
var draw = compiled.draw | |
var batch = compiled.batch | |
var scope = compiled.scope | |
// FIXME: we should modify code generation for batch commands so this | |
// isn't necessary | |
var EMPTY_ARRAY = [] | |
function reserve (count) { | |
while (EMPTY_ARRAY.length < count) { | |
EMPTY_ARRAY.push(null) | |
} | |
return EMPTY_ARRAY | |
} | |
function REGLCommand (args, body) { | |
var i | |
if (typeof args === 'function') { | |
return scope.call(this, null, args, 0) | |
} else if (typeof body === 'function') { | |
if (typeof args === 'number') { | |
for (i = 0; i < args; ++i) { | |
scope.call(this, null, body, i) | |
} | |
return | |
} else if (Array.isArray(args)) { | |
for (i = 0; i < args.length; ++i) { | |
scope.call(this, args[i], body, i) | |
} | |
return | |
} else { | |
return scope.call(this, args, body, 0) | |
} | |
} else if (typeof args === 'number') { | |
if (args > 0) { | |
return batch.call(this, reserve(args | 0), args | 0) | |
} | |
} else if (Array.isArray(args)) { | |
if (args.length) { | |
return batch.call(this, args, args.length) | |
} | |
} else { | |
return draw.call(this, args) | |
} | |
} | |
return extend(REGLCommand, { | |
stats: stats | |
}) | |
} | |
function clear (options) { | |
check( | |
typeof options === 'object' && options, | |
'regl.clear() takes an object as input') | |
var clearFlags = 0 | |
core.procs.poll() | |
var c = options.color | |
if (c) { | |
gl.clearColor(+c[0] || 0, +c[1] || 0, +c[2] || 0, +c[3] || 0) | |
clearFlags |= GL_COLOR_BUFFER_BIT | |
} | |
if ('depth' in options) { | |
gl.clearDepth(+options.depth) | |
clearFlags |= GL_DEPTH_BUFFER_BIT | |
} | |
if ('stencil' in options) { | |
gl.clearStencil(options.stencil | 0) | |
clearFlags |= GL_STENCIL_BUFFER_BIT | |
} | |
check(!!clearFlags, 'called regl.clear with no buffer specified') | |
gl.clear(clearFlags) | |
} | |
function frame (cb) { | |
check.type(cb, 'function', 'regl.frame() callback must be a function') | |
rafCallbacks.push(cb) | |
function cancel () { | |
// FIXME: should we check something other than equals cb here? | |
// what if a user calls frame twice with the same callback... | |
// | |
var i = find(rafCallbacks, cb) | |
check(i >= 0, 'cannot cancel a frame twice') | |
function pendingCancel () { | |
var index = find(rafCallbacks, pendingCancel) | |
rafCallbacks[index] = rafCallbacks[rafCallbacks.length - 1] | |
rafCallbacks.length -= 1 | |
if (rafCallbacks.length <= 0) { | |
stopRAF() | |
} | |
} | |
rafCallbacks[i] = pendingCancel | |
} | |
startRAF() | |
return { | |
cancel: cancel | |
} | |
} | |
// poll viewport | |
function pollViewport () { | |
var viewport = nextState.viewport | |
var scissorBox = nextState.scissor_box | |
viewport[0] = viewport[1] = scissorBox[0] = scissorBox[1] = 0 | |
contextState.viewportWidth = | |
contextState.framebufferWidth = | |
contextState.drawingBufferWidth = | |
viewport[2] = | |
scissorBox[2] = gl.drawingBufferWidth | |
contextState.viewportHeight = | |
contextState.framebufferHeight = | |
contextState.drawingBufferHeight = | |
viewport[3] = | |
scissorBox[3] = gl.drawingBufferHeight | |
} | |
function poll () { | |
contextState.tick += 1 | |
contextState.time = (clock() - START_TIME) / 1000.0 | |
pollViewport() | |
core.procs.poll() | |
} | |
function refresh () { | |
pollViewport() | |
core.procs.refresh() | |
if (timer) { | |
timer.update() | |
} | |
} | |
refresh() | |
var regl = extend(compileProcedure, { | |
// Clear current FBO | |
clear: clear, | |
// Short cuts for dynamic variables | |
prop: dynamic.define.bind(null, DYN_PROP), | |
context: dynamic.define.bind(null, DYN_CONTEXT), | |
this: dynamic.define.bind(null, DYN_STATE), | |
// executes an empty draw command | |
draw: compileProcedure({}), | |
// Resources | |
buffer: function (options) { | |
return bufferState.create(options, GL_ARRAY_BUFFER) | |
}, | |
elements: elementState.create, | |
texture: textureState.create2D, | |
cube: textureState.createCube, | |
renderbuffer: renderbufferState.create, | |
framebuffer: framebufferState.create, | |
framebufferCube: framebufferState.createCube, | |
// Expose context attributes | |
attributes: glAttributes, | |
// Frame rendering | |
frame: frame, | |
// System limits | |
limits: limits, | |
hasExtension: function (name) { | |
return limits.extensions.indexOf(name.toLowerCase()) >= 0 | |
}, | |
// Read pixels | |
read: readPixels, | |
// Destroy regl and all associated resources | |
destroy: destroy, | |
// Direct GL state manipulation | |
_gl: gl, | |
_refresh: refresh, | |
poll: function () { | |
poll() | |
if (timer) { | |
timer.update() | |
} | |
}, | |
// regl Statistics Information | |
stats: stats | |
}) | |
config.onDone(null, regl) | |
return regl | |
} | |
},{"./lib/attribute":1,"./lib/buffer":2,"./lib/core":7,"./lib/dynamic":8,"./lib/elements":9,"./lib/extension":10,"./lib/framebuffer":11,"./lib/limits":12,"./lib/read":13,"./lib/renderbuffer":14,"./lib/shader":15,"./lib/stats":16,"./lib/strings":17,"./lib/texture":18,"./lib/timer":19,"./lib/util/check":20,"./lib/util/clock":21,"./lib/util/extend":23,"./lib/util/raf":29,"./lib/webgl":32}]},{},[]) | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImxpYi9hdHRyaWJ1dGUuanMiLCJsaWIvYnVmZmVyLmpzIiwibGliL2NvbnN0YW50cy9hcnJheXR5cGVzLmpzb24iLCJsaWIvY29uc3RhbnRzL2R0eXBlcy5qc29uIiwibGliL2NvbnN0YW50cy9wcmltaXRpdmVzLmpzb24iLCJsaWIvY29uc3RhbnRzL3VzYWdlLmpzb24iLCJsaWIvY29yZS5qcyIsImxpYi9keW5hbWljLmpzIiwibGliL2VsZW1lbnRzLmpzIiwibGliL2V4dGVuc2lvbi5qcyIsImxpYi9mcmFtZWJ1ZmZlci5qcyIsImxpYi9saW1pdHMuanMiLCJsaWIvcmVhZC5qcyIsImxpYi9yZW5kZXJidWZmZXIuanMiLCJsaWIvc2hhZGVyLmpzIiwibGliL3N0YXRzLmpzIiwibGliL3N0cmluZ3MuanMiLCJsaWIvdGV4dHVyZS5qcyIsImxpYi90aW1lci5qcyIsImxpYi91dGlsL2NoZWNrLmpzIiwibGliL3V0aWwvY2xvY2suanMiLCJsaWIvdXRpbC9jb2RlZ2VuLmpzIiwibGliL3V0aWwvZXh0ZW5kLmpzIiwibGliL3V0aWwvaXMtYXJyYXktbGlrZS5qcyIsImxpYi91dGlsL2lzLW5kYXJyYXkuanMiLCJsaWIvdXRpbC9pcy10eXBlZC1hcnJheS5qcyIsImxpYi91dGlsL2xvb3AuanMiLCJsaWIvdXRpbC9wb29sLmpzIiwibGliL3V0aWwvcmFmLmpzIiwibGliL3V0aWwvdG8taGFsZi1mbG9hdC5qcyIsImxpYi91dGlsL3ZhbHVlcy5qcyIsImxpYi93ZWJnbC5qcyIsInJlZ2wuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2WEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNaQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOXdHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDelJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2gzQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdE9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL2hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdElBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN25CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNiQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJ2YXIgR0xfRkxPQVQgPSA1MTI2XG5cbmZ1bmN0aW9uIEF0dHJpYnV0ZVJlY29yZCAoKSB7XG4gIHRoaXMuc3RhdGUgPSAwXG5cbiAgdGhpcy54ID0gMC4wXG4gIHRoaXMueSA9IDAuMFxuICB0aGlzLnogPSAwLjBcbiAgdGhpcy53ID0gMC4wXG5cbiAgdGhpcy5idWZmZXIgPSBudWxsXG4gIHRoaXMuc2l6ZSA9IDBcbiAgdGhpcy5ub3JtYWxpemVkID0gZmFsc2VcbiAgdGhpcy50eXBlID0gR0xfRkxPQVRcbiAgdGhpcy5vZmZzZXQgPSAwXG4gIHRoaXMuc3RyaWRlID0gMFxuICB0aGlzLmRpdmlzb3IgPSAwXG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gd3JhcEF0dHJpYnV0ZVN0YXRlIChcbiAgZ2wsXG4gIGV4dGVuc2lvbnMsXG4gIGxpbWl0cyxcbiAgYnVmZmVyU3RhdGUsXG4gIHN0cmluZ1N0b3JlKSB7XG4gIHZhciBOVU1fQVRUUklCVVRFUyA9IGxpbWl0cy5tYXhBdHRyaWJ1dGVzXG4gIHZhciBhdHRyaWJ1dGVCaW5kaW5ncyA9IG5ldyBBcnJheShOVU1fQVRUUklCVVRFUylcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBOVU1fQVRUUklCVVRFUzsgKytpKSB7XG4gICAgYXR0cmlidXRlQmluZGluZ3NbaV0gPSBuZXcgQXR0cmlidXRlUmVjb3JkKClcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgUmVjb3JkOiBBdHRyaWJ1dGVSZWNvcmQsXG4gICAgc2NvcGU6IHt9LFxuICAgIHN0YXRlOiBhdHRyaWJ1dGVCaW5kaW5nc1xuICB9XG59XG4iLCJ2YXIgY2hlY2sgPSByZXF1aXJlKCcuL3V0aWwvY2hlY2snKVxudmFyIGlzVHlwZWRBcnJheSA9IHJlcXVpcmUoJy4vdXRpbC9pcy10eXBlZC1hcnJheScpXG52YXIgaXNOREFycmF5TGlrZSA9IHJlcXVpcmUoJy4vdXRpbC9pcy1uZGFycmF5JylcbnZhciB2YWx1ZXMgPSByZXF1aXJlKCcuL3V0aWwvdmFsdWVzJylcbnZhciBwb29sID0gcmVxdWlyZSgnLi91dGlsL3Bvb2wnKVxuXG52YXIgYXJyYXlUeXBlcyA9IHJlcXVpcmUoJy4vY29uc3RhbnRzL2FycmF5dHlwZXMuanNvbicpXG52YXIgYnVmZmVyVHlwZXMgPSByZXF1aXJlKCcuL2NvbnN0YW50cy9kdHlwZXMuanNvbicpXG52YXIgdXNhZ2VUeXBlcyA9IHJlcXVpcmUoJy4vY29uc3RhbnRzL3VzYWdlLmpzb24nKVxuXG52YXIgR0xfU1RBVElDX0RSQVcgPSAweDg4RTRcbnZhciBHTF9TVFJFQU1fRFJBVyA9IDB4ODhFMFxuXG52YXIgR0xfVU5TSUdORURfQllURSA9IDUxMjFcbnZhciBHTF9GTE9BVCA9IDUxMjZcblxudmFyIERUWVBFU19TSVpFUyA9IFtdXG5EVFlQRVNfU0laRVNbNTEyMF0gPSAxIC8vIGludDhcbkRUWVBFU19TSVpFU1s1MTIyXSA9IDIgLy8gaW50MTZcbkRUWVBFU19TSVpFU1s1MTI0XSA9IDQgLy8gaW50MzJcbkRUWVBFU19TSVpFU1s1MTIxXSA9IDEgLy8gdWludDhcbkRUWVBFU19TSVpFU1s1MTIzXSA9IDIgLy8gdWludDE2XG5EVFlQRVNfU0laRVNbNTEyNV0gPSA0IC8vIHVpbnQzMlxuRFRZUEVTX1NJWkVTWzUxMjZdID0gNCAvLyBmbG9hdDMyXG5cbmZ1bmN0aW9uIHR5cGVkQXJyYXlDb2RlIChkYXRhKSB7XG4gIHJldHVybiBhcnJheVR5cGVzW09iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChkYXRhKV0gfCAwXG59XG5cbmZ1bmN0aW9uIGNvcHlBcnJheSAob3V0LCBpbnApIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBpbnAubGVuZ3RoOyArK2kpIHtcbiAgICBvdXRbaV0gPSBpbnBbaV1cbiAgfVxufVxuXG5mdW5jdGlvbiB0cmFuc3Bvc2UgKFxuICByZXN1bHQsIGRhdGEsIHNoYXBlWCwgc2hhcGVZLCBzdHJpZGVYLCBzdHJpZGVZLCBvZmZzZXQpIHtcbiAgdmFyIHB0ciA9IDBcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzaGFwZVg7ICsraSkge1xuICAgIGZvciAodmFyIGogPSAwOyBqIDwgc2hhcGVZOyArK2opIHtcbiAgICAgIHJlc3VsdFtwdHIrK10gPSBkYXRhW3N0cmlkZVggKiBpICsgc3RyaWRlWSAqIGogKyBvZmZzZXRdXG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGZsYXR0ZW4gKHJlc3VsdCwgZGF0YSwgZGltZW5zaW9uKSB7XG4gIHZhciBwdHIgPSAwXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgZGF0YS5sZW5ndGg7ICsraSkge1xuICAgIHZhciB2ID0gZGF0YVtpXVxuICAgIGZvciAodmFyIGogPSAwOyBqIDwgZGltZW5zaW9uOyArK2opIHtcbiAgICAgIHJlc3VsdFtwdHIrK10gPSB2W2pdXG4gICAgfVxuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gd3JhcEJ1ZmZlclN0YXRlIChnbCwgc3RhdHMsIGNvbmZpZykge1xuICB2YXIgYnVmZmVyQ291bnQgPSAwXG4gIHZhciBidWZmZXJTZXQgPSB7fVxuXG4gIGZ1bmN0aW9uIFJFR0xCdWZmZXIgKHR5cGUpIHtcbiAgICB0aGlzLmlkID0gYnVmZmVyQ291bnQrK1xuICAgIHRoaXMuYnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKClcbiAgICB0aGlzLnR5cGUgPSB0eXBlXG4gICAgdGhpcy51c2FnZSA9IEdMX1NUQVRJQ19EUkFXXG4gICAgdGhpcy5ieXRlTGVuZ3RoID0gMFxuICAgIHRoaXMuZGltZW5zaW9uID0gMVxuICAgIHRoaXMuZHR5cGUgPSBHTF9VTlNJR05FRF9CWVRFXG5cbiAgICBpZiAoY29uZmlnLnByb2ZpbGUpIHtcbiAgICAgIHRoaXMuc3RhdHMgPSB7c2l6ZTogMH1cbiAgICB9XG4gIH1cblxuICBSRUdMQnVmZmVyLnByb3RvdHlwZS5iaW5kID0gZnVuY3Rpb24gKCkge1xuICAgIGdsLmJpbmRCdWZmZXIodGhpcy50eXBlLCB0aGlzLmJ1ZmZlcilcbiAgfVxuXG4gIFJFR0xCdWZmZXIucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgZGVzdHJveSh0aGlzKVxuICB9XG5cbiAgdmFyIHN0cmVhbVBvb2wgPSBbXVxuXG4gIGZ1bmN0aW9uIGNyZWF0ZVN0cmVhbSAodHlwZSwgZGF0YSkge1xuICAgIHZhciBidWZmZXIgPSBzdHJlYW1Qb29sLnBvcCgpXG4gICAgaWYgKCFidWZmZXIpIHtcbiAgICAgIGJ1ZmZlciA9IG5ldyBSRUdMQnVmZmVyKHR5cGUpXG4gICAgfVxuICAgIGJ1ZmZlci5iaW5kKClcbiAgICBpbml0QnVmZmVyRnJvbURhdGEoYnVmZmVyLCBkYXRhLCBHTF9TVFJFQU1fRFJBVywgMCwgMSlcbiAgICByZXR1cm4gYnVmZmVyXG4gIH1cblxuICBmdW5jdGlvbiBkZXN0cm95U3RyZWFtIChzdHJlYW0pIHtcbiAgICBzdHJlYW1Qb29sLnB1c2goc3RyZWFtKVxuICB9XG5cbiAgZnVuY3Rpb24gaW5pdEJ1ZmZlckZyb21UeXBlZEFycmF5IChidWZmZXIsIGRhdGEsIHVzYWdlKSB7XG4gICAgYnVmZmVyLmJ5dGVMZW5ndGggPSBkYXRhLmJ5dGVMZW5ndGhcbiAgICBnbC5idWZmZXJEYXRhKGJ1ZmZlci50eXBlLCBkYXRhLCB1c2FnZSlcbiAgfVxuXG4gIGZ1bmN0aW9uIGluaXRCdWZmZXJGcm9tRGF0YSAoYnVmZmVyLCBkYXRhLCB1c2FnZSwgZHR5cGUsIGRpbWVuc2lvbikge1xuICAgIGJ1ZmZlci51c2FnZSA9IHVzYWdlXG4gICAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YSkpIHtcbiAgICAgIGJ1ZmZlci5kdHlwZSA9IGR0eXBlIHx8IEdMX0ZMT0FUXG4gICAgICBpZiAoZGF0YS5sZW5ndGggPiAwKSB7XG4gICAgICAgIHZhciBmbGF0RGF0YVxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShkYXRhWzBdKSkge1xuICAgICAgICAgIGJ1ZmZlci5kaW1lbnNpb24gPSBkYXRhWzBdLmxlbmd0aFxuICAgICAgICAgIGZsYXREYXRhID0gcG9vbC5hbGxvY1R5cGUoXG4gICAgICAgICAgICBidWZmZXIuZHR5cGUsXG4gICAgICAgICAgICBkYXRhLmxlbmd0aCAqIGJ1ZmZlci5kaW1lbnNpb24pXG4gICAgICAgICAgZmxhdHRlbihmbGF0RGF0YSwgZGF0YSwgYnVmZmVyLmRpbWVuc2lvbilcbiAgICAgICAgICBpbml0QnVmZmVyRnJvbVR5cGVkQXJyYXkoYnVmZmVyLCBmbGF0RGF0YSwgdXNhZ2UpXG4gICAgICAgICAgcG9vbC5mcmVlVHlwZShmbGF0RGF0YSlcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgZGF0YVswXSA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICBidWZmZXIuZGltZW5zaW9uID0gZGltZW5zaW9uXG4gICAgICAgICAgdmFyIHR5cGVkRGF0YSA9IHBvb2wuYWxsb2NUeXBlKGJ1ZmZlci5kdHlwZSwgZGF0YS5sZW5ndGgpXG4gICAgICAgICAgY29weUFycmF5KHR5cGVkRGF0YSwgZGF0YSlcbiAgICAgICAgICBpbml0QnVmZmVyRnJvbVR5cGVkQXJyYXkoYnVmZmVyLCB0eXBlZERhdGEsIHVzYWdlKVxuICAgICAgICAgIHBvb2wuZnJlZVR5cGUodHlwZWREYXRhKVxuICAgICAgICB9IGVsc2UgaWYgKGlzVHlwZWRBcnJheShkYXRhWzBdKSkge1xuICAgICAgICAgIGJ1ZmZlci5kaW1lbnNpb24gPSBkYXRhWzBdLmxlbmd0aFxuICAgICAgICAgIGJ1ZmZlci5kdHlwZSA9IGR0eXBlIHx8IHR5cGVkQXJyYXlDb2RlKGRhdGFbMF0pIHx8IEdMX0ZMT0FUXG4gICAgICAgICAgZmxhdERhdGEgPSBwb29sLmFsbG9jVHlwZShcbiAgICAgICAgICAgIGJ1ZmZlci5kdHlwZSxcbiAgICAgICAgICAgIGRhdGEubGVuZ3RoICogYnVmZmVyLmRpbWVuc2lvbilcbiAgICAgICAgICBmbGF0dGVuKGZsYXREYXRhLCBkYXRhLCBidWZmZXIuZGltZW5zaW9uKVxuICAgICAgICAgIGluaXRCdWZmZXJGcm9tVHlwZWRBcnJheShidWZmZXIsIGZsYXREYXRhLCB1c2FnZSlcbiAgICAgICAgICBwb29sLmZyZWVUeXBlKGZsYXREYXRhKVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNoZWNrLnJhaXNlKCdpbnZhbGlkIGJ1ZmZlciBkYXRhJylcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoaXNUeXBlZEFycmF5KGRhdGEpKSB7XG4gICAgICBidWZmZXIuZHR5cGUgPSBkdHlwZSB8fCB0eXBlZEFycmF5Q29kZShkYXRhKVxuICAgICAgYnVmZmVyLmRpbWVuc2lvbiA9IGRpbWVuc2lvblxuICAgICAgaW5pdEJ1ZmZlckZyb21UeXBlZEFycmF5KGJ1ZmZlciwgZGF0YSwgdXNhZ2UpXG4gICAgfSBlbHNlIGlmIChpc05EQXJyYXlMaWtlKGRhdGEpKSB7XG4gICAgICB2YXIgc2hhcGUgPSBkYXRhLnNoYXBlXG4gICAgICB2YXIgc3RyaWRlID0gZGF0YS5zdHJpZGVcbiAgICAgIHZhciBvZmZzZXQgPSBkYXRhLm9mZnNldFxuXG4gICAgICB2YXIgc2hhcGVYID0gMFxuICAgICAgdmFyIHNoYXBlWSA9IDBcbiAgICAgIHZhciBzdHJpZGVYID0gMFxuICAgICAgdmFyIHN0cmlkZVkgPSAwXG4gICAgICBpZiAoc2hhcGUubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIHNoYXBlWCA9IHNoYXBlWzBdXG4gICAgICAgIHNoYXBlWSA9IDFcbiAgICAgICAgc3RyaWRlWCA9IHN0cmlkZVswXVxuICAgICAgICBzdHJpZGVZID0gMFxuICAgICAgfSBlbHNlIGlmIChzaGFwZS5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgc2hhcGVYID0gc2hhcGVbMF1cbiAgICAgICAgc2hhcGVZID0gc2hhcGVbMV1cbiAgICAgICAgc3RyaWRlWCA9IHN0cmlkZVswXVxuICAgICAgICBzdHJpZGVZID0gc3RyaWRlWzFdXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjaGVjay5yYWlzZSgnaW52YWxpZCBzaGFwZScpXG4gICAgICB9XG5cbiAgICAgIGJ1ZmZlci5kdHlwZSA9IGR0eXBlIHx8IHR5cGVkQXJyYXlDb2RlKGRhdGEuZGF0YSkgfHwgR0xfRkxPQVRcbiAgICAgIGJ1ZmZlci5kaW1lbnNpb24gPSBzaGFwZVlcblxuICAgICAgdmFyIHRyYW5zcG9zZURhdGEgPSBwb29sLmFsbG9jVHlwZShidWZmZXIuZHR5cGUsIHNoYXBlWCAqIHNoYXBlWSlcbiAgICAgIHRyYW5zcG9zZSh0cmFuc3Bvc2VEYXRhLFxuICAgICAgICBkYXRhLmRhdGEsXG4gICAgICAgIHNoYXBlWCwgc2hhcGVZLFxuICAgICAgICBzdHJpZGVYLCBzdHJpZGVZLFxuICAgICAgICBvZmZzZXQpXG4gICAgICBpbml0QnVmZmVyRnJvbVR5cGVkQXJyYXkoYnVmZmVyLCB0cmFuc3Bvc2VEYXRhLCB1c2FnZSlcbiAgICAgIHBvb2wuZnJlZVR5cGUodHJhbnNwb3NlRGF0YSlcbiAgICB9IGVsc2Uge1xuICAgICAgY2hlY2sucmFpc2UoJ2ludmFsaWQgYnVmZmVyIGRhdGEnKVxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGRlc3Ryb3kgKGJ1ZmZlcikge1xuICAgIHN0YXRzLmJ1ZmZlckNvdW50LS1cblxuICAgIHZhciBoYW5kbGUgPSBidWZmZXIuYnVmZmVyXG4gICAgY2hlY2soaGFuZGxlLCAnYnVmZmVyIG11c3Qgbm90IGJlIGRlbGV0ZWQgYWxyZWFkeScpXG4gICAgZ2wuZGVsZXRlQnVmZmVyKGhhbmRsZSlcbiAgICBidWZmZXIuYnVmZmVyID0gbnVsbFxuICAgIGRlbGV0ZSBidWZmZXJTZXRbYnVmZmVyLmlkXVxuICB9XG5cbiAgZnVuY3Rpb24gY3JlYXRlQnVmZmVyIChvcHRpb25zLCB0eXBlLCBkZWZlckluaXQpIHtcbiAgICBzdGF0cy5idWZmZXJDb3VudCsrXG5cbiAgICB2YXIgYnVmZmVyID0gbmV3IFJFR0xCdWZmZXIodHlwZSlcbiAgICBidWZmZXJTZXRbYnVmZmVyLmlkXSA9IGJ1ZmZlclxuXG4gICAgZnVuY3Rpb24gcmVnbEJ1ZmZlciAob3B0aW9ucykge1xuICAgICAgdmFyIHVzYWdlID0gR0xfU1RBVElDX0RSQVdcbiAgICAgIHZhciBkYXRhID0gbnVsbFxuICAgICAgdmFyIGJ5dGVMZW5ndGggPSAwXG4gICAgICB2YXIgZHR5cGUgPSAwXG4gICAgICB2YXIgZGltZW5zaW9uID0gMVxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkob3B0aW9ucykgfHxcbiAgICAgICAgICBpc1R5cGVkQXJyYXkob3B0aW9ucykgfHxcbiAgICAgICAgICBpc05EQXJyYXlMaWtlKG9wdGlvbnMpKSB7XG4gICAgICAgIGRhdGEgPSBvcHRpb25zXG4gICAgICB9IGVsc2UgaWYgKHR5cGVvZiBvcHRpb25zID09PSAnbnVtYmVyJykge1xuICAgICAgICBieXRlTGVuZ3RoID0gb3B0aW9ucyB8IDBcbiAgICAgIH0gZWxzZSBpZiAob3B0aW9ucykge1xuICAgICAgICBjaGVjay50eXBlKFxuICAgICAgICAgIG9wdGlvbnMsICdvYmplY3QnLFxuICAgICAgICAgICdidWZmZXIgYXJndW1lbnRzIG11c3QgYmUgYW4gb2JqZWN0LCBhIG51bWJlciBvciBhbiBhcnJheScpXG5cbiAgICAgICAgaWYgKCdkYXRhJyBpbiBvcHRpb25zKSB7XG4gICAgICAgICAgY2hlY2soXG4gICAgICAgICAgICBkYXRhID09PSBudWxsIHx8XG4gICAgICAgICAgICBBcnJheS5pc0FycmF5KGRhdGEpIHx8XG4gICAgICAgICAgICBpc1R5cGVkQXJyYXkoZGF0YSkgfHxcbiAgICAgICAgICAgIGlzTkRBcnJheUxpa2UoZGF0YSksXG4gICAgICAgICAgICAnaW52YWxpZCBkYXRhIGZvciBidWZmZXInKVxuICAgICAgICAgIGRhdGEgPSBvcHRpb25zLmRhdGFcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgndXNhZ2UnIGluIG9wdGlvbnMpIHtcbiAgICAgICAgICBjaGVjay5wYXJhbWV0ZXIob3B0aW9ucy51c2FnZSwgdXNhZ2VUeXBlcywgJ2ludmFsaWQgYnVmZmVyIHVzYWdlJylcbiAgICAgICAgICB1c2FnZSA9IHVzYWdlVHlwZXNbb3B0aW9ucy51c2FnZV1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgndHlwZScgaW4gb3B0aW9ucykge1xuICAgICAgICAgIGNoZWNrLnBhcmFtZXRlcihvcHRpb25zLnR5cGUsIGJ1ZmZlclR5cGVzLCAnaW52YWxpZCBidWZmZXIgdHlwZScpXG4gICAgICAgICAgZHR5cGUgPSBidWZmZXJUeXBlc1tvcHRpb25zLnR5cGVdXG4gICAgICAgIH1cblxuICAgICAgICBpZiAoJ2RpbWVuc2lvbicgaW4gb3B0aW9ucykge1xuICAgICAgICAgIGNoZWNrLnR5cGUob3B0aW9ucy5kaW1lbnNpb24sICdudW1iZXInLCAnaW52YWxpZCBkaW1lbnNpb24nKVxuICAgICAgICAgIGRpbWVuc2lvbiA9IG9wdGlvbnMuZGltZW5zaW9uIHwgMFxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCdsZW5ndGgnIGluIG9wdGlvbnMpIHtcbiAgICAgICAgICBjaGVjay5ubmkoYnl0ZUxlbmd0aCwgJ2J1ZmZlciBsZW5ndGggbXVzdCBiZSBhIG5vbm5lZ2F0aXZlIGludGVnZXInKVxuICAgICAgICAgIGJ5dGVMZW5ndGggPSBvcHRpb25zLmxlbmd0aCB8IDBcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBidWZmZXIuYmluZCgpXG4gICAgICBpZiAoIWRhdGEpIHtcbiAgICAgICAgZ2wuYnVmZmVyRGF0YShidWZmZXIudHlwZSwgYnl0ZUxlbmd0aCwgdXNhZ2UpXG4gICAgICAgIGJ1ZmZlci5kdHlwZSA9IGR0eXBlIHx8IEdMX1VOU0lHTkVEX0JZVEVcbiAgICAgICAgYnVmZmVyLnVzYWdlID0gdXNhZ2VcbiAgICAgICAgYnVmZmVyLmRpbWVuc2lvbiA9IGRpbWVuc2lvblxuICAgICAgICBidWZmZXIuYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGhcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGluaXRCdWZmZXJGcm9tRGF0YShidWZmZXIsIGRhdGEsIHVzYWdlLCBkdHlwZSwgZGltZW5zaW9uKVxuICAgICAgfVxuXG4gICAgICBpZiAoY29uZmlnLnByb2ZpbGUpIHtcbiAgICAgICAgYnVmZmVyLnN0YXRzLnNpemUgPSBidWZmZXIuYnl0ZUxlbmd0aCAqIERUWVBFU19TSVpFU1tidWZmZXIuZHR5cGVdXG4gICAgICB9XG5cbiAgICAgIHJldHVybiByZWdsQnVmZmVyXG4gICAgfVxuXG4gICAgZnVuY3Rpb24gc2V0U3ViRGF0YSAoZGF0YSwgb2Zmc2V0KSB7XG4gICAgICBjaGVjayhvZmZzZXQgKyBkYXRhLmJ5dGVMZW5ndGggPD0gYnVmZmVyLmJ5dGVMZW5ndGgsXG4gICAgICAgICdpbnZhbGlkIGJ1ZmZlciBzdWJkYXRhIGNhbGwsIGJ1ZmZlciBpcyB0b28gc21hbGwuICcgKyAnIENhblxcJ3Qgd3JpdGUgZGF0YSBvZiBzaXplICcgKyBkYXRhLmJ5dGVMZW5ndGggKyAnIHN0YXJ0aW5nIGZyb20gb2Zmc2V0ICcgKyBvZmZzZXQgKyAnIHRvIGEgYnVmZmVyIG9mIHNpemUgJyArIGJ1ZmZlci5ieXRlTGVuZ3RoKVxuXG4gICAgICBnbC5idWZmZXJTdWJEYXRhKGJ1ZmZlci50eXBlLCBvZmZzZXQsIGRhdGEpXG4gICAgfVxuXG4gICAgZnVuY3Rpb24gc3ViZGF0YSAoZGF0YSwgb2Zmc2V0Xykge1xuICAgICAgdmFyIG9mZnNldCA9IChvZmZzZXRfIHx8IDApIHwgMFxuICAgICAgYnVmZmVyLmJpbmQoKVxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YSkpIHtcbiAgICAgICAgaWYgKGRhdGEubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGlmICh0eXBlb2YgZGF0YVswXSA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICAgIHZhciBjb252ZXJ0ZWQgPSBwb29sLmFsbG9jVHlwZShidWZmZXIuZHR5cGUsIGRhdGEubGVuZ3RoKVxuICAgICAgICAgICAgY29weUFycmF5KGNvbnZlcnRlZCwgZGF0YSlcbiAgICAgICAgICAgIHNldFN1YkRhdGEoY29udmVydGVkLCBvZmZzZXQpXG4gICAgICAgICAgICBwb29sLmZyZWVUeXBlKGNvbnZlcnRlZClcbiAgICAgICAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoZGF0YVswXSkgfHwgaXNUeXBlZEFycmF5KGRhdGFbMF0pKSB7XG4gICAgICAgICAgICB2YXIgZGltZW5zaW9uID0gZGF0YVswXS5sZW5ndGhcbiAgICAgICAgICAgIHZhciBmbGF0RGF0YSA9IHBvb2wuYWxsb2NUeXBlKGJ1ZmZlci5kdHlwZSwgZGF0YS5sZW5ndGggKiBkaW1lbnNpb24pXG4gICAgICAgICAgICBmbGF0dGVuKGZsYXREYXRhLCBkYXRhLCBkaW1lbnNpb24pXG4gICAgICAgICAgICBzZXRTdWJEYXRhKGZsYXREYXRhLCBvZmZzZXQpXG4gICAgICAgICAgICBwb29sLmZyZWVUeXBlKGZsYXREYXRhKVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjaGVjay5yYWlzZSgnaW52YWxpZCBidWZmZXIgZGF0YScpXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKGlzVHlwZWRBcnJheShkYXRhKSkge1xuICAgICAgICBzZXRTdWJEYXRhKGRhdGEsIG9mZnNldClcbiAgICAgIH0gZWxzZSBpZiAoaXNOREFycmF5TGlrZShkYXRhKSkge1xuICAgICAgICB2YXIgc2hhcGUgPSBkYXRhLnNoYXBlXG4gICAgICAgIHZhciBzdHJpZGUgPSBkYXRhLnN0cmlkZVxuXG4gICAgICAgIHZhciBzaGFwZVggPSAwXG4gICAgICAgIHZhciBzaGFwZVkgPSAwXG4gICAgICAgIHZhciBzdHJpZGVYID0gMFxuICAgICAgICB2YXIgc3RyaWRlWSA9IDBcbiAgICAgICAgaWYgKHNoYXBlLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIHNoYXBlWCA9IHNoYXBlWzBdXG4gICAgICAgICAgc2hhcGVZID0gMVxuICAgICAgICAgIHN0cmlkZVggPSBzdHJpZGVbMF1cbiAgICAgICAgICBzdHJpZGVZID0gMFxuICAgICAgICB9IGVsc2UgaWYgKHNoYXBlLmxlbmd0aCA9PT0gMikge1xuICAgICAgICAgIHNoYXBlWCA9IHNoYXBlWzBdXG4gICAgICAgICAgc2hhcGVZID0gc2hhcGVbMV1cbiAgICAgICAgICBzdHJpZGVYID0gc3RyaWRlWzBdXG4gICAgICAgICAgc3RyaWRlWSA9IHN0cmlkZVsxXVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNoZWNrLnJhaXNlKCdpbnZhbGlkIHNoYXBlJylcbiAgICAgICAgfVxuICAgICAgICB2YXIgZHR5cGUgPSBBcnJheS5pc0FycmF5KGRhdGEuZGF0YSlcbiAgICAgICAgICA/IGJ1ZmZlci5kdHlwZVxuICAgICAgICAgIDogdHlwZWRBcnJheUNvZGUoZGF0YS5kYXRhKVxuXG4gICAgICAgIHZhciB0cmFuc3Bvc2VEYXRhID0gcG9vbC5hbGxvY1R5cGUoZHR5cGUsIHNoYXBlWCAqIHNoYXBlWSlcbiAgICAgICAgdHJhbnNwb3NlKHRyYW5zcG9zZURhdGEsXG4gICAgICAgICAgZGF0YS5kYXRhLFxuICAgICAgICAgIHNoYXBlWCwgc2hhcGVZLFxuICAgICAgICAgIHN0cmlkZVgsIHN0cmlkZVksXG4gICAgICAgICAgZGF0YS5vZmZzZXQpXG4gICAgICAgIHNldFN1YkRhdGEodHJhbnNwb3NlRGF0YSwgb2Zmc2V0KVxuICAgICAgICBwb29sLmZyZWVUeXBlKHRyYW5zcG9zZURhdGEpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjaGVjay5yYWlzZSgnaW52YWxpZCBkYXRhIGZvciBidWZmZXIgc3ViZGF0YScpXG4gICAgICB9XG4gICAgICByZXR1cm4gcmVnbEJ1ZmZlclxuICAgIH1cblxuICAgIGlmICghZGVmZXJJbml0KSB7XG4gICAgICByZWdsQnVmZmVyKG9wdGlvbnMpXG4gICAgfVxuXG4gICAgcmVnbEJ1ZmZlci5fcmVnbFR5cGUgPSAnYnVmZmVyJ1xuICAgIHJlZ2xCdWZmZXIuX2J1ZmZlciA9IGJ1ZmZlclxuICAgIHJlZ2xCdWZmZXIuc3ViZGF0YSA9IHN1YmRhdGFcbiAgICBpZiAoY29uZmlnLnByb2ZpbGUpIHtcbiAgICAgIHJlZ2xCdWZmZXIuc3RhdHMgPSBidWZmZXIuc3RhdHNcbiAgICB9XG4gICAgcmVnbEJ1ZmZlci5kZXN0cm95ID0gZnVuY3Rpb24gKCkgeyBkZXN0cm95KGJ1ZmZlcikgfVxuXG4gICAgcmV0dXJuIHJlZ2xCdWZmZXJcbiAgfVxuXG4gIGlmIChjb25maWcucHJvZmlsZSkge1xuICAgIHN0YXRzLmdldFRvdGFsQnVmZmVyU2l6ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciB0b3RhbCA9IDBcbiAgICAgIC8vIFRPRE86IFJpZ2h0IG5vdywgdGhlIHN0cmVhbXMgYXJlIG5vdCBwYXJ0IG9mIHRoZSB0b3RhbCBjb3VudC5cbiAgICAgIE9iamVjdC5rZXlzKGJ1ZmZlclNldCkuZm9yRWFjaChmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgIHRvdGFsICs9IGJ1ZmZlclNldFtrZXldLnN0YXRzLnNpemVcbiAgICAgIH0pXG4gICAgICByZXR1cm4gdG90YWxcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIGNyZWF0ZTogY3JlYXRlQnVmZmVyLFxuXG4gICAgY3JlYXRlU3RyZWFtOiBjcmVhdGVTdHJlYW0sXG4gICAgZGVzdHJveVN0cmVhbTogZGVzdHJveVN0cmVhbSxcblxuICAgIGNsZWFyOiBmdW5jdGlvbiAoKSB7XG4gICAgICB2YWx1ZXMoYnVmZmVyU2V0KS5mb3JFYWNoKGRlc3Ryb3kpXG4gICAgICBzdHJlYW1Qb29sLmZvckVhY2goZGVzdHJveSlcbiAgICB9LFxuXG4gICAgZ2V0QnVmZmVyOiBmdW5jdGlvbiAod3JhcHBlcikge1xuICAgICAgaWYgKHdyYXBwZXIgJiYgd3JhcHBlci5fYnVmZmVyIGluc3RhbmNlb2YgUkVHTEJ1ZmZlcikge1xuICAgICAgICByZXR1cm4gd3JhcHBlci5fYnVmZmVyXG4gICAgICB9XG4gICAgICByZXR1cm4gbnVsbFxuICAgIH0sXG5cbiAgICBfaW5pdEJ1ZmZlcjogaW5pdEJ1ZmZlckZyb21EYXRhXG4gIH1cbn1cbiIsIm1vZHVsZS5leHBvcnRzPXtcbiAgXCJbb2JqZWN0IEludDhBcnJheV1cIjogNTEyMFxuLCBcIltvYmplY3QgSW50MTZBcnJheV1cIjogNTEyMlxuLCBcIltvYmplY3QgSW50MzJBcnJheV1cIjogNTEyNFxuLCBcIltvYmplY3QgVWludDhBcnJheV1cIjogNTEyMVxuLCBcIltvYmplY3QgVWludDhDbGFtcGVkQXJyYXldXCI6IDUxMjFcbiwgXCJbb2JqZWN0IFVpbnQxNkFycmF5XVwiOiA1MTIzXG4sIFwiW29iamVjdCBVaW50MzJBcnJheV1cIjogNTEyNVxuLCBcIltvYmplY3QgRmxvYXQzMkFycmF5XVwiOiA1MTI2XG4sIFwiW29iamVjdCBGbG9hdDY0QXJyYXldXCI6IDUxMjFcbiwgXCJbb2JqZWN0IEFycmF5QnVmZmVyXVwiOiA1MTIxXG59XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gIFwiaW50OFwiOiA1MTIwXG4sIFwiaW50MTZcIjogNTEyMlxuLCBcImludDMyXCI6IDUxMjRcbiwgXCJ1aW50OFwiOiA1MTIxXG4sIFwidWludDE2XCI6IDUxMjNcbiwgXCJ1aW50MzJcIjogNTEyNVxuLCBcImZsb2F0XCI6IDUxMjZcbiwgXCJmbG9hdDMyXCI6IDUxMjZcbn1cbiIsIm1vZHVsZS5leHBvcnRzPXtcbiAgXCJwb2ludHNcIjogMCxcbiAgXCJwb2ludFwiOiAwLFxuICBcImxpbmVzXCI6IDEsXG4gIFwibGluZVwiOiAxLFxuICBcImxpbmUgbG9vcFwiOiAyLFxuICBcImxpbmUgc3RyaXBcIjogMyxcbiAgXCJ0cmlhbmdsZXNcIjogNCxcbiAgXCJ0cmlhbmdsZVwiOiA0LFxuICBcInRyaWFuZ2xlIHN0cmlwXCI6IDUsXG4gIFwidHJpYW5nbGUgZmFuXCI6IDZcbn1cbiIsIm1vZHVsZS5leHBvcnRzPXtcbiAgXCJzdGF0aWNcIjogMzUwNDQsXG4gIFwiZHluYW1pY1wiOiAzNTA0OCxcbiAgXCJzdHJlYW1cIjogMzUwNDBcbn1cbiIsInZhciBjaGVjayA9IHJlcXVpcmUoJy4vdXRpbC9jaGVjaycpXG52YXIgY3JlYXRlRW52aXJvbm1lbnQgPSByZXF1aXJlKCcuL3V0aWwvY29kZWdl |
View raw
(Sorry about that, but we can’t show files that are this big right now.)
View raw
(Sorry about that, but we can’t show files that are this big right now.)
View raw
(Sorry about that, but we can’t show files that are this big right now.)
View raw
(Sorry about that, but we can’t show files that are this big right now.)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment