@giro3d/piero-plugin-cityjson
Version:
Load CityJSON datasets in Piero
215 lines (134 loc) • 93.4 kB
JavaScript
"use strict";var $=Object.defineProperty;var Z=(m,e,t)=>e in m?$(m,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):m[e]=t;var x=(m,e,t)=>Z(m,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const K=require("/builds/giro3d/piero/node_modules/@giro3d/giro3d/gui/EntityPanel.js"),Q=require("/builds/giro3d/piero/node_modules/@giro3d/giro3d/core/geographic/Coordinates.js"),Y=require("/builds/giro3d/piero/node_modules/@giro3d/giro3d/entities/Entity3D.js"),E=require("/builds/giro3d/piero/packages/piero/dist/index.es.js"),o=require("/builds/giro3d/piero/node_modules/three");require("/builds/giro3d/piero/node_modules/three/examples/jsm/lines/LineMaterial");const ee=require("/builds/giro3d/piero/node_modules/three/examples/jsm/lines/LineSegments2"),te=require("/builds/giro3d/piero/node_modules/three/examples/jsm/lines/LineSegmentsGeometry"),se=require("/builds/giro3d/piero/node_modules/earcut/src/earcut.js"),ie=require("/builds/giro3d/piero/node_modules/@giro3d/giro3d/gui/EntityInspector.js");var B=typeof document<"u"?document.currentScript:null;const re={Building:7641055,BuildingPart:7641055,BuildingInstallation:7641055,Bridge:10066329,BridgePart:10066329,BridgeInstallation:10066329,BridgeConstructionElement:10066329,CityObjectGroup:16777139,CityFurniture:13369344,GenericCityObject:13369344,LandUse:16777139,PlantCover:3779641,Railway:0,Road:10066329,SolitaryVegetationObject:3779641,TINRelief:16767897,TransportSquare:10066329,Tunnel:10066329,TunnelPart:10066329,TunnelInstallation:10066329,WaterBody:5089023},X={GroundSurface:10066329,WallSurface:16777215,RoofSurface:16711680,TrafficArea:7237230,AuxiliaryTrafficArea:2916864,Window:23039,Door:6553600},_=0,w=1,L=2;class j{constructor(e){this.geometryType=e,this.vertexIds=[],this.objectIds=[],this.objectTypes=[],this.semanticSurfaces=[],this.geometryIds=[],this.boundaryIds=[],this.lodIds=[],this.materials={},this.textures={}}appendMaterial(e,t){e in this.materials||(this.materials[e]=[]);const s=this.materials[e];for(let i=s.length;i<this.count()-1;i++)s.push(-1);this.materials[e].push(t)}appendTexture(e,t){e in this.textures||(this.textures[e]={index:[],uvs:[]});const s=this.textures[e];for(let i=s.index.length;i<this.count()-1;i++)s.index.push(-1),s.uvs.push([0,0]);s.index.push(t.index),s.uvs.push(t.uvs)}addVertex(e,t,s,i,n,r,a,y,c){if(this.vertexIds.push(e),this.objectIds.push(t),this.objectTypes.push(s),this.semanticSurfaces.push(i),this.geometryIds.push(n),this.boundaryIds.push(r),this.lodIds.push(a),y){const h=this;Object.entries(y).forEach(l=>{const[d,u]=l;h.appendMaterial(d,u)})}if(c){const h=this;Object.entries(c).forEach(l=>{const[d,u]=l;h.appendTexture(d,u)})}}completeMaterials(){for(const e in this.materials){const t=this.materials[e];for(let s=t.length;s<this.count();s++)t.push(-1)}}completeTextures(){for(const e in this.textures){const t=this.textures[e];for(let s=t.index.length;s<this.count();s++)t.index.push(-1),t.uvs.push([0,0])}}count(){return this.vertexIds.length}getVertices(e){let t=[];for(const s of this.vertexIds){const i=e[s];t.push(...i)}return t}toObject(){return this.completeMaterials(),this.completeTextures(),{geometryType:this.geometryType,objectIds:this.objectIds,objectType:this.objectTypes,semanticSurfaces:this.semanticSurfaces,geometryIds:this.geometryIds,boundaryIds:this.boundaryIds,lodIds:this.lodIds,materials:this.materials,textures:this.textures}}setObjectId(e){for(let t=0;t<this.objectIds.length;t++)this.objectIds[t]=e}setObjectType(e){for(let t=0;t<this.objectTypes.length;t++)this.objectTypes[t]=e}setGeometryIdx(e){for(let t=0;t<this.geometryIds.length;t++)this.geometryIds[t]=e}merge(e){e.geometryType!=this.geometryType&&console.warn("Merging different types of geometry data!"),this.vertexIds.concat(this.otherGeomData.vertexId),this.objectIds.concat(this.otherGeomData.objectId),this.objectTypes.concat(this.otherGeomData.objectType),this.semanticSurfaces.concat(this.otherGeomData.surfaceType),this.geometryIds.concat(this.otherGeomData.geometryIdx),this.boundaryIds.concat(this.otherGeomData.boundaryIdx),this.lodIds.concat(this.otherGeomData.lodIdx)}}o.UniformsLib.cityobject={objectColors:{value:[]},surfaceColors:{value:[]},attributeColors:{value:[]},cityMaterials:{value:[]},cityTexture:{type:"t"},showLod:{value:-1},highlightedObjId:{value:-1},highlightedGeomId:{value:-1},highlightedBoundId:{value:-1},highlightColor:{value:new o.Color(16761095).convertSRGBToLinear()}};o.ShaderChunk.cityobjectinclude_vertex=`
uniform vec3 objectColors[ OBJCOLOR_COUNT ];
uniform vec3 highlightColor;
uniform float highlightedObjId;
attribute float objectid;
attribute int type;
varying vec3 diffuse_;
#ifdef SHOW_SEMANTICS
uniform vec3 surfaceColors[ SEMANTIC_COUNT ];
attribute int surfacetype;
#endif
#ifdef COLOR_ATTRIBUTE
uniform vec3 attributeColors[ ATTRIBUTE_COUNT ];
attribute int attributevalue;
#endif
#ifdef SELECT_SURFACE
uniform float highlightedGeomId;
uniform float highlightedBoundId;
attribute float geometryid;
attribute float boundaryid;
#endif
#ifdef SHOW_LOD
uniform float showLod;
attribute float lodid;
varying float discard_;
#endif
#ifdef MATERIAL_THEME
struct CityMaterial
{
vec3 diffuseColor;
vec3 emissiveColor;
vec3 specularColor;
};
uniform CityMaterial cityMaterials[ MATERIAL_COUNT ];
varying vec3 emissive_;
attribute int MATERIAL_THEME;
#endif
#ifdef TEXTURE_THEME
attribute int TEXTURE_THEME;
attribute vec2 TEXTURE_THEME_UV;
flat out int vTexIndex;
varying vec2 vTexUV;
#endif
`;o.ShaderChunk.cityobjectdiffuse_vertex=`
#ifdef SHOW_SEMANTICS
diffuse_ = surfacetype > -1 ? surfaceColors[surfacetype] : objectColors[type];
#else
diffuse_ = objectColors[type];
#endif
#ifdef COLOR_ATTRIBUTE
diffuse_ = attributevalue > -1 ? attributeColors[attributevalue] : vec3( 0.0, 0.0, 0.0 );
#endif
#ifdef MATERIAL_THEME
if ( MATERIAL_THEME > - 1 ) {
diffuse_ = cityMaterials[ MATERIAL_THEME ].diffuseColor;
emissive_ = cityMaterials[ MATERIAL_THEME ].emissiveColor;
}
#endif
#ifdef TEXTURE_THEME
vTexIndex = TEXTURE_THEME;
vTexUV = TEXTURE_THEME_UV;
if ( vTexIndex > - 1 ) {
diffuse_ = vec3( 1.0, 1.0, 1.0 );
}
#endif
#ifdef SELECT_SURFACE
diffuse_ = abs( objectid - highlightedObjId ) < 0.5 && abs( geometryid - highlightedGeomId ) < 0.5 && abs( boundaryid - highlightedBoundId ) < 0.5 ? highlightColor : diffuse_;
#else
diffuse_ = abs( objectid - highlightedObjId ) < 0.5 ? highlightColor : diffuse_;
#endif
`;o.ShaderChunk.cityobjectshowlod_vertex=`
#ifdef SHOW_LOD
if ( abs ( lodid - showLod ) > 0.5 ) {
discard_ = 1.0;
}
#endif
`;class R extends o.ShaderMaterial{constructor(e){super(e),this.objectColors={},this.surfaceColors={},this.attributeColors={},this.materials=[],this.showSemantics=!0,this.textures=[],this.instancing=!1,this.isCityObjectsMaterial=!0,this.defines.OBJCOLOR_COUNT=0,this.defines.SEMANTIC_COUNT=0,this.defines.ATTRIBUTE_COUNT=0,this.defines.MATERIAL_COUNT=0}createColorsArray(e){const t=[];for(const s in e){const i=new o.Color(e[s]);t.push(i.convertSRGBToLinear())}return t}set attributeColors(e){this.attributeColorsLookup=e,this.uniforms.attributeColors.value=this.createColorsArray(e),this.defines.ATTRIBUTE_COUNT=Object.keys(e).length}get attributeColors(){return this.attributeColorsLookup}get conditionalFormatting(){return"COLOR_ATTRIBUTE"in this.defines}set conditionalFormatting(e){!!e!="COLOR_ATTRIBUTE"in this.defines&&(this.needsUpdate=!0),e===!0?this.defines.COLOR_ATTRIBUTE="":delete this.defines.COLOR_ATTRIBUTE}set objectColors(e){this.objectColorsLookup=e,this.uniforms.objectColors.value=this.createColorsArray(e),this.defines.OBJCOLOR_COUNT=Object.keys(e).length}get objectColors(){return this.objectColorsLookup}set surfaceColors(e){this.surfaceColorsLookup=e,this.uniforms.surfaceColors.value=this.createColorsArray(e),this.defines.SEMANTIC_COUNT=Object.keys(e).length,this.needsUpdate=!0}get surfaceColors(){return this.surfaceColorsLookup}get showSemantics(){return"SHOW_SEMANTICS"in this.defines}set showSemantics(e){!!e!="SHOW_SEMANTICS"in this.defines&&(this.needsUpdate=!0),e===!0?this.defines.SHOW_SEMANTICS="":delete this.defines.SHOW_SEMANTICS}get selectSurface(){return"SELECT_SURFACE"in this.defines}set selectSurface(e){!!e!="SELECT_SURFACE"in this.defines&&(this.needsUpdate=!0),e===!0?this.defines.SELECT_SURFACE="":delete this.defines.SELECT_SURFACE}get showLod(){return this.uniforms.showLod.value}set showLod(e){e>-1!="SHOW_LOD"in this.defines&&(this.needsUpdate=!0),e>-1?this.defines.SHOW_LOD="":delete this.defines.SHOW_LOD,this.uniforms.showLod.value=e}set materialTheme(e){const t=e.replace(/[^a-z0-9]/gi,"");t!==this.defines.MATERIAL_THEME&&(this.needsUpdate=!0),e==="undefined"||e===void 0||e==null?delete this.defines.MATERIAL_THEME:this.defines.MATERIAL_THEME=`mat${t}`}set textureTheme(e){const t=e.replace(/[^a-z0-9]/gi,"");t!==this.defines.TEXTURE_THEME&&(this.needsUpdate=!0),e==="undefined"||e===void 0||e==null?(delete this.defines.TEXTURE_THEME,delete this.defines.TEXTURE_THEME_UV):(this.defines.TEXTURE_THEME=`tex${t}`,this.defines.TEXTURE_THEME_UV=`tex${t}uv`)}set materials(e){const t=[];for(let s=0;s<e.length;s++){const i=Object.assign({diffuseColor:[1,1,1],emissiveColor:[0,0,0],specularColor:[1,1,1]},e[s]);i.diffuseColor=new o.Color(...i.diffuseColor).convertLinearToSRGB(),i.emissiveColor=new o.Color(...i.emissiveColor).convertLinearToSRGB(),i.specularColor=new o.Color(...i.specularColor).convertLinearToSRGB(),t.push(i)}this.defines.MATERIAL_COUNT=t.length,this.uniforms.cityMaterials.value=t}get highlightColor(){return this.uniforms.highlightColor}set highlightColor(e){typeof e=="string"||e instanceof String?this.uniforms.highlightColor.value.setHex(e.replace("#","0x")):e instanceof Number?this.uniforms.highlightColor.setHex(e):e instanceof o.Color&&(this.uniforms.highlightColor=e)}get highlightedObject(){return{objectIndex:this.uniforms.highlightedObjId.value,geometryIndex:this.uniforms.highlightedGeomId.value,boundaryIndex:this.uniforms.highlightedBoundId.value}}set highlightedObject(e){e?(this.uniforms.highlightedObjId.value=e.objectIndex===void 0?-1:e.objectIndex,this.uniforms.highlightedGeomId.value=e.geometryIndex===void 0?-1:e.geometryIndex,this.uniforms.highlightedBoundId.value=e.boundaryIndex===void 0?-1:e.boundaryIndex):(this.uniforms.highlightedObjId.value=-1,this.uniforms.highlightedGeomId.value=-1,this.uniforms.highlightedBoundId.value=-1)}}class ne extends R{constructor(e,t){const s={...e};s.uniforms={...o.UniformsUtils.clone(o.UniformsLib.cityobject),...o.UniformsUtils.clone(e.uniforms)},s.extensions={derivatives:!0},s.lights=!0,s.vertexShader=o.ShaderChunk.cityobjectinclude_vertex+s.vertexShader.replace(/#include <fog_vertex>/,`
#include <fog_vertex>
`+o.ShaderChunk.cityobjectdiffuse_vertex+o.ShaderChunk.cityobjectshowlod_vertex),s.fragmentShader=`
varying vec3 diffuse_;
varying float discard_;
#ifdef TEXTURE_THEME
uniform sampler2D cityTexture;
flat in int vTexIndex;
varying vec2 vTexUV;
#endif
#ifdef MATERIAL_THEME
varying vec3 emissive_;
#endif
`+s.fragmentShader.replace(/vec4 diffuseColor = vec4\( diffuse, opacity \);/,`
vec4 diffuseColor = vec4( diffuse_, opacity );
#ifdef TEXTURE_THEME
if ( vTexIndex > - 1 ) {
vec4 tempDiffuseColor = vec4(1.0, 1.0, 1.0, 0.0);
tempDiffuseColor = texture2D( cityTexture, vTexUV );
diffuseColor *= tempDiffuseColor;
}
#endif
#ifdef SHOW_LOD
if ( discard_ > 0.0 ) {
discard;
}
#endif
`).replace(/vec3 totalEmissiveRadiance = emissive;/,`
#ifdef MATERIAL_THEME
vec3 totalEmissiveRadiance = emissive_;
#else
vec3 totalEmissiveRadiance = emissive;
#endif
`),super(s),this.setValues(t)}}class oe extends o.Mesh{constructor(e,t,s,i,n){const r=new o.BufferGeometry,a=new Float32Array(t);r.setAttribute("position",new o.BufferAttribute(a,3));const y=new Uint16Array(s.objectIds);r.setAttribute("objectid",new o.BufferAttribute(y,1));const c=new Uint8Array(s.objectType);r.setAttribute("type",new o.Int32BufferAttribute(c,1));const h=new Int8Array(s.semanticSurfaces);r.setAttribute("surfacetype",new o.Int32BufferAttribute(h,1));const l=new Float32Array(s.geometryIds);r.setAttribute("geometryid",new o.BufferAttribute(l,1));const d=new Int8Array(s.lodIds);r.setAttribute("lodid",new o.BufferAttribute(d,1));const u=new Float32Array(s.boundaryIds);r.setAttribute("boundaryid",new o.BufferAttribute(u,1));for(const f in s.materials){const g=f.replace(/[^a-z0-9]/gi,""),b=new Uint8Array(s.materials[f]);r.setAttribute(`mat${g}`,new o.Int32BufferAttribute(b,1))}for(const f in s.textures){const g=f.replace(/[^a-z0-9]/gi,""),b=new Int16Array(s.textures[f].index);r.setAttribute(`tex${g}`,new o.Int32BufferAttribute(b,1));const I=new Float32Array(s.textures[f].uvs.flat(1));r.setAttribute(`tex${g}uv`,new o.BufferAttribute(I,2))}r.attributes.position.needsUpdate=!0,i&&r.applyMatrix4(i),r.computeVertexNormals(),super(r,n),this.citymodel=e,this.isCityObject=!0,this.isCityObjectMesh=!0,this.supportsConditionalFormatting=!0,this.supportsMaterials=!0}setArrayAsAttribute(e){this.geometry.setAttribute("attributevalue",new o.Int32BufferAttribute(new Int32Array(e),1))}addAttributeByProperty(e){const t=e.getAllValues(),s=e.getUniqueValues();if(s.length<110){const i=[];for(const a of t)i.push(s.indexOf(a));const n=this.geometry.attributes.objectid.array,r=n.map(a=>i[a]);if(r.length!==n.length){console.warn("Wrong size of attributes array.");return}this.setArrayAsAttribute(r)}}getIntersectionVertex(e){return e.face.a}resolveIntersectionInfo(e){const t={},s=this.getIntersectionVertex(e),i=this.geometry.getAttribute("objectid").getX(s);return t.vertexIndex=s,t.objectIndex=i,t.objectId=Object.keys(this.citymodel.CityObjects)[i],t.geometryIndex=this.geometry.getAttribute("geometryid").getX(s),t.boundaryIndex=this.geometry.getAttribute("boundaryid").getX(s),t.objectTypeIndex=this.geometry.getAttribute("type").getX(s),t.surfaceTypeIndex=this.geometry.getAttribute("surfacetype").getX(s),t.lodIndex=this.geometry.getAttribute("lodid").getX(s),t}setTextureTheme(e,t){if(e==="undefined"){this.unsetTextures();return}const i=`tex${e.replace(/[^a-z0-9]/gi,"")}`;if(i in this.geometry.attributes){const n=this.geometry.attributes[i].array,{values:r,indices:a}=n.reduce((l,d,u)=>(l.last!==d&&(l.values.push(d),l.indices.push(u),l.last=d),l),{last:-1,values:[],indices:[]}),y=Array.isArray(this.material)?this.material[this.material.length-1]:this.material,c=t.getMaterials(y);for(const l of c)l!==y&&(l.textureTheme=e);for(let l=0;l<a.length-1;l++)this.geometry.addGroup(a[l],a[l+1]-a[l],r[l]>-1?r[l]:c.length-1);const h=a.length-1;this.geometry.addGroup(a[h],this.geometry.attributes.type.array.length-a[h],r[h]>-1?r[h]:c.length-1),this.material=c}}unsetTextures(){Array.isArray(this.material)&&(this.material=this.material[this.material.length-1]),this.material.textureTheme="undefined"}}function T(m){let e=[m.length/2];for(let t=0;t<m.length;t+=2)e[t/2]=m[t];return e}class H extends ee.LineSegments2{constructor(e,t,s,i,n){const r=new te.LineSegmentsGeometry;r.setPositions(new Float32Array(t));const a=new Float32Array(T(s.objectIds));r.setAttribute("objectid",new o.InstancedBufferAttribute(a,1));const y=new Int32Array(T(s.objectType));r.setAttribute("type",new o.InstancedBufferAttribute(y,1));const c=new Int32Array(T(s.semanticSurfaces));r.setAttribute("surfacetype",new o.InstancedBufferAttribute(c,1));const h=new Float32Array(T(s.geometryIds));r.setAttribute("geometryid",new o.InstancedBufferAttribute(h,1));const l=new Uint8Array(T(s.lodIds));r.setAttribute("lodid",new o.InstancedBufferAttribute(l,1));const d=new Float32Array(T(s.boundaryIds));r.setAttribute("boundaryid",new o.InstancedBufferAttribute(d,1)),i&&r.applyMatrix4(i),super(r,n),this.citymodel=e,this.isCityObject=!0,this.isCityObjectLine=!0}getIntersectionVertex(e){return e.faceIndex}resolveIntersectionInfo(e){const t={},s=this.getIntersectionVertex(e),i=this.geometry.getAttribute("objectid").getX(s);return t.vertexIndex=s,t.objectIndex=i,t.objectId=Object.keys(this.citymodel.CityObjects)[i],t.geometryIndex=this.geometry.getAttribute("geometryid").getX(s),t.boundaryIndex=this.geometry.getAttribute("boundaryid").getX(s),t.objectTypeIndex=this.geometry.getAttribute("type").getX(s),t.surfaceTypeIndex=this.geometry.getAttribute("surfacetype").getX(s),t.lodIndex=this.geometry.getAttribute("lodid").getX(s),t}}class D extends o.Points{constructor(e,t,s,i,n){const r=new o.BufferGeometry,a=new Float32Array(t);r.setAttribute("position",new o.BufferAttribute(a,3));const y=new Uint16Array(s.objectIds);r.setAttribute("objectid",new o.BufferAttribute(y,1));const c=new Uint8Array(s.objectType);r.setAttribute("type",new o.Int32BufferAttribute(c,1));const h=new Int8Array(s.semanticSurfaces);r.setAttribute("surfacetype",new o.Int32BufferAttribute(h,1));const l=new Float32Array(s.geometryIds);r.setAttribute("geometryid",new o.BufferAttribute(l,1));const d=new Int8Array(s.lodIds);r.setAttribute("lodid",new o.BufferAttribute(d,1));const u=new Float32Array(s.boundaryIds);r.setAttribute("boundaryid",new o.BufferAttribute(u,1)),r.attributes.position.needsUpdate=!0,i&&r.applyMatrix4(i),r.computeVertexNormals(),super(r,n),this.citymodel=e,this.isCityObject=!0,this.isCityObjectPoints=!0}getIntersectionVertex(e){return e.index}resolveIntersectionInfo(e){const t={},s=this.getIntersectionVertex(e),i=this.geometry.getAttribute("objectid").getX(s);return t.vertexIndex=s,t.objectIndex=i,t.objectId=Object.keys(this.citymodel.CityObjects)[i],t.geometryIndex=this.geometry.getAttribute("geometryid").getX(s),t.boundaryIndex=this.geometry.getAttribute("boundaryid").getX(s),t.objectTypeIndex=this.geometry.getAttribute("type").getX(s),t.surfaceTypeIndex=this.geometry.getAttribute("surfacetype").getX(s),t.lodIndex=this.geometry.getAttribute("lodid").getX(s),t}}class ae extends R{constructor(e){const t=o.ShaderLib.line,s={...t};s.uniforms={...o.UniformsLib.cityobject,...o.UniformsUtils.clone(t.uniforms)},s.extensions={derivatives:!0},s.lights=!1,s.vertexShader=o.ShaderChunk.cityobjectinclude_vertex+s.vertexShader.replace(/#include <fog_vertex>/,`
#include <fog_vertex>
`+o.ShaderChunk.cityobjectdiffuse_vertex+o.ShaderChunk.cityobjectshowlod_vertex),s.fragmentShader=`
varying vec3 diffuse_;
varying float discard_;
`+s.fragmentShader.replace(/vec4 diffuseColor = vec4\( diffuse, alpha \);/,`
vec4 diffuseColor = vec4( diffuse_, alpha );
#ifdef SHOW_LOD
if ( discard_ > 0.0 ) {
discard;
}
#endif
`),super(s),Object.defineProperties(this,{color:{enumerable:!0,get:function(){return this.uniforms.diffuse.value},set:function(i){this.uniforms.diffuse.value=i}},worldUnits:{enumerable:!0,get:function(){return"WORLD_UNITS"in this.defines},set:function(i){i===!0?this.defines.WORLD_UNITS="":delete this.defines.WORLD_UNITS}},linewidth:{enumerable:!0,get:function(){return this.uniforms.linewidth.value},set:function(i){this.uniforms.linewidth.value=i}},dashed:{enumerable:!0,get:function(){return"USE_DASH"in this.defines},set(i){!!i!="USE_DASH"in this.defines&&(this.needsUpdate=!0),i===!0?this.defines.USE_DASH="":delete this.defines.USE_DASH}},dashScale:{enumerable:!0,get:function(){return this.uniforms.dashScale.value},set:function(i){this.uniforms.dashScale.value=i}},dashSize:{enumerable:!0,get:function(){return this.uniforms.dashSize.value},set:function(i){this.uniforms.dashSize.value=i}},dashOffset:{enumerable:!0,get:function(){return this.uniforms.dashOffset.value},set:function(i){this.uniforms.dashOffset.value=i}},gapSize:{enumerable:!0,get:function(){return this.uniforms.gapSize.value},set:function(i){this.uniforms.gapSize.value=i}},opacity:{enumerable:!0,get:function(){return this.uniforms.opacity.value},set:function(i){this.uniforms.opacity.value=i}},resolution:{enumerable:!0,get:function(){return this.uniforms.resolution.value},set:function(i){this.uniforms.resolution.value.copy(i)}},alphaToCoverage:{enumerable:!0,get:function(){return"USE_ALPHA_TO_COVERAGE"in this.defines},set:function(i){!!i!="USE_ALPHA_TO_COVERAGE"in this.defines&&(this.needsUpdate=!0),i===!0?(this.defines.USE_ALPHA_TO_COVERAGE="",this.extensions.derivatives=!0):(delete this.defines.USE_ALPHA_TO_COVERAGE,this.extensions.derivatives=!1)}}}),this.setValues(e)}}class le extends R{constructor(e){const t=o.ShaderLib.points,s={...t};s.uniforms={...o.UniformsLib.cityobject,...o.UniformsUtils.clone(t.uniforms)},s.extensions={derivatives:!0},s.lights=!1,s.vertexShader=o.ShaderChunk.cityobjectinclude_vertex+s.vertexShader.replace(/#include <fog_vertex>/,`
#include <fog_vertex>
`+o.ShaderChunk.cityobjectdiffuse_vertex+o.ShaderChunk.cityobjectshowlod_vertex),s.fragmentShader=`
varying vec3 diffuse_;
varying float discard_;
`+s.fragmentShader.replace(/vec4 diffuseColor = vec4\( diffuse, opacity \);/,`
vec4 diffuseColor = vec4( diffuse_, opacity );
#ifdef SHOW_LOD
if ( discard_ > 0.0 ) {
discard;
}
#endif
`),super(s,e),this.setValues(e)}get size(){return this.uniforms.size.value}set size(e){this.uniforms.size.value=e}get sizeAttenuation(){return"USE_SIZEATTENUATION"in this.defines}set sizeAttenuation(e){!!e!="USE_SIZEATTENUATION"in this.defines&&(this.needsUpdate=!0),e===!0?this.defines.USE_SIZEATTENUATION="":delete this.defines.USE_SIZEATTENUATION}}class N{constructor(e,t,s){this.json=e,this.objectIds=t,this.objectColors=s,this.surfaceColors=X,this.lods=[]}clean(){}parseGeometry(e,t,s){}getObjectIdx(e){return this.objectIds.indexOf(e)}getObjectTypeIdx(e){let t=Object.keys(this.objectColors).indexOf(e);return t<0&&(t=Object.keys(this.objectColors).length,this.objectColors[e]=Math.floor(Math.random()*16777215)),t}getSurfaceTypeIdx(e,t,s){let i=-1;if(t.length>0){const n=s[t[e]];n&&(i=Object.keys(this.surfaceColors).indexOf(n.type),i<0&&(i=Object.keys(this.surfaceColors).length,this.surfaceColors[n.type]=Math.floor(Math.random()*16777215)))}return i}getSurfaceMaterials(e,t){const s=Object.entries(t).map(i=>{const[n,r]=i;return r.values?[n,r.values[e]]:r.value!==void 0?[n,r.value]:[n,-1]});return Object.fromEntries(s)}getTextureData(e,t,s,i){if(this.json.appearance&&this.json.appearance["vertices-texture"]){const n=this.json.appearance["vertices-texture"],r=Object.entries(i).map(a=>{const[y,c]=a;if(c.values){const h=s.filter(f=>f<=t),l=h.length,d=l?t-h[h.length-1]:t,u=c.values[e];if(u[0][0]!==null){const f=n[u[l][d+1]];return[y,{index:u[0][0],uvs:f}]}return[y,{index:-1,uvs:[0,0]}]}else return[y,{index:-1,uvs:[0,0]}]});return Object.fromEntries(r)}}getLodIndex(e){if(e===void 0)return-1;const t=this.lods.indexOf(e);if(t<0){const s=this.lods.length;return this.lods.push(e),s}return t}}class ce extends N{constructor(e,t,s,i){super(e,t,s),i?this.vertices=i:this.vertices=this.json.vertices,this.geomData=new j(L)}clean(){this.geomData=new j(L)}flattenGeometry(e){const t=e.type;if(t=="MultiSurface"||t=="CompositeSurface")return e;if(t=="Solid"){const s=Object.assign({},e);if(s.boundaries=e.boundaries.flat(1),e.semantics&&(s.semantics.values=e.semantics.values.flat(1)),e.material)for(const i in e.material)s.material[i].values=e.material[i].values.flat(1);if(e.texture)for(const i in e.texture)s.texture[i].values=e.texture[i].values.flat(1);return s}if(t=="MultiSolid"||t=="CompositeSolid"){const s=Object.assign({},e);if(s.boundaries=e.boundaries.flat(2),e.semantics&&(s.semantics.values=e.semantics.values.flat(2)),e.material)for(const i in e.material)s.material[i].values=e.material[i].values.flat(2);if(e.texture)for(const i in e.texture)s.texture[i].values=e.texture[i].values.flat(2);return s}}parseGeometry(e,t,s){const i=this.json.CityObjects[t],n=i?this.getObjectIdx(t):-1,r=i?this.getObjectTypeIdx(i.type):-1,a=this.getLodIndex(e.lod),y=this.flattenGeometry(e);y&&this.parseShell(y,n,r,s,a)}parseShell(e,t,s,i,n){const r=e.boundaries,a=e.semantics?e.semantics.values:[],y=e.semantics?e.semantics.surfaces:[],c=e.material?e.material:{},h=e.texture?e.texture:{};for(let l=0;l<r.length;l++){let d=[],u=[];const f=this.getSurfaceTypeIdx(l,a,y),g=this.getSurfaceMaterials(l,c);for(let b=0;b<r[l].length;b++)d.length>0&&u.push(d.length),d.push(...r[l][b]);if(d.length==3)for(let b=0;b<3;b++)this.geomData.addVertex(d[b],t,s,f,i,l,n,g,this.getTextureData(l,b,u,h));else if(d.length>3){let b=[];for(let p=0;p<d.length;p++)b.push({x:this.vertices[d[p]][0],y:this.vertices[d[p]][1],z:this.vertices[d[p]][2]});const I=this.getNewellsNormal(b);let v=[];for(let p=0;p<b.length;p++){const A=this.to_2d(b[p],I);v.push(A.x),v.push(A.y)}const C=se(v,u,2);for(let p=0;p<C.length;p+=3)for(let A=0;A<3;A++){const O=d[C[p+A]];this.geomData.addVertex(O,t,s,f,i,l,n,g,this.getTextureData(l,C[p+A],u,h))}}}}getNewellsNormal(e){let t=[0,0,0];for(let i=0;i<e.length;i++){let n=i+1;n==e.length&&(n=0),t[0]=t[0]+(e[i].y-e[n].y)*(e[i].z+e[n].z),t[1]=t[1]+(e[i].z-e[n].z)*(e[i].x+e[n].x),t[2]=t[2]+(e[i].x-e[n].x)*(e[i].y+e[n].y)}return new o.Vector3(t[0],t[1],t[2]).normalize()}to_2d(e,t){e=new o.Vector3(e.x,e.y,e.z);let s=new o.Vector3(1.1,1.1,1.1);s.distanceTo(t)<.01&&s.add(new o.Vector3(1,2,3));let i=s.dot(t),n=t.clone();n.multiplyScalar(i),s.sub(n),s.normalize();let r=t.clone();r.cross(s);let a=e.dot(s),y=e.dot(r);return{x:a,y}}}class ue extends N{constructor(e,t,s){super(e,t,s),this.geomData=new j(w)}clean(){this.geomData=new j(w)}handles(e){return e.type=="MultiLineString"}parseGeometry(e,t,s){const i=e.semantics?e.semantics.surfaces:[];if(e.type=="MultiLineString"){const n=this.json.CityObjects[t],r=this.getObjectIdx(t),a=this.getObjectTypeIdx(n.type),y=this.getLodIndex(n.geometry[s].lod),c=e.boundaries;for(let h=0;h<c.length;h++)if(c[h].length>1){const l=e.semantics?e.semantics.values:[],d=this.getSurfaceTypeIdx(h,l,i),u=c[h];for(let f=0;f<c[h].length-1;f++)this.geomData.addVertex(u[f],r,a,d,s,h,y),this.geomData.addVertex(u[f+1],r,a,d,s,h,y)}}}}class de extends N{constructor(e,t,s){super(e,t,s),this.geomData=new j(_)}clean(){this.geomData=new j(_)}handles(e){return e.type=="MultiPoint"}parseGeometry(e,t,s){const i=e.semantics?e.semantics.surfaces:[];if(e.type=="MultiPoint"){const n=this.json.CityObjects[t],r=this.getObjectIdx(t),a=this.getObjectTypeIdx(n.type),y=this.getLodIndex(n.geometry[s].lod),c=e.boundaries;for(let h=0;h<c.length;h++){const l=e.semantics?e.semantics.values:[],d=this.getSurfaceTypeIdx(h,l,i);this.geomData.addVertex(c[h],r,a,d,s,h,y)}}}}class he extends o.InstancedMesh{constructor(e,t,s,i,n,r){const a=new o.InstancedBufferGeometry,y=new Float32Array(t);a.setAttribute("position",new o.BufferAttribute(y,3));const c=new Uint16Array(i.objectIds);a.setAttribute("objectid",new o.InstancedBufferAttribute(c,1));const h=new Int32Array(i.objectType);a.setAttribute("type",new o.InstancedBufferAttribute(h,1));const l=new Int8Array(s.semanticSurfaces);a.setAttribute("surfacetype",new o.Int32BufferAttribute(l,1));const d=new Float32Array(i.geometryIds);a.setAttribute("geometryid",new o.InstancedBufferAttribute(d,1));const u=new Int8Array(s.lodIds);a.setAttribute("lodid",new o.BufferAttribute(u,1));const f=new Float32Array(s.boundaryIds);a.setAttribute("boundaryid",new o.BufferAttribute(f,1));for(const g in s.materials){const b=new Uint8Array(s.materials[g]);a.setAttribute(`mat${g}`,new o.Int32BufferAttribute(b,1))}a.attributes.position.needsUpdate=!0,n&&a.applyMatrix4(n),a.computeVertexNormals(),super(a,r,i.matrices.length);for(let g=0;g<i.matrices.length;g++)this.setMatrixAt(g,i.matrices[g]);this.citymodel=e,this.isCityObject=!0,this.isCityObjectMesh=!0,this.supportsConditionalFormatting=!0,this.supportsMaterials=!0}setArrayAsAttribute(e){this.geometry.setAttribute("attributevalue",new o.InstancedBufferAttribute(new Int32Array(e),1))}addAttributeByProperty(e){const t=e.getAllValues(),s=e.getUniqueValues();if(s.length<110){const i=[];for(const a of t)i.push(s.indexOf(a));const n=this.geometry.attributes.objectid.array,r=n.map(a=>i[a]);if(r.length!==n.length){console.warn("Wrong size of attributes array.");return}this.setArrayAsAttribute(r)}}getIntersectionVertex(e){return e.face.a}resolveIntersectionInfo(e){const t={},s=this.getIntersectionVertex(e),i=e.instanceId,n=this.geometry.getAttribute("objectid").getX(i);return t.vertexIndex=s,t.objectIndex=n,t.objectId=Object.keys(this.citymodel.CityObjects)[n],t.geometryIndex=this.geometry.getAttribute("geometryid").getX(i),t.boundaryIndex=this.geometry.getAttribute("boundaryid").getX(s),t.objectTypeIndex=this.geometry.getAttribute("type").getX(i),t.surfaceTypeIndex=this.geometry.getAttribute("surfacetype").getX(s),t.lodIndex=this.geometry.getAttribute("lodid").getX(s),t}setTextureTheme(e,t){if(e==="undefined"){this.unsetTextures();return}const i=`tex${e.replace(/[^a-z0-9]/gi,"")}`;if(i in this.geometry.attributes){const n=this.geometry.attributes[i].array,{values:r,indices:a}=n.reduce((l,d,u)=>(l.last!==d&&(l.values.push(d),l.indices.push(u),l.last=d),l),{last:-1,values:[],indices:[]}),y=Array.isArray(this.material)?this.material[this.material.length-1]:this.material,c=t.getMaterials(y);for(const l of c)l!==y&&(l.textureTheme=e);for(let l=0;l<a.length-1;l++)this.geometry.addGroup(a[l],a[l+1]-a[l],r[l]>-1?r[l]:c.length-1);const h=a.length-1;this.geometry.addGroup(a[h],this.geometry.attributes.type.array.length-a[h],r[h]>-1?r[h]:c.length-1),this.material=c}}unsetTextures(){Array.isArray(this.material)&&(this.material=this.material[this.material.length-1]),this.material.textureTheme="undefined"}}class z{constructor(){this.matrix=null,this.onChunkLoad=null,this.onComplete=null,this.chunkSize=2e3,this.loading=!1,this.objectColors=re,this.surfaceColors=X,this.lods=[],this.resetMaterial()}resetMaterial(){this.meshMaterial=new ne(o.ShaderLib.lambert,{objectColors:this.objectColors,surfaceColors:this.surfaceColors}),this.lineMaterial=new ae({color:16777215,linewidth:.001,vertexColors:!1,dashed:!1,objectColors:this.objectColors,surfaceColors:this.surfaceColors}),this.pointsMaterial=new le({size:10,objectColors:this.objectColors,surfaceColors:this.surfaceColors})}setMaterialsColors(e,t){this.meshMaterial.objectColors=e,this.meshMaterial.surfaceColors=t,this.lineMaterial.objectColors=e,this.lineMaterial.surfaceColors=t,this.pointsMaterial.objectColors=e,this.pointsMaterial.surfaceColors=t}parse(e,t){this.loading=!0;const s=new Worker(URL.createObjectURL(new Blob([atob('KGZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIFN0KHcpe3JldHVybiB3JiZ3Ll9fZXNNb2R1bGUmJk9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh3LCJkZWZhdWx0Iik/dy5kZWZhdWx0Ond9dmFyIHN0PXtleHBvcnRzOnt9fSx1dDtmdW5jdGlvbiBqdCgpe3JldHVybiB1dHx8KHV0PTEsKGZ1bmN0aW9uKHcpe3ZhciB0PShmdW5jdGlvbihlKXt2YXIgcz1PYmplY3QucHJvdG90eXBlLG89cy5oYXNPd25Qcm9wZXJ0eSxjPU9iamVjdC5kZWZpbmVQcm9wZXJ0eXx8ZnVuY3Rpb24obixpLGEpe25baV09YS52YWx1ZX0seSxfPXR5cGVvZiBTeW1ib2w9PSJmdW5jdGlvbiI/U3ltYm9sOnt9LGQ9Xy5pdGVyYXRvcnx8IkBAaXRlcmF0b3IiLHA9Xy5hc3luY0l0ZXJhdG9yfHwiQEBhc3luY0l0ZXJhdG9yIix4PV8udG9TdHJpbmdUYWd8fCJAQHRvU3RyaW5nVGFnIjtmdW5jdGlvbiBtKG4saSxhKXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5KG4saSx7dmFsdWU6YSxlbnVtZXJhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMCx3cml0YWJsZTohMH0pLG5baV19dHJ5e20oe30sIiIpfWNhdGNoe209ZnVuY3Rpb24oaSxhLGwpe3JldHVybiBpW2FdPWx9fWZ1bmN0aW9uIHYobixpLGEsbCl7dmFyIGY9aSYmaS5wcm90b3R5cGUgaW5zdGFuY2VvZiBqP2k6aix6PU9iamVjdC5jcmVhdGUoZi5wcm90b3R5cGUpLE09bmV3IHIobHx8W10pO3JldHVybiBjKHosIl9pbnZva2UiLHt2YWx1ZTpldChuLGEsTSl9KSx6fWUud3JhcD12O2Z1bmN0aW9uIGcobixpLGEpe3RyeXtyZXR1cm57dHlwZToibm9ybWFsIixhcmc6bi5jYWxsKGksYSl9fWNhdGNoKGwpe3JldHVybnt0eXBlOiJ0aHJvdyIsYXJnOmx9fX12YXIgYj0ic3VzcGVuZGVkU3RhcnQiLEE9InN1c3BlbmRlZFlpZWxkIixMPSJleGVjdXRpbmciLFA9ImNvbXBsZXRlZCIsRz17fTtmdW5jdGlvbiBqKCl7fWZ1bmN0aW9uIGsoKXt9ZnVuY3Rpb24gRSgpe312YXIgRj17fTttKEYsZCxmdW5jdGlvbigpe3JldHVybiB0aGlzfSk7dmFyIFI9T2JqZWN0LmdldFByb3RvdHlwZU9mLFE9UiYmUihSKHUoW10pKSk7USYmUSE9PXMmJm8uY2FsbChRLGQpJiYoRj1RKTt2YXIgVj1FLnByb3RvdHlwZT1qLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKEYpO2sucHJvdG90eXBlPUUsYyhWLCJjb25zdHJ1Y3RvciIse3ZhbHVlOkUsY29uZmlndXJhYmxlOiEwfSksYyhFLCJjb25zdHJ1Y3RvciIse3ZhbHVlOmssY29uZmlndXJhYmxlOiEwfSksay5kaXNwbGF5TmFtZT1tKEUseCwiR2VuZXJhdG9yRnVuY3Rpb24iKTtmdW5jdGlvbiB0dChuKXtbIm5leHQiLCJ0aHJvdyIsInJldHVybiJdLmZvckVhY2goZnVuY3Rpb24oaSl7bShuLGksZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuX2ludm9rZShpLGEpfSl9KX1lLmlzR2VuZXJhdG9yRnVuY3Rpb249ZnVuY3Rpb24obil7dmFyIGk9dHlwZW9mIG49PSJmdW5jdGlvbiImJm4uY29uc3RydWN0b3I7cmV0dXJuIGk/aT09PWt8fChpLmRpc3BsYXlOYW1lfHxpLm5hbWUpPT09IkdlbmVyYXRvckZ1bmN0aW9uIjohMX0sZS5tYXJrPWZ1bmN0aW9uKG4pe3JldHVybiBPYmplY3Quc2V0UHJvdG90eXBlT2Y/T2JqZWN0LnNldFByb3RvdHlwZU9mKG4sRSk6KG4uX19wcm90b19fPUUsbShuLHgsIkdlbmVyYXRvckZ1bmN0aW9uIikpLG4ucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoViksbn0sZS5hd3JhcD1mdW5jdGlvbihuKXtyZXR1cm57X19hd2FpdDpufX07ZnVuY3Rpb24gWChuLGkpe2Z1bmN0aW9uIGEoeixNLEksUyl7dmFyIEM9ZyhuW3pdLG4sTSk7aWYoQy50eXBlPT09InRocm93IilTKEMuYXJnKTtlbHNle3ZhciBEPUMuYXJnLFQ9RC52YWx1ZTtyZXR1cm4gVCYmdHlwZW9mIFQ9PSJvYmplY3QiJiZvLmNhbGwoVCwiX19hd2FpdCIpP2kucmVzb2x2ZShULl9fYXdhaXQpLnRoZW4oZnVuY3Rpb24oTil7YSgibmV4dCIsTixJLFMpfSxmdW5jdGlvbihOKXthKCJ0aHJvdyIsTixJLFMpfSk6aS5yZXNvbHZlKFQpLnRoZW4oZnVuY3Rpb24oTil7RC52YWx1ZT1OLEkoRCl9LGZ1bmN0aW9uKE4pe3JldHVybiBhKCJ0aHJvdyIsTixJLFMpfSl9fXZhciBsO2Z1bmN0aW9uIGYoeixNKXtmdW5jdGlvbiBJKCl7cmV0dXJuIG5ldyBpKGZ1bmN0aW9uKFMsQyl7YSh6LE0sUyxDKX0pfXJldHVybiBsPWw/bC50aGVuKEksSSk6SSgpfWModGhpcywiX2ludm9rZSIse3ZhbHVlOmZ9KX10dChYLnByb3RvdHlwZSksbShYLnByb3RvdHlwZSxwLGZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9KSxlLkFzeW5jSXRlcmF0b3I9WCxlLmFzeW5jPWZ1bmN0aW9uKG4saSxhLGwsZil7Zj09PXZvaWQgMCYmKGY9UHJvbWlzZSk7dmFyIHo9bmV3IFgodihuLGksYSxsKSxmKTtyZXR1cm4gZS5pc0dlbmVyYXRvckZ1bmN0aW9uKGkpP3o6ei5uZXh0KCkudGhlbihmdW5jdGlvbihNKXtyZXR1cm4gTS5kb25lP00udmFsdWU6ei5uZXh0KCl9KX07ZnVuY3Rpb24gZXQobixpLGEpe3ZhciBsPWI7cmV0dXJuIGZ1bmN0aW9uKHosTSl7aWYobD09PUwpdGhyb3cgbmV3IEVycm9yKCJHZW5lcmF0b3IgaXMgYWxyZWFkeSBydW5uaW5nIik7aWYobD09PVApe2lmKHo9PT0idGhyb3ciKXRocm93IE07cmV0dXJuIGgoKX1mb3IoYS5tZXRob2Q9eixhLmFyZz1NOzspe3ZhciBJPWEuZGVsZWdhdGU7aWYoSSl7dmFyIFM9WShJLGEpO2lmKFMpe2lmKFM9PT1HKWNvbnRpbnVlO3JldHVybiBTfX1pZihhLm1ldGhvZD09PSJuZXh0IilhLnNlbnQ9YS5fc2VudD1hLmFyZztlbHNlIGlmKGEubWV0aG9kPT09InRocm93Iil7aWYobD09PWIpdGhyb3cgbD1QLGEuYXJnO2EuZGlzcGF0Y2hFeGNlcHRpb24oYS5hcmcpfWVsc2UgYS5tZXRob2Q9PT0icmV0dXJuIiYmYS5hYnJ1cHQoInJldHVybiIsYS5hcmcpO2w9TDt2YXIgQz1nKG4saSxhKTtpZihDLnR5cGU9PT0ibm9ybWFsIil7aWYobD1hLmRvbmU/UDpBLEMuYXJnPT09Ryljb250aW51ZTtyZXR1cm57dmFsdWU6Qy5hcmcsZG9uZTphLmRvbmV9fWVsc2UgQy50eXBlPT09InRocm93IiYmKGw9UCxhLm1ldGhvZD0idGhyb3ciLGEuYXJnPUMuYXJnKX19fWZ1bmN0aW9uIFkobixpKXt2YXIgYT1pLm1ldGhvZCxsPW4uaXRlcmF0b3JbYV07aWYobD09PXkpcmV0dXJuIGkuZGVsZWdhdGU9bnVsbCxhPT09InRocm93IiYmbi5pdGVyYXRvci5yZXR1cm4mJihpLm1ldGhvZD0icmV0dXJuIixpLmFyZz15LFkobixpKSxpLm1ldGhvZD09PSJ0aHJvdyIpfHxhIT09InJldHVybiImJihpLm1ldGhvZD0idGhyb3ciLGkuYXJnPW5ldyBUeXBlRXJyb3IoIlRoZSBpdGVyYXRvciBkb2VzIG5vdCBwcm92aWRlIGEgJyIrYSsiJyBtZXRob2QiKSksRzt2YXIgZj1nKGwsbi5pdGVyYXRvcixpLmFyZyk7aWYoZi50eXBlPT09InRocm93IilyZXR1cm4gaS5tZXRob2Q9InRocm93IixpLmFyZz1mLmFyZyxpLmRlbGVnYXRlPW51bGwsRzt2YXIgej1mLmFyZztpZigheilyZXR1cm4gaS5tZXRob2Q9InRocm93IixpLmFyZz1uZXcgVHlwZUVycm9yKCJpdGVyYXRvciByZXN1bHQgaXMgbm90IGFuIG9iamVjdCIpLGkuZGVsZWdhdGU9bnVsbCxHO2lmKHouZG9uZSlpW24ucmVzdWx0TmFtZV09ei52YWx1ZSxpLm5leHQ9bi5uZXh0TG9jLGkubWV0aG9kIT09InJldHVybiImJihpLm1ldGhvZD0ibmV4dCIsaS5hcmc9eSk7ZWxzZSByZXR1cm4gejtyZXR1cm4gaS5kZWxlZ2F0ZT1udWxsLEd9dHQoViksbShWLHgsIkdlbmVyYXRvciIpLG0oVixkLGZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9KSxtKFYsInRvU3RyaW5nIixmdW5jdGlvbigpe3JldHVybiJbb2JqZWN0IEdlbmVyYXRvcl0ifSk7ZnVuY3Rpb24gJChuKXt2YXIgaT17dHJ5TG9jOm5bMF19OzEgaW4gbiYmKGkuY2F0Y2hMb2M9blsxXSksMiBpbiBuJiYoaS5maW5hbGx5TG9jPW5bMl0saS5hZnRlckxvYz1uWzNdKSx0aGlzLnRyeUVudHJpZXMucHVzaChpKX1mdW5jdGlvbiBIKG4pe3ZhciBpPW4uY29tcGxldGlvbnx8e307aS50eXBlPSJub3JtYWwiLGRlbGV0ZSBpLmFyZyxuLmNvbXBsZXRpb249aX1mdW5jdGlvbiByKG4pe3RoaXMudHJ5RW50cmllcz1be3RyeUxvYzoicm9vdCJ9XSxuLmZvckVhY2goJCx0aGlzKSx0aGlzLnJlc2V0KCEwKX1lLmtleXM9ZnVuY3Rpb24obil7dmFyIGk9T2JqZWN0KG4pLGE9W107Zm9yKHZhciBsIGluIGkpYS5wdXNoKGwpO3JldHVybiBhLnJldmVyc2UoKSxmdW5jdGlvbiBmKCl7Zm9yKDthLmxlbmd0aDspe3ZhciB6PWEucG9wKCk7aWYoeiBpbiBpKXJldHVybiBmLnZhbHVlPXosZi5kb25lPSExLGZ9cmV0dXJuIGYuZG9uZT0hMCxmfX07ZnVuY3Rpb24gdShuKXtpZihuIT1udWxsKXt2YXIgaT1uW2RdO2lmKGkpcmV0dXJuIGkuY2FsbChuKTtpZih0eXBlb2Ygbi5uZXh0PT0iZnVuY3Rpb24iKXJldHVybiBuO2lmKCFpc05hTihuLmxlbmd0aCkpe3ZhciBhPS0xLGw9ZnVuY3Rpb24gZigpe2Zvcig7KythPG4ubGVuZ3RoOylpZihvLmNhbGwobixhKSlyZXR1cm4gZi52YWx1ZT1uW2FdLGYuZG9uZT0hMSxmO3JldHVybiBmLnZhbHVlPXksZi5kb25lPSEwLGZ9O3JldHVybiBsLm5leHQ9bH19dGhyb3cgbmV3IFR5cGVFcnJvcih0eXBlb2YgbisiIGlzIG5vdCBpdGVyYWJsZSIpfWUudmFsdWVzPXU7ZnVuY3Rpb24gaCgpe3JldHVybnt2YWx1ZTp5LGRvbmU6ITB9fXJldHVybiByLnByb3RvdHlwZT17Y29uc3RydWN0b3I6cixyZXNldDpmdW5jdGlvbihuKXtpZih0aGlzLnByZXY9MCx0aGlzLm5leHQ9MCx0aGlzLnNlbnQ9dGhpcy5fc2VudD15LHRoaXMuZG9uZT0hMSx0aGlzLmRlbGVnYXRlPW51bGwsdGhpcy5tZXRob2Q9Im5leHQiLHRoaXMuYXJnPXksdGhpcy50cnlFbnRyaWVzLmZvckVhY2goSCksIW4pZm9yKHZhciBpIGluIHRoaXMpaS5jaGFyQXQoMCk9PT0idCImJm8uY2FsbCh0aGlzLGkpJiYhaXNOYU4oK2kuc2xpY2UoMSkpJiYodGhpc1tpXT15KX0sc3RvcDpmdW5jdGlvbigpe3RoaXMuZG9uZT0hMDt2YXIgbj10aGlzLnRyeUVudHJpZXNbMF0saT1uLmNvbXBsZXRpb247aWYoaS50eXBlPT09InRocm93Iil0aHJvdyBpLmFyZztyZXR1cm4gdGhpcy5ydmFsfSxkaXNwYXRjaEV4Y2VwdGlvbjpmdW5jdGlvbihuKXtpZih0aGlzLmRvbmUpdGhyb3cgbjt2YXIgaT10aGlzO2Z1bmN0aW9uIGEoUyxDKXtyZXR1cm4gei50eXBlPSJ0aHJvdyIsei5hcmc9bixpLm5leHQ9UyxDJiYoaS5tZXRob2Q9Im5leHQiLGkuYXJnPXkpLCEhQ31mb3IodmFyIGw9dGhpcy50cnlFbnRyaWVzLmxlbmd0aC0xO2w+PTA7LS1sKXt2YXIgZj10aGlzLnRyeUVudHJpZXNbbF0sej1mLmNvbXBsZXRpb247aWYoZi50cnlMb2M9PT0icm9vdCIpcmV0dXJuIGEoImVuZCIpO2lmKGYudHJ5TG9jPD10aGlzLnByZXYpe3ZhciBNPW8uY2FsbChmLCJjYXRjaExvYyIpLEk9by5jYWxsKGYsImZpbmFsbHlMb2MiKTtpZihNJiZJKXtpZih0aGlzLnByZXY8Zi5jYXRjaExvYylyZXR1cm4gYShmLmNhdGNoTG9jLCEwKTtpZih0aGlzLnByZXY8Zi5maW5hbGx5TG9jKXJldHVybiBhKGYuZmluYWxseUxvYyl9ZWxzZSBpZihNKXtpZih0aGlzLnByZXY8Zi5jYXRjaExvYylyZXR1cm4gYShmLmNhdGNoTG9jLCEwKX1lbHNlIGlmKEkpe2lmKHRoaXMucHJldjxmLmZpbmFsbHlMb2MpcmV0dXJuIGEoZi5maW5hbGx5TG9jKX1lbHNlIHRocm93IG5ldyBFcnJvcigidHJ5IHN0YXRlbWVudCB3aXRob3V0IGNhdGNoIG9yIGZpbmFsbHkiKX19fSxhYnJ1cHQ6ZnVuY3Rpb24obixpKXtmb3IodmFyIGE9dGhpcy50cnlFbnRyaWVzLmxlbmd0aC0xO2E+PTA7LS1hKXt2YXIgbD10aGlzLnRyeUVudHJpZXNbYV07aWYobC50cnlMb2M8PXRoaXMucHJldiYmby5jYWxsKGwsImZpbmFsbHlMb2MiKSYmdGhpcy5wcmV2PGwuZmluYWxseUxvYyl7dmFyIGY9bDticmVha319ZiYmKG49PT0iYnJlYWsifHxuPT09ImNvbnRpbnVlIikmJmYudHJ5TG9jPD1pJiZpPD1mLmZpbmFsbHlMb2MmJihmPW51bGwpO3ZhciB6PWY/Zi5jb21wbGV0aW9uOnt9O3JldHVybiB6LnR5cGU9bix6LmFyZz1pLGY/KHRoaXMubWV0aG9kPSJuZXh0Iix0aGlzLm5leHQ9Zi5maW5hbGx5TG9jLEcpOnRoaXMuY29tcGxldGUoeil9LGNvbXBsZXRlOmZ1bmN0aW9uKG4saSl7aWYobi50eXBlPT09InRocm93Iil0aHJvdyBuLmFyZztyZXR1cm4gbi50eXBlPT09ImJyZWFrInx8bi50eXBlPT09ImNvbnRpbnVlIj90aGlzLm5leHQ9bi5hcmc6bi50eXBlPT09InJldHVybiI/KHRoaXMucnZhbD10aGlzLmFyZz1uLmFyZyx0aGlzLm1ldGhvZD0icmV0dXJuIix0aGlzLm5leHQ9ImVuZCIpOm4udHlwZT09PSJub3JtYWwiJiZpJiYodGhpcy5uZXh0PWkpLEd9LGZpbmlzaDpmdW5jdGlvbihuKXtmb3IodmFyIGk9dGhpcy50cnlFbnRyaWVzLmxlbmd0aC0xO2k+PTA7LS1pKXt2YXIgYT10aGlzLnRyeUVudHJpZXNbaV07aWYoYS5maW5hbGx5TG9jPT09bilyZXR1cm4gdGhpcy5jb21wbGV0ZShhLmNvbXBsZXRpb24sYS5hZnRlckxvYyksSChhKSxHfX0sY2F0Y2g6ZnVuY3Rpb24obil7Zm9yKHZhciBpPXRoaXMudHJ5RW50cmllcy5sZW5ndGgtMTtpPj0wOy0taSl7dmFyIGE9dGhpcy50cnlFbnRyaWVzW2ldO2lmKGEudHJ5TG9jPT09bil7dmFyIGw9YS5jb21wbGV0aW9uO2lmKGwudHlwZT09PSJ0aHJvdyIpe3ZhciBmPWwuYXJnO0goYSl9cmV0dXJuIGZ9fXRocm93IG5ldyBFcnJvcigiaWxsZWdhbCBjYXRjaCBhdHRlbXB0Iil9LGRlbGVnYXRlWWllbGQ6ZnVuY3Rpb24obixpLGEpe3JldHVybiB0aGlzLmRlbGVnYXRlPXtpdGVyYXRvcjp1KG4pLHJlc3VsdE5hbWU6aSxuZXh0TG9jOmF9LHRoaXMubWV0aG9kPT09Im5leHQiJiYodGhpcy5hcmc9eSksR319LGV9KSh3LmV4cG9ydHMpO3RyeXtyZWdlbmVyYXRvclJ1bnRpbWU9dH1jYXRjaHt0eXBlb2YgZ2xvYmFsVGhpcz09Im9iamVjdCI/Z2xvYmFsVGhpcy5yZWdlbmVyYXRvclJ1bnRpbWU9dDpGdW5jdGlvbigiciIsInJlZ2VuZXJhdG9yUnVudGltZSA9IHIiKSh0KX19KShzdCkpLHN0LmV4cG9ydHN9anQoKTtjb25zdCBjdD0wLGx0PTEsZnQ9MjtjbGFzcyBxe2NvbnN0cnVjdG9yKHQpe3RoaXMuZ2VvbWV0cnlUeXBlPXQsdGhpcy52ZXJ0ZXhJZHM9W10sdGhpcy5vYmplY3RJZHM9W10sdGhpcy5vYmplY3RUeXBlcz1bXSx0aGlzLnNlbWFudGljU3VyZmFjZXM9W10sdGhpcy5nZW9tZXRyeUlkcz1bXSx0aGlzLmJvdW5kYXJ5SWRzPVtdLHRoaXMubG9kSWRzPVtdLHRoaXMubWF0ZXJpYWxzPXt9LHRoaXMudGV4dHVyZXM9e319YXBwZW5kTWF0ZXJpYWwodCxlKXt0IGluIHRoaXMubWF0ZXJpYWxzfHwodGhpcy5tYXRlcmlhbHNbdF09W10pO2NvbnN0IHM9dGhpcy5tYXRlcmlhbHNbdF07Zm9yKGxldCBvPXMubGVuZ3RoO288dGhpcy5jb3VudCgpLTE7bysrKXMucHVzaCgtMSk7dGhpcy5tYXRlcmlhbHNbdF0ucHVzaChlKX1hcHBlbmRUZXh0dXJlKHQsZSl7dCBpbiB0aGlzLnRleHR1cmVzfHwodGhpcy50ZXh0dXJlc1t0XT17aW5kZXg6W10sdXZzOltdfSk7Y29uc3Qgcz10aGlzLnRleHR1cmVzW3RdO2ZvcihsZXQgbz1zLmluZGV4Lmxlbmd0aDtvPHRoaXMuY291bnQoKS0xO28rKylzLmluZGV4LnB1c2goLTEpLHMudXZzLnB1c2goWzAsMF0pO3MuaW5kZXgucHVzaChlLmluZGV4KSxzLnV2cy5wdXNoKGUudXZzKX1hZGRWZXJ0ZXgodCxlLHMsbyxjLHksXyxkLHApe2lmKHRoaXMudmVydGV4SWRzLnB1c2godCksdGhpcy5vYmplY3RJZHMucHVzaChlKSx0aGlzLm9iamVjdFR5cGVzLnB1c2gocyksdGhpcy5zZW1hbnRpY1N1cmZhY2VzLnB1c2gobyksdGhpcy5nZW9tZXRyeUlkcy5wdXNoKGMpLHRoaXMuYm91bmRhcnlJZHMucHVzaCh5KSx0aGlzLmxvZElkcy5wdXNoKF8pLGQpe2NvbnN0IHg9dGhpcztPYmplY3QuZW50cmllcyhkKS5mb3JFYWNoKG09Pntjb25zdFt2LGddPW07eC5hcHBlbmRNYXRlcmlhbCh2LGcpfSl9aWYocCl7Y29uc3QgeD10aGlzO09iamVjdC5lbnRyaWVzKHApLmZvckVhY2gobT0+e2NvbnN0W3YsZ109bTt4LmFwcGVuZFRleHR1cmUodixnKX0pfX1jb21wbGV0ZU1hdGVyaWFscygpe2Zvcihjb25zdCB0IGluIHRoaXMubWF0ZXJpYWxzKXtjb25zdCBlPXRoaXMubWF0ZXJpYWxzW3RdO2ZvcihsZXQgcz1lLmxlbmd0aDtzPHRoaXMuY291bnQoKTtzKyspZS5wdXNoKC0xKX19Y29tcGxldGVUZXh0dXJlcygpe2Zvcihjb25zdCB0IGluIHRoaXMudGV4dHVyZXMpe2NvbnN0IGU9dGhpcy50ZXh0dXJlc1t0XTtmb3IobGV0IHM9ZS5pbmRleC5sZW5ndGg7czx0aGlzLmNvdW50KCk7cysrKWUuaW5kZXgucHVzaCgtMSksZS51dnMucHVzaChbMCwwXSl9fWNvdW50KCl7cmV0dXJuIHRoaXMudmVydGV4SWRzLmxlbmd0aH1nZXRWZXJ0aWNlcyh0KXtsZXQgZT1bXTtmb3IoY29uc3QgcyBvZiB0aGlzLnZlcnRleElkcyl7Y29uc3Qgbz10W3NdO2UucHVzaCguLi5vKX1yZXR1cm4gZX10b09iamVjdCgpe3JldHVybiB0aGlzLmNvbXBsZXRlTWF0ZXJpYWxzKCksdGhpcy5jb21wbGV0ZVRleHR1cmVzKCkse2dlb21ldHJ5VHlwZTp0aGlzLmdlb21ldHJ5VHlwZSxvYmplY3RJZHM6dGhpcy5vYmplY3RJZHMsb2JqZWN0VHlwZTp0aGlzLm9iamVjdFR5cGVzLHNlbWFudGljU3VyZmFjZXM6dGhpcy5zZW1hbnRpY1N1cmZhY2VzLGdlb21ldHJ5SWRzOnRoaXMuZ2VvbWV0cnlJZHMsYm91bmRhcnlJZHM6dGhpcy5ib3VuZGFyeUlkcyxsb2RJZHM6dGhpcy5sb2RJZHMsbWF0ZXJpYWxzOnRoaXMubWF0ZXJpYWxzLHRleHR1cmVzOnRoaXMudGV4dHVyZXN9fXNldE9iamVjdElkKHQpe2ZvcihsZXQgZT0wO2U8dGhpcy5vYmplY3RJZHMubGVuZ3RoO2UrKyl0aGlzLm9iamVjdElkc1tlXT10fXNldE9iamVjdFR5cGUodCl7Zm9yKGxldCBlPTA7ZTx0aGlzLm9iamVjdFR5cGVzLmxlbmd0aDtlKyspdGhpcy5vYmplY3RUeXBlc1tlXT10fXNldEdlb21ldHJ5SWR4KHQpe2ZvcihsZXQgZT0wO2U8dGhpcy5nZW9tZXRyeUlkcy5sZW5ndGg7ZSsrKXRoaXMuZ2VvbWV0cnlJZHNbZV09dH1tZXJnZSh0KXt0Lmdlb21ldHJ5VHlwZSE9dGhpcy5nZW9tZXRyeVR5cGUmJmNvbnNvbGUud2FybigiTWVyZ2luZyBkaWZmZXJlbnQgdHlwZXMgb2YgZ2VvbWV0cnkgZGF0YSEiKSx0aGlzLnZlcnRleElkcy5jb25jYXQodGhpcy5vdGhlckdlb21EYXRhLnZlcnRleElkKSx0aGlzLm9iamVjdElkcy5jb25jYXQodGhpcy5vdGhlckdlb21EYXRhLm9iamVjdElkKSx0aGlzLm9iamVjdFR5cGVzLmNvbmNhdCh0aGlzLm90aGVyR2VvbURhdGEub2JqZWN0VHlwZSksdGhpcy5zZW1hbnRpY1N1cmZhY2VzLmNvbmNhdCh0aGlzLm90aGVyR2VvbURhdGEuc3VyZmFjZVR5cGUpLHRoaXMuZ2VvbWV0cnlJZHMuY29uY2F0KHRoaXMub3RoZXJHZW9tRGF0YS5nZW9tZXRyeUlkeCksdGhpcy5ib3VuZGFyeUlkcy5jb25jYXQodGhpcy5vdGhlckdlb21EYXRhLmJvdW5kYXJ5SWR4KSx0aGlzLmxvZElkcy5jb25jYXQodGhpcy5vdGhlckdlb21EYXRhLmxvZElkeCl9fWNvbnN0IEl0PXtHcm91bmRTdXJmYWNlOjEwMDY2MzI5LFdhbGxTdXJmYWNlOjE2Nzc3MjE1LFJvb2ZTdXJmYWNlOjE2NzExNjgwLFRyYWZmaWNBcmVhOjcyMzcyMzAsQXV4aWxpYXJ5VHJhZmZpY0FyZWE6MjkxNjg2NCxXaW5kb3c6MjMwMzksRG9vcjo2NTUzNjAwfTtjbGFzcyBydHtjb25zdHJ1Y3Rvcih0LGUscyl7dGhpcy5qc29uPXQsdGhpcy5vYmplY3RJZHM9ZSx0aGlzLm9iamVjdENvbG9ycz1zLHRoaXMuc3VyZmFjZUNvbG9ycz1JdCx0aGlzLmxvZHM9W119Y2xlYW4oKXt9cGFyc2VHZW9tZXRyeSh0LGUscyl7fWdldE9iamVjdElkeCh0KXtyZXR1cm4gdGhpcy5vYmplY3RJZHMuaW5kZXhPZih0KX1nZXRPYmplY3RUeXBlSWR4KHQpe2xldCBlPU9iamVjdC5rZXlzKHRoaXMub2JqZWN0Q29sb3JzKS5pbmRleE9mKHQpO3JldHVybiBlPDAmJihlPU9iamVjdC5rZXlzKHRoaXMub2JqZWN0Q29sb3JzKS5sZW5ndGgsdGhpcy5vYmplY3RDb2xvcnNbdF09TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpKjE2Nzc3MjE1KSksZX1nZXRTdXJmYWNlVHlwZUlkeCh0LGUscyl7bGV0IG89LTE7aWYoZS5sZW5ndGg+MCl7Y29uc3QgYz1zW2VbdF1dO2MmJihvPU9iamVjdC5rZXlzKHRoaXMuc3VyZmFjZUNvbG9ycykuaW5kZXhPZihjLnR5cGUpLG88MCYmKG89T2JqZWN0LmtleXModGhpcy5zdXJmYWNlQ29sb3JzKS5sZW5ndGgsdGhpcy5zdXJmYWNlQ29sb3JzW2MudHlwZV09TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpKjE2Nzc3MjE1KSkpfXJldHVybiBvfWdldFN1cmZhY2VNYXRlcmlhbHModCxlKXtjb25zdCBzPU9iamVjdC5lbnRyaWVzKGUpLm1hcChvPT57Y29uc3RbYyx5XT1vO3JldHVybiB5LnZhbHVlcz9bYyx5LnZhbHVlc1t0XV06eS52YWx1ZSE9PXZvaWQgMD9bYyx5LnZhbHVlXTpbYywtMV19KTtyZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKHMpfWdldFRleHR1cmVEYXRhKHQsZSxzLG8pe2lmKHRoaXMuanNvbi5hcHBlYXJhbmNlJiZ0aGlzLmpzb24uYXBwZWFyYW5jZVsidmVydGljZXMtdGV4dHVyZSJdKXtjb25zdCBjPXRoaXMuanNvbi5hcHBlYXJhbmNlWyJ2ZXJ0aWNlcy10ZXh0dXJlIl0seT1PYmplY3QuZW50cmllcyhvKS5tYXAoXz0+e2NvbnN0W2QscF09XztpZihwLnZhbHVlcyl7Y29uc3QgeD1zLmZpbHRlcihiPT5iPD1lKSxtPXgubGVuZ3RoLHY9bT9lLXhbeC5sZW5ndGgtMV06ZSxnPXAudmFsdWVzW3RdO2lmKGdbMF1bMF0hPT1udWxsKXtjb25zdCBiPWNbZ1ttXVt2KzFdXTtyZXR1cm5bZCx7aW5kZXg6Z1swXVswXSx1dnM6Yn1dfXJldHVybltkLHtpbmRleDotMSx1dnM6WzAsMF19XX1lbHNlIHJldHVybltkLHtpbmRleDotMSx1dnM6WzAsMF19XX0pO3JldHVybiBPYmplY3QuZnJvbUVudHJpZXMoeSl9fWdldExvZEluZGV4KHQpe2lmKHQ9PT12b2lkIDApcmV0dXJuLTE7Y29uc3QgZT10aGlzLmxvZHMuaW5kZXhPZih0KTtpZihlPDApe2NvbnN0IHM9dGhpcy5sb2RzLmxlbmd0aDtyZXR1cm4gdGhpcy5sb2RzLnB1c2godCksc31yZXR1cm4gZX19Y2xhc3Mga3QgZXh0ZW5kcyBydHtjb25zdHJ1Y3Rvcih0LGUscyl7c3VwZXIodCxlLHMpLHRoaXMuZ2VvbURhdGE9bmV3IHEobHQpfWNsZWFuKCl7dGhpcy5nZW9tRGF0YT1uZXcgcShsdCl9aGFuZGxlcyh0KXtyZXR1cm4gdC50eXBlPT0iTXVsdGlMaW5lU3RyaW5nIn1wYXJzZUdlb21ldHJ5KHQsZSxzKXtjb25zdCBvPXQuc2VtYW50aWNzP3Quc2VtYW50aWNzLnN1cmZhY2VzOltdO2lmKHQudHlwZT09Ik11bHRpTGluZVN0cmluZyIpe2NvbnN0IGM9dGhpcy5qc29uLkNpdHlPYmplY3RzW2VdLHk9dGhpcy5nZXRPYmplY3RJZHgoZSksXz10aGlzLmdldE9iamVjdFR5cGVJZHgoYy50eXBlKSxkPXRoaXMuZ2V0TG9kSW5kZXgoYy5nZW9tZXRyeVtzXS5sb2QpLHA9dC5ib3VuZGFyaWVzO2ZvcihsZXQgeD0wO3g8cC5sZW5ndGg7eCsrKWlmKHBbeF0ubGVuZ3RoPjEpe2NvbnN0IG09dC5zZW1hbnRpY3M/dC5zZW1hbnRpY3MudmFsdWVzOltdLHY9dGhpcy5nZXRTdXJmYWNlVHlwZUlkeCh4LG0sbyksZz1wW3hdO2ZvcihsZXQgYj0wO2I8cFt4XS5sZW5ndGgtMTtiKyspdGhpcy5nZW9tRGF0YS5hZGRWZXJ0ZXgoZ1tiXSx5LF8sdixzLHgsZCksdGhpcy5nZW9tRGF0YS5hZGRWZXJ0ZXgoZ1tiKzFdLHksXyx2LHMseCxkKX19fX1jbGFzcyBUdCBleHRlbmRzIHJ0e2NvbnN0cnVjdG9yKHQsZSxzKXtzdXBlcih0LGUscyksdGhpcy5nZW9tRGF0YT1uZXcgcShjdCl9Y2xlYW4oKXt0aGlzLmdlb21EYXRhPW5ldyBxKGN0KX1oYW5kbGVzKHQpe3JldHVybiB0LnR5cGU9PSJNdWx0aVBvaW50In1wYXJzZUdlb21ldHJ5KHQsZSxzKXtjb25zdCBvPXQuc2VtYW50aWNzP3Quc2VtYW50aWNzLnN1cmZhY2VzOltdO2lmKHQudHlwZT09Ik11bHRpUG9pbnQiKXtjb25zdCBjPXRoaXMuanNvbi5DaXR5T2JqZWN0c1tlXSx5PXRoaXMuZ2V0T2JqZWN0SWR4KGUpLF89dGhpcy5nZXRPYmplY3RUeXBlSWR4KGMudHlwZSksZD10aGlzLmdldExvZEluZGV4KGMuZ2VvbWV0cnlbc10ubG9kKSxwPXQuYm91bmRhcmllcztmb3IobGV0IHg9MDt4PHAubGVuZ3RoO3grKyl7Y29uc3QgbT10LnNlbWFudGljcz90LnNlbWFudGljcy52YWx1ZXM6W10sdj10aGlzLmdldFN1cmZhY2VUeXBlSWR4KHgsbSxvKTt0aGlzLmdlb21EYXRhLmFkZFZlcnRleChwW3hdLHksXyx2LHMseCxkKX19fX0vKioKICogQGxpY2Vuc2UKICogQ29weXJpZ2h0IDIwMTAtMjAyNCBUaHJlZS5qcyBBdXRob3JzCiAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVQKICovY29uc3QgeHQ9IjE3MCIsRXQ9IiIsSj0ic3JnYiIseXQ9InNyZ2ItbGluZWFyIixwdD0ibGluZWFyIixpdD0ic3JnYiI7ZnVuY3Rpb24gbXQodyx0LGUpe3JldHVybiBNYXRoLm1heCh0LE1hdGgubWluKGUsdykpfWNsYXNzIFd7Y29uc3RydWN0b3IodCxlLHMsbyxjLHksXyxkLHApe1cucHJvdG90eXBlLmlzTWF0cml4Mz0hMCx0aGlzLmVsZW1lbnRzPVsxLDAsMCwwLDEsMCwwLDAsMV0sdCE9PXZvaWQgMCYmdGhpcy5zZXQodCxlLHMsbyxjLHksXyxkLHApfXNldCh0LGUscyxvLGMseSxfLGQscCl7Y29uc3QgeD10aGlzLmVsZW1lbnRzO3JldHVybiB4WzBdPXQseFsxXT1vLHhbMl09Xyx4WzNdPWUseFs0XT1jLHhbNV09ZCx4WzZdPXMseFs3XT15LHhbOF09cCx0aGlzfWlkZW50aXR5KCl7cmV0dXJuIHRoaXMuc2V0KDEsMCwwLDAsMSwwLDAsMCwxKSx0aGlzfWNvcHkodCl7Y29uc3QgZT10aGlzLmVsZW1lbnRzLHM9dC5lbGVtZW50cztyZXR1cm4gZVswXT1zWzBdLGVbMV09c1sxXSxlWzJdPXNbMl0sZVszXT1zWzNdLGVbNF09c1s0XSxlWzVdPXNbNV0sZVs2XT1zWzZdLGVbN109c1s3XSxlWzhdPXNbOF0sdGhpc31leHRyYWN0QmFzaXModCxlLHMpe3JldHVybiB0LnNldEZyb21NYXRyaXgzQ29sdW1uKHRoaXMsMCksZS5zZXRGcm9tTWF0cml4M0NvbHVtbih0aGlzLDEpLHMuc2V0RnJvbU1hdHJpeDNDb2x1bW4odGhpcywyKSx0aGlzfXNldEZyb21NYXRyaXg0KHQpe2NvbnN0IGU9dC5lbGVtZW50cztyZXR1cm4gdGhpcy5zZXQoZVswXSxlWzRdLGVbOF0sZVsxXSxlWzVdLGVbOV0sZVsyXSxlWzZdLGVbMTBdKSx0aGlzfW11bHRpcGx5KHQpe3JldHVybiB0aGlzLm11bHRpcGx5TWF0cmljZXModGhpcyx0KX1wcmVtdWx0aXBseSh0KXtyZXR1cm4gdGhpcy5tdWx0aXBseU1hdHJpY2VzKHQsdGhpcyl9bXVsdGlwbHlNYXRyaWNlcyh0LGUpe2NvbnN0IHM9dC5lbGVtZW50cyxvPWUuZWxlbWVudHMsYz10aGlzLmVsZW1lbnRzLHk9c1swXSxfPXNbM10sZD1zWzZdLHA9c1sxXSx4PXNbNF0sbT1zWzddLHY9c1syXSxnPXNbNV0sYj1zWzhdLEE9b1swXSxMPW9bM10sUD1vWzZdLEc9b1sxXSxqPW9bNF0saz1vWzddLEU9b1syXSxGPW9bNV0sUj1vWzhdO3JldHVybiBjWzBdPXkqQStfKkcrZCpFLGNbM109eSpMK18qaitkKkYsY1s2XT15KlArXyprK2QqUixjWzFdPXAqQSt4KkcrbSpFLGNbNF09cCpMK3gqaittKkYsY1s3XT1wKlAreCprK20qUixjWzJdPXYqQStnKkcrYipFLGNbNV09dipMK2cqaitiKkYsY1s4XT12KlArZyprK2IqUix0aGlzfW11bHRpcGx5U2NhbGFyKHQpe2NvbnN0IGU9dGhpcy5lbGVtZW50cztyZXR1cm4gZVswXSo9dCxlWzNdKj10LGVbNl0qPXQsZVsxXSo9dCxlWzRdKj10LGVbN10qPXQsZVsyXSo9dCxlWzVdKj10LGVbOF0qPXQsdGhpc31kZXRlcm1pbmFudCgpe2NvbnN0IHQ9dGhpcy5lbGVtZW50cyxlPXRbMF0scz10WzFdLG89dFsyXSxjPXRbM10seT10WzRdLF89dFs1XSxkPXRbNl0scD10WzddLHg9dFs4XTtyZXR1cm4gZSp5KngtZSpfKnAtcypjKngrcypfKmQrbypjKnAtbyp5KmR9aW52ZXJ0KCl7Y29uc3QgdD10aGlzLmVsZW1lbnRzLGU9dFswXSxzPXRbMV0sbz10WzJdLGM9dFszXSx5PXRbNF0sXz10WzVdLGQ9dFs2XSxwPXRbN10seD10WzhdLG09eCp5LV8qcCx2PV8qZC14KmMsZz1wKmMteSpkLGI9ZSptK3MqditvKmc7aWYoYj09PTApcmV0dXJuIHRoaXMuc2V0KDAsMCwwLDAsMCwwLDAsMCwwKTtjb25zdCBBPTEvYjtyZXR1cm4gdFswXT1tKkEsdFsxXT0obypwLXgqcykqQSx0WzJdPShfKnMtbyp5KSpBLHRbM109dipBLHRbNF09KHgqZS1vKmQpKkEsdFs1XT0obypjLV8qZSkqQSx0WzZdPWcqQSx0WzddPShzKmQtcCplKSpBLHRbOF09KHkqZS1zKmMpKkEsdGhpc310cmFuc3Bvc2UoKXtsZXQgdDtjb25zdCBlPXRoaXMuZWxlbWVudHM7cmV0dXJuIHQ9ZVsxXSxlWzFdPWVbM10sZVszXT10LHQ9ZVsyXSxlWzJdPWVbNl0sZVs2XT10LHQ9ZVs1XSxlWzVdPWVbN10sZVs3XT10LHRoaXN9Z2V0Tm9ybWFsTWF0cml4KHQpe3JldHVybiB0aGlzLnNldEZyb21NYXRyaXg0KHQpLmludmVydCgpLnRyYW5zcG9zZSgpfXRyYW5zcG9zZUludG9BcnJheSh0KXtjb25zdCBlPXRoaXMuZWxlbWVudHM7cmV0dXJuIHRbMF09ZVswXSx0WzFdPWVbM10sdFsyXT1lWzZdLHRbM109ZVsxXSx0WzRdPWVbNF0sdFs1XT1lWzddLHRbNl09ZVsyXSx0WzddPWVbNV0sdFs4XT1lWzhdLHRoaXN9c2V0VXZUcmFuc2Zvcm