webglimpse
Version:
Webglimpse is a data visualization library for the web.
314 lines • 71 kB
JavaScript
/*
* Copyright (c) 2014, Metron, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import { Side, nearestPixelCenter_GLSLFUNC, modelview_VERTSHADER, solid_FRAGSHADER } from '../misc';
import { concatLines, ensureCapacityFloat32, GL, order, hasval, clamp } from '../util/util';
import { getTickInterval, getTickCount, getTickPositions } from './axis';
import { black } from '../color';
import { getGradientTexture } from '../gradient';
import { Program, UniformMatrix4f, UniformSampler2D, Attribute, UniformColor, Uniform1f, Uniform2f } from '../shader';
import { heatmap_VERTSHADER } from './heatmap_painter';
import { newDynamicBuffer } from '../buffer';
import { newTextTextureCache } from '../text';
import { TextureRenderer } from '../texture';
import { glOrthoViewport } from '../matrix';
export function edgeMarks_VERTSHADER(labelSide) {
// The shader uses 'a' for the along-axis coord, and 'b' for the across-axis coord
const horizontal = (labelSide === Side.TOP || labelSide === Side.BOTTOM);
const bFlip = (labelSide === Side.LEFT || labelSide === Side.BOTTOM);
return concatLines(nearestPixelCenter_GLSLFUNC, ' ', ' uniform float u_VMin; ', ' uniform float u_VSize; ', ' uniform vec2 u_ViewportSize; ', ' uniform float u_MarkSize; ', ' ', ' attribute vec2 a_VCoord; ', ' ', ' void main( ) { ', ' float aViewportSize = ' + (horizontal ? 'u_ViewportSize.x' : 'u_ViewportSize.y') + '; ', ' float aFrac = nearestPixelCenter( ( a_VCoord.x - u_VMin ) / u_VSize, aViewportSize ); ', ' float a = -1.0 + 2.0*( aFrac ); ', ' ', ' float bViewportSize = ' + (horizontal ? 'u_ViewportSize.y' : 'u_ViewportSize.x') + '; ', ' float bFrac = ( a_VCoord.y * u_MarkSize ) / bViewportSize; ', ' float b = ' + (bFlip ? '-' : '') + '( -1.0 + 2.0*( bFrac ) ); ', ' ', ' gl_Position = vec4( ' + (horizontal ? 'a,b' : 'b,a') + ', 0.0, 1.0 ); ', ' } ', ' ');
}
export let gradient_FRAGSHADER = concatLines(' ', ' precision highp float; ', ' uniform sampler2D u_colorTex; ', ' ', ' varying vec2 v_texCoord; ', ' ', ' void main( ) { ', ' vec4 color = texture2D( u_colorTex, v_texCoord ); ', ' gl_FragColor = color; ', ' gl_FragColor.a = 1.0; ', ' } ');
export function newEdgeAxisPainter(axis, labelSide, options) {
const tickSpacing = (hasval(options) && hasval(options.tickSpacing) ? options.tickSpacing : 100);
const label = (hasval(options) && hasval(options.label) ? options.label : '');
const units = (hasval(options) && hasval(options.units) ? options.units : '');
const shortenLabels = (hasval(options) && hasval(options.shortenLabels) ? options.shortenLabels : true);
const font = (hasval(options) && hasval(options.font) ? options.font : '11px verdana,sans-serif');
const textColor = (hasval(options) && hasval(options.textColor) ? options.textColor : black);
const tickColor = (hasval(options) && hasval(options.tickColor) ? options.tickColor : black);
const tickSize = (hasval(options) && hasval(options.tickSize) ? options.tickSize : 6);
const showLabel = (hasval(options) && hasval(options.showLabel) ? options.showLabel : true);
const showBorder = (hasval(options) && hasval(options.showBorder) ? options.showBorder : false);
const gradientFill = (hasval(options) && hasval(options.gradientFill) ? options.gradientFill : undefined);
const tickLabeler = (hasval(options) && hasval(options.tickLabeler) ? options.tickLabeler : undefined);
let tickPositions = new Float32Array(0);
const gradientProgram = new Program(heatmap_VERTSHADER, gradient_FRAGSHADER);
const gradientProgram_u_modelViewMatrix = new UniformMatrix4f(gradientProgram, 'u_modelViewMatrix');
const gradientProgram_u_colorTexture = new UniformSampler2D(gradientProgram, 'u_colorTex');
const gradientProgram_a_vertCoord = new Attribute(gradientProgram, 'a_vertCoord');
const gradientProgram_a_texCoord = new Attribute(gradientProgram, 'a_texCoord');
let gradientColorTexture = null;
if (gradientFill) {
gradientColorTexture = getGradientTexture(gradientFill);
}
let gradientVertCoords = new Float32Array(0);
const gradientVertCoordsBuffer = newDynamicBuffer();
let gradientTexCoords = new Float32Array(0);
const gradientTexCoordsBuffer = newDynamicBuffer();
const borderProgram = new Program(modelview_VERTSHADER, solid_FRAGSHADER);
const borderProgram_a_Position = new Attribute(borderProgram, 'a_Position');
const borderProgram_u_modelViewMatrix = new UniformMatrix4f(borderProgram, 'u_modelViewMatrix');
const borderProgram_u_Color = new UniformColor(borderProgram, 'u_Color');
let borderCoords = new Float32Array(0);
const borderCoordsBuffer = newDynamicBuffer();
const marksProgram = new Program(edgeMarks_VERTSHADER(labelSide), solid_FRAGSHADER);
const marksProgram_u_VMin = new Uniform1f(marksProgram, 'u_VMin');
const marksProgram_u_VSize = new Uniform1f(marksProgram, 'u_VSize');
const marksProgram_u_ViewportSize = new Uniform2f(marksProgram, 'u_ViewportSize');
const marksProgram_u_MarkSize = new Uniform1f(marksProgram, 'u_MarkSize');
const marksProgram_u_Color = new UniformColor(marksProgram, 'u_Color');
const marksProgram_a_VCoord = new Attribute(marksProgram, 'a_VCoord');
let markCoords = new Float32Array(0);
const markCoordsBuffer = newDynamicBuffer();
const textTextures = newTextTextureCache(font, textColor);
const textureRenderer = new TextureRenderer();
const hTickLabels = textTextures.value('-0.123456789').h;
const isVerticalAxis = (labelSide === Side.LEFT || labelSide === Side.RIGHT);
return function (gl, viewport) {
const sizePixels = isVerticalAxis ? viewport.h : viewport.w;
if (sizePixels === 0) {
return;
}
const approxNumTicks = sizePixels / tickSpacing;
const tickInterval = getTickInterval(axis, approxNumTicks);
const tickCount = getTickCount(axis, tickInterval);
tickPositions = ensureCapacityFloat32(tickPositions, tickCount);
getTickPositions(axis, tickInterval, tickCount, tickPositions);
// Border Box and Gradient Fill
//
// XXX border vertices are fixed in normalized 0-1 viewport coordinates
// XXX they could be calculated ahead of time -- however I had trouble with 'fuzzy' lines when using 0-1 coordinates
if (showBorder || gradientFill) {
borderCoords = ensureCapacityFloat32(borderCoords, 10);
const horizontal = (labelSide === Side.TOP || labelSide === Side.BOTTOM);
const bFlip = (labelSide === Side.LEFT || labelSide === Side.BOTTOM);
const width = viewport.w - 1;
const height = viewport.h - 1;
borderCoords[0] = horizontal ? 0 : (bFlip ? width - tickSize : 0);
borderCoords[1] = !horizontal ? 0 : (bFlip ? height - tickSize : 0);
borderCoords[2] = horizontal ? 0 : (bFlip ? width : tickSize);
borderCoords[3] = !horizontal ? 0 : (bFlip ? height : tickSize);
borderCoords[4] = horizontal ? width : (bFlip ? width : tickSize);
borderCoords[5] = !horizontal ? height : (bFlip ? height : tickSize);
borderCoords[6] = horizontal ? width : (bFlip ? width - tickSize : 0);
borderCoords[7] = !horizontal ? height : (bFlip ? height - tickSize : 0);
// finish off the box (same as 0, 1 coordinates)
borderCoords[8] = horizontal ? 0 : (bFlip ? width - tickSize : 0);
borderCoords[9] = !horizontal ? 0 : (bFlip ? height - tickSize : 0);
}
if (gradientFill) {
gradientProgram.use(gl);
gradientProgram_u_modelViewMatrix.setData(gl, glOrthoViewport(viewport));
gradientProgram_u_colorTexture.setDataAndBind(gl, 0, gradientColorTexture);
gradientVertCoords = ensureCapacityFloat32(gradientVertCoords, 8);
gradientVertCoords[0] = borderCoords[2];
gradientVertCoords[1] = borderCoords[3];
gradientVertCoords[2] = borderCoords[0];
gradientVertCoords[3] = borderCoords[1];
gradientVertCoords[4] = borderCoords[4];
gradientVertCoords[5] = borderCoords[5];
gradientVertCoords[6] = borderCoords[6];
gradientVertCoords[7] = borderCoords[7];
gradientVertCoordsBuffer.setData(gradientVertCoords);
gradientProgram_a_vertCoord.setDataAndEnable(gl, gradientVertCoordsBuffer, 2, GL.FLOAT);
// y texture coordinates don't really matter ( we're simulating a 1d texture )
// using a 1-by-n 2d texture because 1d textures aren't available
gradientTexCoords = ensureCapacityFloat32(gradientTexCoords, 8);
gradientTexCoords[0] = 0;
gradientTexCoords[1] = 0;
gradientTexCoords[2] = 0;
gradientTexCoords[3] = 0;
gradientTexCoords[4] = 1;
gradientTexCoords[5] = 1;
gradientTexCoords[6] = 1;
gradientTexCoords[7] = 1;
gradientTexCoordsBuffer.setData(gradientTexCoords);
gradientProgram_a_texCoord.setDataAndEnable(gl, gradientTexCoordsBuffer, 2, GL.FLOAT);
gl.drawArrays(GL.TRIANGLE_STRIP, 0, 4);
gradientProgram_u_colorTexture.unbind(gl);
gradientProgram_a_vertCoord.disable(gl);
gradientProgram_a_texCoord.disable(gl);
gradientProgram.endUse(gl);
}
if (showBorder) {
borderProgram.use(gl);
borderProgram_u_Color.setData(gl, tickColor);
borderProgram_u_modelViewMatrix.setData(gl, glOrthoViewport(viewport));
borderCoordsBuffer.setData(borderCoords.subarray(0, 10));
borderProgram_a_Position.setDataAndEnable(gl, borderCoordsBuffer, 2, GL.FLOAT);
// IE does not support lineWidths other than 1, so make sure all browsers use lineWidth of 1
gl.lineWidth(1);
gl.drawArrays(GL.LINE_STRIP, 0, 5);
borderProgram_a_Position.disable(gl);
borderProgram.endUse(gl);
}
// Tick marks
//
marksProgram.use(gl);
marksProgram_u_VMin.setData(gl, axis.vMin);
marksProgram_u_VSize.setData(gl, axis.vSize);
marksProgram_u_ViewportSize.setData(gl, viewport.w, viewport.h);
marksProgram_u_MarkSize.setData(gl, tickSize);
marksProgram_u_Color.setData(gl, tickColor);
markCoords = ensureCapacityFloat32(markCoords, 4 * tickCount);
for (let n = 0; n < tickCount; n++) {
const v = tickPositions[n];
markCoords[(4 * n + 0)] = v;
markCoords[(4 * n + 1)] = 0;
markCoords[(4 * n + 2)] = v;
markCoords[(4 * n + 3)] = 1;
}
markCoordsBuffer.setData(markCoords.subarray(0, 4 * tickCount));
marksProgram_a_VCoord.setDataAndEnable(gl, markCoordsBuffer, 2, GL.FLOAT);
// IE does not support lineWidths other than 1, so make sure all browsers use lineWidth of 1
gl.lineWidth(1);
gl.drawArrays(GL.LINES, 0, 2 * tickCount);
marksProgram_a_VCoord.disable(gl);
marksProgram.endUse(gl);
// Tick labels
//
gl.blendFuncSeparate(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA, GL.ONE, GL.ONE_MINUS_SRC_ALPHA);
gl.enable(GL.BLEND);
const orderAxisRaw = order(Math.abs(axis.vSize));
let orderAxis = 0;
if (orderAxisRaw > 0) {
orderAxis = Math.floor((orderAxisRaw - 1) / 3) * 3;
}
else if (orderAxisRaw < 0) {
orderAxis = (Math.ceil(orderAxisRaw / 3) - 1) * 3;
}
const orderFactor = Math.pow(10, -orderAxis);
const orderTick = order(tickInterval);
const precision = Math.max(0, orderAxis - orderTick);
textTextures.resetTouches();
textureRenderer.begin(gl, viewport);
for (let n = 0; n < tickCount; n++) {
const v = tickPositions[n];
const vFrac = axis.vFrac(v);
if (vFrac < 0 || vFrac >= 1) {
continue;
}
let tickLabel;
if (tickLabeler) {
// show custom tick value
tickLabel = tickLabeler(v, axis, tickInterval);
}
else if (shortenLabels && showLabel) {
// show shortened tick value
tickLabel = Number(v * orderFactor).toFixed(precision);
}
else if (!shortenLabels) {
// show actual tick value
if (orderAxisRaw >= 0) {
tickLabel = Number(v).toFixed(0);
}
else {
tickLabel = Number(v).toFixed(-orderAxisRaw);
}
}
else {
// show magnitude inline for each tick
tickLabel = Number(v * orderFactor).toFixed(precision) + (orderAxis === 0 ? '' : 'e' + orderAxis);
}
const textTexture = textTextures.value(tickLabel);
let xFrac;
let yFrac;
if (labelSide === Side.LEFT || labelSide === Side.RIGHT) {
const yAnchor = textTexture.yAnchor(0.43);
const j0 = (vFrac * viewport.h) - yAnchor * textTexture.h;
const j = clamp(0, viewport.h - textTexture.h, j0);
yFrac = j / viewport.h;
if (labelSide === Side.LEFT) {
xFrac = (viewport.w - tickSize - 2 - textTexture.w) / viewport.w;
}
else {
xFrac = (tickSize + 2) / viewport.w;
}
}
else {
let wMinus = 0;
if (v < 0) {
const absTickLabel = Number(Math.abs(v) * orderFactor).toFixed(precision);
wMinus = textTexture.w - textTextures.value(absTickLabel).w;
}
const xAnchor = 0.45;
const i0 = (vFrac * viewport.w) - xAnchor * (textTexture.w - wMinus) - wMinus;
const i = clamp(0, viewport.w - textTexture.w, i0);
xFrac = i / viewport.w;
if (labelSide === Side.BOTTOM) {
yFrac = (viewport.h - tickSize - 2 - hTickLabels) / viewport.h;
}
else {
yFrac = (tickSize + 2) / viewport.h;
}
}
textureRenderer.draw(gl, textTexture, xFrac, yFrac, { xAnchor: 0, yAnchor: 0 });
}
// Axis label
//
if (showLabel) {
const unitsString = units + (!shortenLabels || orderAxis === 0 ? '' : ' x 10^' + orderAxis.toFixed(0));
const axisLabel = label + (unitsString ? ' (' + unitsString + ')' : '');
if (axisLabel !== '') {
const textTexture = textTextures.value(axisLabel);
let xFrac;
let yFrac;
let textOpts;
if (labelSide === Side.LEFT || labelSide === Side.RIGHT) {
// Using hTickLabels here works out about right, even though the tick-label text is horizontal
const xFrac0 = 0.5 * (viewport.w - tickSize - 2 - hTickLabels) / viewport.w;
xFrac = (labelSide === Side.LEFT ? xFrac0 : 1 - xFrac0);
yFrac = 0.5;
textOpts = {
xAnchor: textTexture.yAnchor(0.5),
yAnchor: 0.5,
rotation_CCWRAD: 0.5 * Math.PI
};
}
else {
const yFrac0 = 0.5 * (viewport.h - tickSize - 2 - hTickLabels) / viewport.h;
yFrac = (labelSide === Side.BOTTOM ? yFrac0 : 1 - yFrac0);
xFrac = 0.5;
textOpts = {
xAnchor: 0.5,
yAnchor: textTexture.yAnchor(0.5),
rotation_CCWRAD: 0
};
}
textureRenderer.draw(gl, textTexture, xFrac, yFrac, textOpts);
}
}
// Finish up
//
textureRenderer.end(gl);
textTextures.retainTouched();
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRnZV9heGlzX3BhaW50ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvd2ViZ2xpbXBzZS9wbG90L2VkZ2VfYXhpc19wYWludGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNEJHO0FBQ0gsT0FBTyxFQUFFLElBQUksRUFBRSwyQkFBMkIsRUFBRSxvQkFBb0IsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNwRyxPQUFPLEVBQUUsV0FBVyxFQUFFLHFCQUFxQixFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUM1RixPQUFPLEVBQVUsZUFBZSxFQUFFLFlBQVksRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUNqRixPQUFPLEVBQVMsS0FBSyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ3hDLE9BQU8sRUFBWSxrQkFBa0IsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUUzRCxPQUFPLEVBQUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxnQkFBZ0IsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDdEgsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDdkQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sV0FBVyxDQUFDO0FBRTdDLE9BQU8sRUFBaUIsbUJBQW1CLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDN0QsT0FBTyxFQUFFLGVBQWUsRUFBK0IsTUFBTSxZQUFZLENBQUM7QUFFMUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUc1QyxNQUFNLFVBQVUsb0JBQW9CLENBQUMsU0FBZTtJQUNoRCxrRkFBa0Y7SUFDbEYsTUFBTSxVQUFVLEdBQUcsQ0FBQyxTQUFTLEtB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QU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzdGLE1BQU0sU0FBUyxHQUFHLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzdGLE1BQU0sUUFBUSxHQUFHLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RGLE1BQU0sU0FBUyxHQUFHLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzVGLE1BQU0sVUFBVSxHQUFHLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2hHLE1BQU0sWUFBWSxHQUFHLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzFHLE1BQU0sV0FBVyxHQUFHLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBRXZHLElBQUks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QyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDbEUsWUFBWSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUVwRSxZQUFZLENBQUMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQzlELFlBQVksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUVoRSxZQUFZLENBQUMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ2xFLFlBQVksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUVyRSxZQUFZLENBQUMsQ0FBQyxDQUFDLEdBQUcsVUFBVSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUcsUUFBUSxDQUFDLENB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QUFXLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQzt3QkFDakMsT0FBTyxFQUFFLEdBQUc7d0JBQ1osZUFBZSxFQUFFLEdBQUcsR0FBRyxJQUFJLENBQUMsRUFBRTtxQkFDakMsQ0FBQztpQkFDTDtxQkFDSTtvQkFDRCxNQUFNLE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQyxHQUFHLFFBQVEsR0FBRyxDQUFDLEdBQUcsV0FBVyxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQztvQkFDNUUsS0FBSyxHQUFHLENBQUMsU0FBUyxLQUFLLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDO29CQUMxRCxLQUFLLEdBQUcsR0FBRyxDQUFDO29CQUNaLFFBQVEsR0FBRzt3QkFDUCxPQUFPLEVBQUUsR0FBRzt3QkFDWixPQUFPLEVBQUUsV0FBVyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUM7d0JBQ2pDLGVBQWUsRUFBRSxDQUFDO3FCQUNyQixDQUFDO2lCQUNMO2dCQUNELGVBQWUsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLFFBQVEsQ0FBQyxDQUFDO2FBQ2pFO1NBQ0o7UUFHRCxZQUFZO1FBQ1osRUFBRTtRQUVGLGVBQWUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDeEIsWUFBWSxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQ2pDLENBQUMsQ0FBQztBQUNOLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxyXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTQsIE1ldHJvbiwgSW5jLlxyXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxyXG4gKlxyXG4gKiBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQgbW9kaWZpY2F0aW9uLFxyXG4gKiBhcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxvd2luZyBjb25kaXRpb25zIGFyZSBtZXQ6XHJcbiAqXHJcbiAqIDEuIFJlZGlzdHJpYnV0aW9ucyBvZiBzb3VyY2UgY29kZSBtdXN0IHJldGFpbiB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSwgdGhpc1xyXG4gKiAgICBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lci5cclxuICpcclxuICogMi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlLFxyXG4gKiAgICB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyIGluIHRoZSBkb2N1bWVudGF0aW9uXHJcbiAqICAgIGFuZC9vciBvdGhlciBtYXRlcmlhbHMgcHJvdmlkZWQgd2l0aCB0aGUgZGlzdHJpYnV0aW9uLlxyXG4gKlxyXG4gKiAzLiBOZWl0aGVyIHRoZSBuYW1lIG9mIHRoZSBjb3B5cmlnaHQgaG9sZGVyIG5vciB0aGUgbmFtZXMgb2YgaXRzIGNvbnRyaWJ1dG9yc1xyXG4gKiAgICBtYXkgYmUgdXNlZCB0byBlbmRvcnNlIG9yIHByb21vdGUgcHJvZHVjdHMgZGVyaXZlZCBmcm9tIHRoaXMgc29mdHdhcmUgd2l0aG91dFxyXG4gKiAgICBzcGVjaWZpYyBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIFRISVMgU09GVFdBUkUgSVMgUFJPVklERUQgQlkgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORCBDT05UUklCVVRPUlMgXCJBUyBJU1wiIEFORFxyXG4gKiBBTlkgRVhQUkVTUyBPUiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBUSEUgSU1QTElFRFxyXG4gKiBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSBBTkQgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQVJFXHJcbiAqIERJU0NMQUlNRUQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBDT1BZUklHSFQgSE9MREVSIE9SIENPTlRSSUJVVE9SUyBCRSBMSUFCTEUgRk9SXHJcbiAqIEFOWSBESVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLCBTUEVDSUFMLCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFU1xyXG4gKiAoSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFBST0NVUkVNRU5UIE9GIFNVQlNUSVRVVEUgR09PRFMgT1IgU0VSVklDRVM7XHJcbiAqIExPU1MgT0YgVVNFLCBEQVRBLCBPUiBQUk9GSVRTOyBPUiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhPV0VWRVIgQ0FVU0VEIEFORCBPTlxyXG4gKiBBTlkgVEhFT1JZIE9GIExJQUJJTElUWSwgV0hFVEhFUiBJTiBDT05UUkFDVCwgU1RSSUNUIExJQUJJTElUWSwgT1IgVE9SVFxyXG4gKiAoSU5DTFVESU5HIE5FR0xJR0VOQ0UgT1IgT1RIRVJXSVNFKSBBUklTSU5HIElOIEFOWSBXQVkgT1VUIE9GIFRIRSBVU0UgT0YgVEhJU1xyXG4gKiBTT0ZUV0FSRSwgRVZFTiBJRiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS5cclxuICovXHJcbmltcG9ydCB7IFNpZGUsIG5lYXJlc3RQaXhlbENlbnRlcl9HTFNMRlVOQywgbW9kZWx2aWV3X1ZFUlRTSEFERVIsIHNvbGlkX0ZSQUdTSEFERVIgfSBmcm9tICcuLi9taXNjJztcclxuaW1wb3J0IHsgY29uY2F0TGluZXMsIGVuc3VyZUNhcGFjaXR5RmxvYXQzMiwgR0wsIG9yZGVyLCBoYXN2YWwsIGNsYW1wIH0gZnJvbSAnLi4vdXRpbC91dGlsJztcclxuaW1wb3J0IHsgQXhpczFELCBnZXRUaWNrSW50ZXJ2YWwsIGdldFRpY2tDb3VudCwgZ2V0VGlja1Bvc2l0aW9ucyB9IGZyb20gJy4vYXhpcyc7XHJcbmltcG9ydCB7IENvbG9yLCBibGFjayB9IGZyb20gJy4uL2NvbG9yJztcclxuaW1wb3J0IHsgR3JhZGllbnQsIGdldEdyYWRpZW50VGV4dHVyZSB9IGZyb20gJy4uL2dyYWRpZW50JztcclxuaW1wb3J0IHsgUGFpbnRlciB9IGZyb20gJy4uL2NvcmUnO1xyXG5pbXBvcnQgeyBQcm9ncmFtLCBVbmlmb3JtTWF0cml4NGYsIFVuaWZvcm1TYW1wbGVyMkQsIEF0dHJpYnV0ZSwgVW5pZm9ybUNvbG9yLCBVbmlmb3JtMWYsIFVuaWZvcm0yZiB9IGZyb20gJy4uL3NoYWRlcic7XHJcbmltcG9ydCB7IGhlYXRtYXBfVkVSVFNIQURFUiB9IGZyb20gJy4vaGVhdG1hcF9wYWludGVyJztcclxuaW1wb3J0IHsgbmV3RHluYW1pY0J1ZmZlciB9IGZyb20gJy4uL2J1ZmZlcic7XHJcbmltcG9ydCB7IENhY2hlIH0gZnJvbSAnLi4vdXRpbC9jYWNoZSc7XHJcbmltcG9ydCB7IFRleHRUZXh0dXJlMkQsIG5ld1RleHRUZXh0dXJlQ2FjaGUgfSBmcm9tICcuLi90ZXh0JztcclxuaW1wb3J0IHsgVGV4dHVyZVJlbmRlcmVyLCBUZXh0dXJlRHJhd09wdGlvbnMsIFRleHR1cmUgfSBmcm9tICcuLi90ZXh0dXJlJztcclxuaW1wb3J0IHsgQm91bmRzVW5tb2RpZmlhYmxlIH0gZnJvbSAnLi4vYm91bmRzJztcclxuaW1wb3J0IHsgZ2xPcnRob1ZpZXdwb3J0IH0gZnJvbSAnLi4vbWF0cml4JztcclxuXHJcblxyXG5leHBvcnQgZnVuY3Rpb24gZWRnZU1hcmtzX1ZFUlRTSEFERVIobGFiZWxTaWRlOiBTaWRlKSB7XHJcbiAgICAvLyBUaGUgc2hhZGVyIHVzZXMgJ2EnIGZvciB0aGUgYWxvbmctYXhpcyBjb29yZCwgYW5kICdiJyBmb3IgdGhlIGFjcm9zcy1heGlzIGNvb3JkXHJcbiAgICBjb25zdCBob3Jpem9udGFsID0gKGxhYmVsU2lkZSA9PT0gU2lkZS5UT1AgfHwgbGFiZWxTaWRlID09PSBTaWRlLkJPVFRPTSk7XHJcbiAgICBjb25zdCBiRmxpcCA9IChsYWJlbFNpZGUgPT09IFNpZGUuTEVGVCB8fCBsYWJlbFNpZGUgPT09IFNpZGUuQk9UVE9NKTtcclxuICAgIHJldHVybiBjb25jYXRMaW5lcyhcclxuICAgICAgICBuZWFyZXN0UGl4ZWxDZW50ZXJfR0xTTEZVTkMsXHJcbiAgICAgICAgJyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyxcclxuICAgICAgICAnICB1bmlmb3JtIGZsb2F0IHVfVk1pbjsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnLFxyXG4gICAgICAgICcgIHVuaWZvcm0gZmxvYXQgdV9WU2l6ZTsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcsXHJcbiAgICAgICAgJyAgdW5pZm9ybSB2ZWMyIHVfVmlld3BvcnRTaXplOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyxcclxuICAgICAgICAnICB1bmlmb3JtIGZsb2F0IHVfTWFya1NpemU7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnLFxyXG4gICAgICAgICcgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcsXHJcbiAgICAgICAgJyAgYXR0cmlidXRlIHZlYzIgYV9WQ29vcmQ7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyxcclxuICAgICAgICAnICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnLFxyXG4gICAgICAgICcgIHZvaWQgbWFpbiggKSB7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcsXHJcbiAgICAgICAgJyAgICAgIGZsb2F0IGFWaWV3cG9ydFNpemUgPSAnICsgKGhvcml6b250YWwgPyAndV9WaWV3cG9ydFNpemUueCcgOiAndV9WaWV3cG9ydFNpemUueScpICsgJzsgICcsXHJcbiAgICAgICAgJyAgICAgIGZsb2F0IGFGcmFjID0gbmVhcmVzdFBpeGVsQ2VudGVyKCAoIGFfVkNvb3JkLnggLSB1X1ZNaW4gKSAvIHVfVlNpemUsIGFWaWV3cG9ydFNpemUgKTsgICAgJyxcclxuICAgICAgICAnICAgICAgZmxvYXQgYSA9IC0xLjAgKyAyLjAqKCBhRnJhYyApOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnLFxyXG4gICAgICAgICcgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcsXHJcbiAgICAgICAgJyAgICAgIGZsb2F0IGJWaWV3cG9ydFNpemUgPSAnICsgKGhvcml6b250YWwgPyAndV9WaWV3cG9ydFNpemUueScgOiAndV9WaWV3cG9ydFNpemUueCcpICsgJzsgICcsXHJcbiAgICAgICAgJyAgICAgIGZsb2F0IGJGcmFjID0gKCBhX1ZDb29yZC55ICogdV9NYXJrU2l6ZSApIC8gYlZpZXdwb3J0U2l6ZTsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyxcclxuICAgICAgICAnICAgICAgZmxvYXQgYiA9ICcgKyAoYkZsaXAgPyAnLScgOiAnJykgKyAnKCAtMS4wICsgMi4wKiggYkZyYWMgKSApOyAgICAgICAgICAgICAgICAgICAgICAgICAnLFxyXG4gICAgICAgICcgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcsXHJcbiAgICAgICAgJyAgICAgIGdsX1Bvc2l0aW9uID0gdmVjNCggJyArIChob3Jpem9udGFsID8gJ2EsYicgOiAnYixhJykgKyAnLCAwLjAsIDEuMCApOyAgICAgICAgICAgICAgICAgICcsXHJcbiAgICAgICAgJyAgfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyxcclxuICAgICAgICAnICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnXHJcbiAgICApO1xyXG59XHJcblxyXG5leHBvcnQgbGV0IGdyYWRpZW50X0ZSQUdTSEFERVIgPSBjb25jYXRMaW5lcyhcclxuICAgICcgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnLFxyXG4gICAgJyAgcHJlY2lzaW9uIGhpZ2hwIGZsb2F0OyAgICAgICAgICcsXHJcbiAgICAnICB1bmlmb3JtIHNhbXBsZXIyRCB1X2NvbG9yVGV4OyAgJyxcclxuICAgICcgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnLFxyXG4gICAgJyAgdmFyeWluZyB2ZWMyIHZfdGV4Q29vcmQ7ICAgICAgICcsXHJcbiAgICAnICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnLFxyXG4gICAgJyAgdm9pZCBtYWluKCApIHsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyxcclxuICAgICcgICAgIHZlYzQgY29sb3IgPSB0ZXh0dXJlMkQoIHVfY29sb3JUZXgsIHZfdGV4Q29vcmQgKTsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcsXHJcbiAgICAnICAgICBnbF9GcmFnQ29sb3IgPSBjb2xvcjsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnLFxyXG4gICAgJyAgICAgZ2xfRnJhZ0NvbG9yLmEgPSAxLjA7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyxcclxuICAgICcgIH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdcclxuKTtcclxuXHJcbi8vIHByb3ZpZGVzIGEgY3VzdG9tIGxhYmVsZXIgZm9yIGF4aXMgdGljayBtYXJrc1xyXG4vL1xyXG4vLyB2YWx1ZSAgICAgICAgOiB0aGUgdGljayB2YWx1ZSB0byBjcmVhdGUgYSBsYWJlbCBzdHJpbmcgZm9yXHJcbi8vIGF4aXMgICAgICAgICA6IHRoZSBheGlzIGFzc29jaWF0ZWQgd2l0aCB0aGUgdGljayB2YWx1ZVxyXG4vLyB0aWNrSW50ZXJ2YWwgOiB0aGUgcmVxdWVzdGVkIHNwYWNpbmcgaW4gcGl4ZWxzIGJldHdlZW4gdGlja3NcclxuLy8gcHJlY2lzaW9uICAgIDogbnVtYmVyIG9mIGRlY2ltYWwgcG9pbnRzIHdoaWNoIHNob3VsZCBiZSB1c2VkIGZvciB0aWNrIGxhYmVsc1xyXG4vLyBvcmRlckF4aXMgICAgOiBvcmRlciggTWF0aC5hYnMoIGF4aXMudlNpemUgKSApIHRoZW4gcm91bmRlZCB0byBuZWFyZXN0IG11bHRpcGxlIG9mIHRocmVlICgtMywgMCwgMywgNi4uLilcclxuLy8gb3JkZXJGYWN0b3IgIDogTWF0aC5wb3coIDEwLCAtb3JkZXJBeGlzIClcclxuZXhwb3J0IHR5cGUgVGlja0xhYmVsZXIgPSAodmFsdWU6IG51bWJlciwgYXhpczogQXhpczFELCB0aWN