super-hero/extensions/shader-graph/dist/block-forge/forge.js

616 lines
81 KiB
JavaScript
Raw Normal View History

2024-05-20 20:02:45 -07:00
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.HTMLGraphForgeElement = void 0;
const tslib_1 = require("tslib");
const graph_1 = require("./graph");
const utils_1 = require("./utils");
const event_1 = require("./event");
const structures_1 = require("@itharbors/structures");
const undo_1 = require("./undo");
const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
const enum_1 = require("./enum");
const STYLE = /*css*/ `
:host { display: flex; flex-direction: column; }
:host > header { padding: 4px 10px; display: flex; }
:host > header > div { flex: 1; }
:host > header > div > span { cursor: pointer; }
:host > header > slot { display: block; }
:host > header > i { margin: 0 4px; }
:host > section { flex: 1; display: flex; }
:host > section > v-graph { flex: 1; }
`;
const HTML = /*html*/ `
<style>${STYLE}</style>
<header>
<div></div>
<slot></slot>
</header>
<section>
<v-graph type=""><v-graph>
</section>
`;
class HTMLGraphForgeElement extends HTMLElement {
constructor() {
super();
this.actionQueue = new structures_1.ActionQueue({
forge: this,
});
this.paths = [];
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML = HTML;
this.$graph = this.shadowRoot.querySelector('v-graph');
this._initHeader();
this._initSection();
}
_initHeader() {
this._updateHeader();
this.shadowRoot.querySelector('header > div').addEventListener('click', (event) => {
const $span = event.target;
if (!$span.hasAttribute('path-index')) {
return;
}
let index = parseInt($span.getAttribute('path-index') || '0');
if (index < 0) {
index = 0;
}
this.paths.splice(index + 1);
this._updateGraph();
const graph = this.paths[this.paths.length - 1];
(0, utils_1.dispatch)(this, 'enter-graph', {
detail: {
id: graph.name,
},
});
});
}
_updateHeader() {
const paths = this.paths.map((info, index) => `<span path-index="${index}">${info.name || info.type}</span>`).join('<i>/</i>');
this.shadowRoot.querySelector('header > div').innerHTML = paths;
}
_initSection() {
const $graph = this.shadowRoot.querySelector('v-graph');
$graph.shadowRoot.addEventListener('block-click', (event) => {
const customEvent = event;
const type = this.paths[this.paths.length - 1].type;
const info = graph_1.graphMap.get(type);
if (!info) {
return;
}
const $node = customEvent.target;
if (info.graph.event && info.graph.event.onBlockClick) {
const nodes = $graph.getProperty('nodes');
const lines = $graph.getProperty('lines');
const uuid = $node.getAttribute('node-uuid') || '';
const block = $graph.getProperty('nodes')[uuid];
const blockEvent = new event_1.BlockMouseEvent(nodes, lines, $node, block);
info.graph.event.onBlockClick(blockEvent);
}
});
$graph.shadowRoot.addEventListener('block-dblclick', (event) => {
const customEvent = event;
const type = this.paths[this.paths.length - 1].type;
const info = graph_1.graphMap.get(type);
if (!info) {
return;
}
const $node = customEvent.target;
if ($node.tagName === 'V-GRAPH-NODE') {
const details = $node.getProperty('details');
if (details.subGraph) {
this.enterSubGraph(details.subGraph);
return;
}
}
if (info.graph.event && info.graph.event.onBlockDblClick) {
const nodes = $graph.getProperty('nodes');
const lines = $graph.getProperty('lines');
const uuid = $node.getAttribute('node-uuid') || '';
const block = $graph.getProperty('nodes')[uuid];
const blockEvent = new event_1.BlockMouseEvent(nodes, lines, $node, block);
blockEvent.initPagePosition(customEvent.detail.pageX, customEvent.detail.pageY);
const graphPosition = $graph.convertCoordinate(customEvent.detail.offsetX, customEvent.detail.offsetY);
blockEvent.initGraphPosition(graphPosition.x, graphPosition.y);
info.graph.event.onBlockDblClick(blockEvent);
}
});
$graph.shadowRoot.addEventListener('block-right-click', (event) => {
const customEvent = event;
const type = this.paths[this.paths.length - 1].type;
const info = graph_1.graphMap.get(type);
if (!info) {
return;
}
const $node = customEvent.target;
if (info.graph.event && info.graph.event.onBlockRightClick) {
const nodes = $graph.getProperty('nodes');
const lines = $graph.getProperty('lines');
const uuid = $node.getAttribute('node-uuid') || '';
const block = $graph.getProperty('nodes')[uuid];
const blockEvent = new event_1.BlockMouseEvent(nodes, lines, $node, block);
info.graph.event.onBlockRightClick(blockEvent);
}
});
$graph.addEventListener('node-selected', (event) => {
const type = this.paths[this.paths.length - 1].type;
const info = graph_1.graphMap.get(type);
if (!info) {
return;
}
const $node = event.target;
if (info.graph.event && info.graph.event.onBlockSelected) {
const nodes = $graph.getProperty('nodes');
const lines = $graph.getProperty('lines');
const uuid = $node.getAttribute('node-uuid') || '';
const block = $graph.getProperty('nodes')[uuid];
const event = new event_1.BlockEvent(nodes, lines, $node, block);
info.graph.event.onBlockSelected(event);
}
});
$graph.addEventListener('node-unselected', (event) => {
const type = this.paths[this.paths.length - 1].type;
const info = graph_1.graphMap.get(type);
if (!info) {
return;
}
const $node = event.target;
if (info.graph.event && info.graph.event.onBlockUnselected) {
const nodes = $graph.getProperty('nodes');
const lines = $graph.getProperty('lines');
const uuid = $node.getAttribute('node-uuid') || '';
const block = $graph.getProperty('nodes')[uuid];
const event = new event_1.BlockEvent(nodes, lines, $node, block);
info.graph.event.onBlockUnselected(event);
}
});
$graph.addEventListener('line-selected', (event) => {
const type = this.paths[this.paths.length - 1].type;
const info = graph_1.graphMap.get(type);
if (!info) {
return;
}
const $g = event.target;
if (info.graph.event && info.graph.event.onLineSelected) {
const nodes = $graph.getProperty('nodes');
const lines = $graph.getProperty('lines');
const uuid = $g.getAttribute('line-uuid') || '';
const line = lines[uuid];
const event = new event_1.LineEvent(nodes, lines, $g, line);
info.graph.event.onLineSelected(event);
}
});
$graph.addEventListener('line-unselected', (event) => {
const type = this.paths[this.paths.length - 1].type;
const info = graph_1.graphMap.get(type);
if (!info) {
return;
}
const $g = event.target;
if (info.graph.event && info.graph.event.onLineUnselected) {
const nodes = $graph.getProperty('nodes');
const lines = $graph.getProperty('lines');
const uuid = $g.getAttribute('line-uuid') || '';
const line = lines[uuid];
const event = new event_1.LineEvent(nodes, lines, $g, line);
info.graph.event.onLineUnselected(event);
}
});
$graph.addEventListener('node-added', (event) => {
const cEvent = event;
(0, utils_1.dispatch)(this, 'node-added', {
detail: cEvent.detail,
});
(0, utils_1.dispatch)(this, 'dirty');
});
$graph.addEventListener('node-removed', (event) => {
const cEvent = event;
(0, utils_1.dispatch)(this, 'node-removed', {
detail: cEvent.detail,
});
(0, utils_1.dispatch)(this, 'dirty');
});
$graph.addEventListener('node-changed', (event) => {
const cEvent = event;
(0, utils_1.dispatch)(this, 'node-changed', {
detail: cEvent.detail,
});
(0, utils_1.dispatch)(this, 'dirty');
});
$graph.addEventListener('node-position-changed', (event) => {
const cEvent = event;
const queue = cEvent.detail.moveList.map((item) => {
return new undo_1.BlockPositionAction({
blockName: item.id,
target: item.target,
source: item.source,
});
});
if (queue.length === 1) {
this.actionQueue.exec(queue[0]);
}
else if (queue.length > 1) {
this.actionQueue.exec(new structures_1.ActionList({
queue,
}));
}
(0, utils_1.dispatch)(this, 'dirty', {
detail: {
dirtyType: 'position-changed',
},
});
});
// //// ////
$graph.shadowRoot.addEventListener('dirty', (event) => {
const cEvent = event;
if (cEvent.detail && cEvent.detail.action) {
this.actionQueue.exec(cEvent.detail.action);
}
(0, utils_1.dispatch)(this, 'dirty', {
detail: cEvent.detail,
});
});
$graph.addEventListener('mouseup', (event) => {
const info = graph_1.graphMap.get(this.rootGraph.type);
if (!info) {
return;
}
if (event.button === 2 && info.graph.event?.onGraphRightClick) {
const nodes = $graph.getProperty('nodes');
const lines = $graph.getProperty('lines');
const graphPosition = $graph.convertCoordinate(event.offsetX, event.offsetY);
const customEvent = new event_1.GraphMouseEvent(nodes, lines, $graph, this);
customEvent.initPagePosition(event.pageX, event.pageY);
customEvent.initGraphPosition(graphPosition.x, graphPosition.y);
info.graph.event.onGraphRightClick(customEvent);
}
});
$graph.addEventListener('line-added', (event) => {
const customEment = event;
const $node = $graph.queryNodeElement(customEment.detail.line.output.node);
if ($node) {
// @ts-ignore
$node.onUpdate && $node.onUpdate();
}
(0, utils_1.dispatch)(this, 'line-added', {
detail: customEment.detail,
});
(0, utils_1.dispatch)(this, 'dirty');
});
$graph.addEventListener('line-removed', (event) => {
const customEment = event;
const $node = $graph.queryNodeElement(customEment.detail.line.output.node);
if ($node) {
// @ts-ignore
$node.onUpdate && $node.onUpdate();
}
(0, utils_1.dispatch)(this, 'line-removed', {
detail: customEment.detail,
});
(0, utils_1.dispatch)(this, 'dirty');
});
$graph.addEventListener('line-changed', (event) => {
const customElement = event;
(0, utils_1.dispatch)(this, 'line-changed', {
detail: customElement.detail,
});
(0, utils_1.dispatch)(this, 'dirty');
});
$graph.addEventListener('node-connected', (event) => {
const customElement = event;
this.startRecording();
this.addLine(customElement.detail.line);
setTimeout(() => {
this.stopRecording();
}, 200);
});
const $svg = $graph.shadowRoot.querySelector('#lines');
function searchG(htmlArray) {
const length = Math.min(htmlArray.length, 4);
for (let i = 0; i < length; i++) {
const $elem = htmlArray[i];
// 如果找到顶部的 document 元素的话,是没有 tagName 的
if ($elem.tagName && $elem.tagName.toLocaleLowerCase() === 'g') {
return $elem;
}
}
}
$svg.addEventListener('dblclick', (event) => {
// @ts-ignore
const $g = searchG(event.path);
if (!$g || !$g.hasAttribute('line-uuid')) {
return;
}
const type = this.paths[this.paths.length - 1].type;
const info = graph_1.graphMap.get(type);
if (!info) {
return;
}
if (info.graph.event && info.graph.event.onLineDblClick) {
const nodes = $graph.getProperty('nodes');
const lines = $graph.getProperty('lines');
const uuid = $g.getAttribute('line-uuid') || '';
const line = lines[uuid];
const event = new event_1.LineMouseEvent(nodes, lines, $g, line);
info.graph.event.onLineDblClick(event);
}
});
$svg.addEventListener('click', (event) => {
// @ts-ignore
const $g = searchG(event.path);
if (!$g || !$g.hasAttribute('line-uuid')) {
return;
}
const type = this.paths[this.paths.length - 1].type;
const info = graph_1.graphMap.get(type);
if (!info) {
return;
}
if (info.graph.event && info.graph.event.onLineClick) {
const nodes = $graph.getProperty('nodes');
const lines = $graph.getProperty('lines');
const uuid = $g.getAttribute('line-uuid') || '';
const line = lines[uuid];
const event = new event_1.LineMouseEvent(nodes, lines, $g, line);
info.graph.event.onLineClick(event);
}
});
$svg.addEventListener('mouseup', (event) => {
// @ts-ignore
const $g = searchG(event.path);
if (!$g || !$g.hasAttribute('line-uuid')) {
return;
}
if (event.button !== 2) {
return;
}
const type = this.paths[this.paths.length - 1].type;
const info = graph_1.graphMap.get(type);
if (!info) {
return;
}
if (info.graph.event && info.graph.event.onLineRightClick) {
const nodes = $graph.getProperty('nodes');
const lines = $graph.getProperty('lines');
const uuid = $g.getAttribute('line-uuid') || '';
const line = lines[uuid];
const event = new event_1.LineMouseEvent(nodes, lines, $g, line);
info.graph.event.onLineRightClick(event);
}
});
}
_updateGraph() {
(0, enum_1.clearDynamicEnum)();
const graph = this.paths[this.paths.length - 1];
const $graph = this.shadowRoot.querySelector('v-graph');
$graph.clear();
requestAnimationFrame(() => {
$graph.setAttribute('type', graph.type);
$graph.setProperty('lines', graph.lines);
$graph.setProperty('nodes', graph.nodes);
this._updateHeader();
});
}
undo() {
this.actionQueue.undo();
(0, utils_1.dispatch)(this, 'undo');
}
redo() {
this.actionQueue.redo();
(0, utils_1.dispatch)(this, 'redo');
}
startRecording() {
this.actionQueue.startRecording();
}
stopRecording() {
this.actionQueue.stopRecording();
}
getPinElement(blockName, type, index) {
const $block = this.$graph.shadowRoot.querySelector(`v-graph-node[node-uuid=${blockName}]`);
if (!$block) {
return;
}
const $pinList = $block.shadowRoot.querySelectorAll(`.pin.in`);
const $pin = $pinList[index];
return $pin;
}
getBlockElement(blockName) {
return this.$graph.shadowRoot.querySelector(`v-graph-node[node-uuid=${blockName}]`);
}
/// ---- 操作整个图
/**
* 将屏幕坐标转换成 Graph 内的坐标
* @param point
* @returns
*/
convertCoordinate(point) {
point = this.$graph.convertCoordinate(point.x, point.y);
return point;
}
/**
* 设置编辑的根图
* @param graph
*/
setRootGraph(graph) {
this.rootGraph = graph;
this.paths = [graph];
this._updateGraph();
}
/**
* 获取正在编辑的根图
* @returns
*/
getRootGraph() {
return this.paths[0];
}
/**
* 传入一个字符串反序列化成图数据
* @param content
* @returns
*/
deserialize(content) {
const graphData = js_yaml_1.default.load(content);
return graphData;
}
/**
* 传入一个图数据序列化成 yaml 字符串
* @param data
* @returns
*/
serialize(data) {
const str = js_yaml_1.default.dump(data || this.paths[0]);
// return JSON.stringify(this.paths[0]);
// outputFileSync('/Users/wangsijie/Project/Creator/cocos-editor/extension-repos/shader-graph/test.yaml', str);
return str;
}
/**
* 获取整个图现在的一些基础数据
* @returns
*/
getGraphInfo() {
const offset = this.$graph.getProperty('offset');
const scale = this.$graph.getProperty('scale');
return {
offset, scale,
};
}
/**
* 设置整个图的一些基础数据
* @param info
*/
setGraphInfo(info) {
this.$graph.setProperty('offset', info.offset);
this.$graph.setProperty('scale', info.scale);
}
/**
* 恢复缩放比例
*/
zoomToFit() {
this.$graph.data.setProperty('scale', 1);
}
/// ---- 操作当前图
/**
* 获取选中的 Block 列表
* @returns
*/
getSelectedBlockList() {
return this.$graph.getSelectedNodeList();
}
/**
* 获取选中的 Line 列表
* @returns
*/
getSelectedLineList() {
return this.$graph.getSelectedLineList();
}
/**
* 设置当前正在编辑的图数据
* @param graph
* @returns
*/
setCurrentGraph(graph) {
if (this.paths.length <= 1) {
this.setRootGraph(graph);
return;
}
this.paths[this.paths.length - 1] = graph;
this._updateGraph();
}
/**
* 获取正在编辑的图数据
* @returns
*/
getCurrentGraph() {
return this.paths[this.paths.length - 1];
}
/**
* 在当前正在操作的图数据里增加一个 Block
* @param block
* @param id
*/
addBlock(block, id) {
this.actionQueue.exec(new undo_1.AddBlockAction({ block, id }));
}
/**
* 在当前正在操作的图数据里删除一个节点
* @param id
*/
removeBlock(id) {
const queue = [];
// remove line
const lines = this.$graph.getProperty('lines');
for (const key in lines) {
const line = lines[key];
if (line.input.node === id || line.output.node === id) {
queue.push(new undo_1.RemoveLineAction({ id: key }));
}
}
queue.push(new undo_1.RemoveBlockAction({ id }));
this.actionQueue.exec(new structures_1.ActionList({
queue,
}));
}
/**
* 在当前正在操作的图数据里增加一个连线
* @param line
* @param id
*/
addLine(line, id) {
this.actionQueue.exec(new undo_1.AddLineAction({ line, id }));
}
/**
* 在当前正在操作的图数据里删除一个连线
* @param id
*/
removeLine(id) {
this.actionQueue.exec(new undo_1.RemoveLineAction({ id }));
}
/**
* 进入当前图的子图
* @param id
*/
enterSubGraph(id) {
const graph = this.paths[this.paths.length - 1];
const subGraph = graph.graphs[id];
if (subGraph) {
this.paths.push(subGraph);
this._updateGraph();
}
(0, utils_1.dispatch)(this, 'enter-graph', {
detail: {
id: id,
},
});
}
/**
* 在当前编辑的图里增加一个子图
* @param type
* @param id
* @returns
*/
addSubGraph(type, id) {
const info = this.paths[this.paths.length - 1];
// const uuid = generateUUID();
info.graphs[id] = {
type,
name: type,
nodes: {},
lines: {},
graphs: {},
};
return info.graphs[id];
}
/**
* 在当前编辑的图里删除一个子图
* @param id
*/
removeSubGraph(id) {
const info = this.paths[this.paths.length - 1];
delete info.graphs[id];
}
}
exports.HTMLGraphForgeElement = HTMLGraphForgeElement;
if (!window.customElements.get('ui-graph-forge')) {
window.customElements.define('ui-graph-forge', HTMLGraphForgeElement);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYmxvY2stZm9yZ2UvZm9yZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWSxDQUFDOzs7O0FBVWIsbUNBQW1DO0FBQ25DLG1DQUFpRDtBQUNqRCxtQ0FBa0c7QUFFbEcsc0RBSStCO0FBRS9CLGlDQU1nQjtBQUloQiw4REFBMkI7QUFDM0IsaUNBQTBDO0FBRTFDLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQTs7Ozs7Ozs7O0NBU3BCLENBQUM7QUFFRixNQUFNLElBQUksR0FBRyxRQUFRLENBQUE7U0FDWixLQUFLOzs7Ozs7OztDQVFiLENBQUM7QUFFRixNQUFhLHFCQUFzQixTQUFRLFdBQVc7SUFRbEQ7UUFDSSxLQUFLLEVBQUUsQ0FBQztRQVBKLGdCQUFXLEdBQUcsSUFBSSx3QkFBVyxDQUFDO1lBQ2xDLEtBQUssRUFBRSxJQUFJO1NBQ2QsQ0FBQyxDQUFDO1FBbUJILFVBQUssR0FBZ0IsRUFBRSxDQUFDO1FBYnBCLElBQUksQ0FBQyxZQUFZLENBQUM7WUFDZCxJQUFJLEVBQUUsTUFBTTtTQUNmLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxVQUFXLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztRQUVsQyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxVQUFXLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBa0IsQ0FBQztRQUV6RSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDbkIsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFLTyxXQUFXO1FBQ2YsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxVQUFXLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBRSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQ2hGLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxNQUFxQixDQUFDO1lBQzFDLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxFQUFFO2dCQUNuQyxPQUFPO2FBQ1Y7WUFDRCxJQUFJLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQztZQUM5RCxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUU7Z0JBQ1gsS0FBSyxHQUFHLENBQUMsQ0FBQzthQUNiO1lBQ0QsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQzdCLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNwQixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ2hELElBQUEsZ0JBQVEsRUFBQyxJQUFJLEVBQUUsYUFBYSxFQUFFO2dCQUMxQixNQUFNLEVBQUU7b0JBQ0osRUFBRSxFQUFFLEtBQUssQ0FBQyxJQUFJO2lCQUNqQjthQUNKLENBQUMsQ0FBQztRQUNQLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVPLGFBQWE7UUFDakIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxxQkFBcUIsS0FBSyxLQUFLLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLElBQUksU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQy9ILElBQUksQ0FBQyxVQUFXLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBRSxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUM7SUFDdEUsQ0FBQztJQUVPLFlBQVk7UUFDaEIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVcsQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFpQixDQUFDO1FBQ3pFLE1BQU0sQ0FBQyxVQUFXLENBQUMsZ0JBQWdCLENBQUMsYUFBYSxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDekQsTUFBTSxXQUFXLEdBQUcsS0FDbEIsQ0FBQztZQUNILE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQ3BELE1BQU0sSUFBSSxHQUFHLGdCQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2hDLElBQUksQ0FBQyxJQUFJLEVBQUU7Z0JBQ1AsT0FBTzthQUNWO1lBQ0QsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDLE1BQTBCLENBQUM7WUFDckQsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQUU7Z0JBQ25ELE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFtQyxDQUFDO2dCQUM1RSxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBa0MsQ0FBQztnQkFDM0UsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ25ELE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFjLENBQUM7Z0JBQzdELE1BQU0sVUFBVSxHQUFHLElBQUksdUJBQWUsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztnQkFDbkUsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2FBQzdDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFDSCxNQUFNLENBQUMsVUFBVyxDQUFDLGdCQUFnQixDQUFDLGdCQUFnQixFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDNUQsTUFBTSxXQUFXLEdBQUcsS0FLbEIsQ0FBQztZQUNILE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQ3BELE1BQU0sSUFBSSxHQUFHLGdCQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2hDLElBQUksQ0FBQyxJQUFJLEVBQUU7Z0JBQ1AsT0FBTzthQUNWO1lBQ0QsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDLE1BQTBCLENBQUM7WUFDckQsSUFBSSxLQUFLLENBQUMsT0FBTyxLQUFLLGNBQWMsRUFBRTtnQkFDbEMsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLFdBQ