UNPKG

hacker-news-reel

Version:

A lightweight, typed client for the Hacker News API with validation using Zod

4 lines (3 loc) 103 kB
var XG=Object.create;var{getPrototypeOf:YG,defineProperty:w,getOwnPropertyNames:a,getOwnPropertyDescriptor:jG}=Object,n=Object.prototype.hasOwnProperty;var i=(G,J,V)=>{V=G!=null?XG(YG(G)):{};let Q=J||!G||!G.__esModule?w(V,"default",{value:G,enumerable:!0}):V;for(let Z of a(G))if(!n.call(Q,Z))w(Q,Z,{get:()=>G[Z],enumerable:!0});return Q},c=new WeakMap,WG=(G)=>{var J=c.get(G),V;if(J)return J;if(J=w({},"__esModule",{value:!0}),G&&typeof G==="object"||typeof G==="function")a(G).map((Q)=>!n.call(J,Q)&&w(J,Q,{get:()=>G[Q],enumerable:!(V=jG(G,Q))||V.enumerable}));return c.set(G,J),J};var PG=(G,J)=>{for(var V in J)w(G,V,{get:J[V],enumerable:!0,configurable:!0,set:(Q)=>J[V]=()=>Q})};var dG={};PG(dG,{searchStories:()=>zG,invalidateUserCache:()=>SG,invalidateSearchCache:()=>yG,invalidateListCaches:()=>wG,invalidateItemCache:()=>FG,getUser:()=>vG,getUpdates:()=>AG,getTopStories:()=>HG,getShowStories:()=>MG,getNewStories:()=>NG,getMaxItemId:()=>xG,getJobStories:()=>LG,getItems:()=>qG,getItemWithComments:()=>TG,getItem:()=>OG,getFrontPageStories:()=>fG,getBestStories:()=>RG,getAskStories:()=>UG,createSearchClient:()=>QG,createClient:()=>e,clearSearchCache:()=>uG,clearAllCaches:()=>IG,RateLimitError:()=>S,HooksManager:()=>F,HackerNewsUsernameSchema:()=>f,HackerNewsUserSchema:()=>u,HackerNewsUpdatesSchema:()=>d,HackerNewsItemTypeSchema:()=>s,HackerNewsItemSchema:()=>y,HackerNewsIdSchema:()=>b,HackerNewsIdListSchema:()=>I});module.exports=WG(dG);var p=i(require("bottleneck"));class R{cache=new Map;options;fetchPromises=new Map;constructor(G={}){this.options={maxAge:60000,staleWhileRevalidate:300000,maxEntries:1000,...G}}evictLRUIfNeeded(){let{maxEntries:G}=this.options;if(!G||this.cache.size<=G)return;let J=this.cache.size-G;Array.from(this.cache.entries()).map(([Q,Z])=>({key:Q,lastAccessed:Z.lastAccessed!==void 0?Z.lastAccessed:Z.timestamp})).sort((Q,Z)=>Q.lastAccessed-Z.lastAccessed).slice(0,J).forEach((Q)=>{this.cache.delete(Q.key)})}async get(G,J){let V=Date.now(),Q=this.cache.get(G);if(Q&&V-Q.timestamp<this.options.maxAge)return this.cache.set(G,{...Q,lastAccessed:V}),Q.data;if(Q&&V-Q.timestamp<this.options.staleWhileRevalidate)return this.refreshInBackground(G,J),this.cache.set(G,{...Q,lastAccessed:V}),Q.data;if(this.fetchPromises.has(G)){let Z=this.fetchPromises.get(G);if(Z)return Z}return this.fetchAndCache(G,J)}async refresh(G,J){return this.fetchAndCache(G,J)}invalidate(G){this.cache.delete(G),this.fetchPromises.delete(G)}clear(){this.cache.clear(),this.fetchPromises.clear()}has(G){return this.cache.has(G)}refreshInBackground(G,J){this.fetchAndCache(G,J).catch((V)=>{console.error(`Background cache refresh failed for key "${G}":`,V),this.fetchPromises.delete(G)})}async fetchAndCache(G,J){let V=(async()=>{try{let Q=await J(),Z=Date.now();return this.cache.set(G,{data:Q,timestamp:Z,lastAccessed:Z}),this.evictLRUIfNeeded(),Q}finally{this.fetchPromises.delete(G)}})();return this.fetchPromises.set(G,V),V}}class F{beforeFetchHooks=[];afterFetchHooks=[];onErrorHooks=[];register(G){if(G.beforeFetch)this.beforeFetchHooks.push(G.beforeFetch);if(G.afterFetch)this.afterFetchHooks.push(G.afterFetch);if(G.onError)this.onErrorHooks.push(G.onError)}clear(){this.beforeFetchHooks=[],this.afterFetchHooks=[],this.onErrorHooks=[]}async runBeforeFetchHooks(G,J){let V={url:G,options:J};for(let Q of this.beforeFetchHooks)V=Q(V.url,V.options);return V}async runAfterFetchHooks(G){let J=G;for(let V of this.afterFetchHooks)J=await V(J);return J}async runOnErrorHooks(G){let J=G;for(let V of this.onErrorHooks)try{let Q=await V(J);if(Q instanceof Error)J=Q}catch(Q){if(Q instanceof Error)J=Q}return J}}var j=require("zod"),b=j.z.number({required_error:"Item ID is required",invalid_type_error:"Item ID must be a number"}).int({message:"Item ID must be an integer"}).nonnegative({message:"Item ID must be a non-negative number"}),f=j.z.string({required_error:"Username is required",invalid_type_error:"Username must be a string"}).min(1,{message:"Username cannot be empty"}),I=j.z.array(b,{required_error:"ID list is required",invalid_type_error:"ID list must be an array of item IDs"}),s=j.z.enum(["job","story","comment","poll","pollopt"],{required_error:"Item type is required",invalid_type_error:"Invalid item type. Must be one of: job, story, comment, poll, or pollopt"}),y=j.z.object({id:j.z.number({required_error:"Item ID is required",invalid_type_error:"Item ID must be a number"}),deleted:j.z.boolean({invalid_type_error:"Deleted flag must be a boolean"}).optional(),type:s.optional(),by:j.z.string({invalid_type_error:"Author username must be a string"}).optional(),time:j.z.number({invalid_type_error:"Creation time must be a number (Unix timestamp)"}).optional(),text:j.z.string({invalid_type_error:"Text content must be a string"}).optional(),dead:j.z.boolean({invalid_type_error:"Dead flag must be a boolean"}).optional(),parent:j.z.number({invalid_type_error:"Parent ID must be a number"}).optional(),poll:j.z.number({invalid_type_error:"Poll ID must be a number"}).optional(),kids:j.z.array(j.z.number({invalid_type_error:"Comment ID must be a number"}),{invalid_type_error:"Kids must be an array of comment IDs"}).optional(),url:j.z.string({invalid_type_error:"URL must be a string"}).optional(),score:j.z.number({invalid_type_error:"Score must be a number"}).optional(),title:j.z.string({invalid_type_error:"Title must be a string"}).optional(),parts:j.z.array(j.z.number({invalid_type_error:"Poll option ID must be a number"}),{invalid_type_error:"Parts must be an array of poll option IDs"}).optional(),descendants:j.z.number({invalid_type_error:"Descendants count must be a number"}).optional()},{required_error:"Item object is required",invalid_type_error:"Item must be an object"}),u=j.z.object({id:f,created:j.z.number({required_error:"User creation date is required",invalid_type_error:"User creation date must be a number (Unix timestamp)"}),karma:j.z.number({required_error:"User karma is required",invalid_type_error:"User karma must be a number"}),about:j.z.string({invalid_type_error:"User about text must be a string"}).optional(),submitted:I.optional()},{required_error:"User object is required",invalid_type_error:"User must be an object"}),d=j.z.object({items:I.describe("List of recently changed items"),profiles:j.z.array(f,{required_error:"Profiles list is required",invalid_type_error:"Profiles must be an array of usernames"}).describe("List of recently changed user profiles")},{required_error:"Updates object is required",invalid_type_error:"Updates must be an object with 'items' and 'profiles' fields"});class S extends Error{status;response;retryAfterSeconds;constructor(G,J){super(G);this.name="RateLimitError",this.status=J.status,this.response=J;let V=J.headers.get("Retry-After");if(V)this.retryAfterSeconds=parseInt(V,10)}}var KG={maxRetries:3,initialBackoff:300,maxBackoff:1e4,jitter:0.2,retryableStatusCodes:[429,500,502,503,504],retryNetworkErrors:!0,backoffFactor:2},DG=(G)=>{return G instanceof TypeError&&(G.message.includes("Failed to fetch")||G.message.includes("Network request failed"))},BG=(G,{initialBackoff:J,backoffFactor:V,maxBackoff:Q,jitter:Z})=>{let D=J*Math.pow(V,G),x=1-Z+Math.random()*(2*Z);return D=D*x,Math.min(D,Q)},o=(G)=>{return new Promise((J)=>setTimeout(J,G))},g=async(G,J,V)=>{if(J?.signal?.aborted)throw new DOMException("The operation was aborted.","AbortError");if(V===!1)return fetch(G,J);let Q={...KG,...V},{maxRetries:Z,retryableStatusCodes:D,retryNetworkErrors:x}=Q,T=!1,U=()=>{T=!0};if(J?.signal)J.signal.addEventListener("abort",U);let M;for(let _=0;_<=Z;_++)try{if(T||J?.signal?.aborted)throw new DOMException("The operation was aborted.","AbortError");if(_>0){let O=BG(_-1,Q);if(await o(O),T||J?.signal?.aborted)throw new DOMException("The operation was aborted.","AbortError")}let $=await fetch(G,J);if($.ok)return $;if(!D.includes($.status))throw new Error(`Request failed with status ${$.status}: ${$.statusText}`);if(_>=Z&&$.status===429)throw new S(`Rate limit exceeded with status code ${$.status}. Check retryAfterSeconds for wait time.`,$);if(_<Z){let O=`Received status code ${$.status}, retrying (${_+1}/${Z})`;console.warn(O),M=new Error(O);let B=$.headers.get("Retry-After");if(B){let v=parseInt(B,10)*1000;if(!isNaN(v)&&v>0){if(T||J?.signal?.aborted)throw new DOMException("The operation was aborted.","AbortError");if(await o(v),T||J?.signal?.aborted)throw new DOMException("The operation was aborted.","AbortError");continue}}}else throw new Error(`Request failed with status ${$.status} after ${Z} retries`)}catch($){if(M=$,$ instanceof DOMException&&$.name==="AbortError"){if(J?.signal)J.signal.removeEventListener("abort",U);throw $}if(!x||!DG($))throw $;if(_<Z)console.warn(`Network error, retrying (${_+1}/${Z})`,$);else throw $}try{throw M}finally{if(J?.signal)J.signal.removeEventListener("abort",U)}};var C="https://hacker-news.firebaseio.com/",k=new R({maxAge:300000,staleWhileRevalidate:3600000,maxEntries:2000}),m=new R({maxAge:30000,staleWhileRevalidate:120000,maxEntries:20}),l=new R({maxAge:300000,staleWhileRevalidate:1800000,maxEntries:500}),r=new R({maxAge:30000,staleWhileRevalidate:60000,maxEntries:5}),t=new R({maxAge:30000,staleWhileRevalidate:60000,maxEntries:1}),e=(G={})=>{let J=G.fetch||fetch,V={maxConcurrent:5,strategy:p.default.strategy.BLOCK},Q=new p.default(G.limiter===void 0||G.limiter===null?V:G.limiter===!1?{maxConcurrent:1/0}:{...V,...G.limiter}),Z=new F;if(G.hooks)Z.register(G.hooks);let D=async(X,W)=>{let P=G.signal?{...W,signal:W?.signal||G.signal}:W;try{let{url:Y,options:q}=await Z.runBeforeFetchHooks(X,P),A;if(G.fetch&&G.fetch!==globalThis.fetch)A=await J(Y,q);else A=await g(Y,q,G.retry);return await Z.runAfterFetchHooks(A)}catch(Y){throw await Z.runOnErrorHooks(Y instanceof Error?Y:new Error(String(Y)))}},x=(X)=>async()=>{let W=`list:${X}`;return m.get(W,async()=>{let P=new URL(X,C),Y=await D(P);if(!Y.ok)throw new Error(`HN API error ${Y.status}: Failed to fetch list from ${X}`);let q=await Y.json();return I.parse(q)})},T=async(X)=>{let W=`item:${X}`;return k.get(W,async()=>{let P=new URL(`v0/item/${X}.json`,C),Y=await D(P);if(!Y.ok)throw new Error(`HN API error ${Y.status}: Failed to fetch item ${X}`);let q=await Y.json();return y.parse(q)})},U=async(X)=>{let W=Q,P=X.map((Y)=>{return W.schedule(()=>T(Y))});return Promise.all(P)},M=async(X)=>{let W=`user:${X}`;return l.get(W,async()=>{let P=new URL(`v0/user/${X}.json`,C),Y=await D(P);if(!Y.ok)throw new Error(`HN API error ${Y.status}: Failed to fetch user ${X}`);let q=await Y.json();return u.parse(q)})},_=async()=>{return t.get("maxitem",async()=>{let W=new URL("v0/maxitem.json",C),P=await D(W);if(!P.ok)throw new Error(`HN API error ${P.status}: Failed to fetch max item ID`);let Y=await P.json();return b.parse(Y)})},$=async()=>{return r.get("updates",async()=>{let W=new URL("v0/updates.json",C),P=await D(W);if(!P.ok)throw new Error(`HN API error ${P.status}: Failed to fetch updates`);let Y=await P.json();return d.parse(Y)})},O=25,B=async(X,W={})=>{let{maxDepth:P=O,currentDepth:Y=0,concurrency:q=5}=W,A=await T(X);if(!A.kids||A.kids.length===0||Y>=P)return{...A,replies:[]};let E=Q,N=(await Promise.all(A.kids.map((H)=>{return E.schedule(async()=>{try{return await B(H,{maxDepth:P,currentDepth:Y+1,concurrency:q})}catch{return{id:H,deleted:!0,type:"comment",text:"Failed to load comment",replies:[]}}})}))).filter((H)=>!H.deleted&&!H.dead);return{...A,replies:N}},v={getItem:T,getItems:U,getUser:M,getMaxItemId:_,getUpdates:$,getItemWithComments:B,getTopStories:x("v0/topstories.json"),getNewStories:x("v0/newstories.json"),getBestStories:x("v0/beststories.json"),getAskStories:x("v0/askstories.json"),getShowStories:x("v0/showstories.json"),getJobStories:x("v0/jobstories.json"),invalidateItemCache:(X)=>{k.invalidate(`item:${X}`)},invalidateUserCache:(X)=>{l.invalidate(`user:${X}`)},invalidateListCaches:()=>{["v0/topstories.json","v0/newstories.json","v0/beststories.json","v0/askstories.json","v0/showstories.json","v0/jobstories.json"].forEach((W)=>{m.invalidate(`list:${W}`)})},clearAllCaches:()=>{k.clear(),m.clear(),l.clear(),r.clear(),t.clear()},use:(X)=>{return Z.register(X),v},clearHooks:()=>{return Z.clear(),v}};return v},_G=e(),{getItem:OG,getItems:qG,getUser:vG,getMaxItemId:xG,getUpdates:AG,getItemWithComments:TG,getTopStories:HG,getNewStories:NG,getBestStories:RG,getAskStories:UG,getShowStories:MG,getJobStories:LG,invalidateItemCache:FG,invalidateUserCache:SG,invalidateListCaches:wG,clearAllCaches:IG}=_G;var JG=i(require("bottleneck")),K=require("zod");var CG="https://hn.algolia.com/api/v1",EG=K.z.object({objectID:K.z.string(),title:K.z.string().nullable().optional(),url:K.z.string().nullable().optional(),author:K.z.string(),points:K.z.number().nullable().optional(),story_text:K.z.string().nullable().optional(),comment_text:K.z.string().nullable().optional(),_tags:K.z.array(K.z.string()),created_at:K.z.string(),created_at_i:K.z.number(),num_comments:K.z.number().nullable().optional()}),bG=K.z.object({hits:K.z.array(EG),page:K.z.number(),nbHits:K.z.number(),nbPages:K.z.number(),hitsPerPage:K.z.number(),processingTimeMS:K.z.number(),query:K.z.string()}),h=new R({maxAge:30000,staleWhileRevalidate:120000,maxEntries:500}),GG=(G,J)=>{return`search:${G}:${JSON.stringify(J)}`},QG=({limiter:G={minTime:370,maxConcurrent:1,reservoir:100,reservoirRefreshAmount:10,reservoirRefreshInterval:3700},fetch:J=globalThis.fetch,retry:V,signal:Q,hooks:Z}={})=>{let D=new F;if(Z)D.register(Z);let x=new JG.default(G===!1?{maxConcurrent:1/0}:G),T=async($,O)=>{return x.schedule(async()=>{try{let B={...O};if(Q)B.signal=O?.signal||Q;let{url:v,options:X}=await D.runBeforeFetchHooks($,B),W;if(J!==globalThis.fetch)W=await J(v,X);else W=await g(v,X,V);return await D.runAfterFetchHooks(W)}catch(B){throw await D.runOnErrorHooks(B instanceof Error?B:new Error(String(B)))}})},U=async($,O={})=>{let B=GG($,O);return h.get(B,async()=>{let{tags:v=["story"],numericFilters:X=[],page:W=0,hitsPerPage:P=20,sortByDate:Y=!1,restrictSearchableAttributes:q=[],author:A,storyId:E}=O,N=new URL(`${CG}/${Y?"search_by_date":"search"}`);N.searchParams.append("query",$);let H=[...v];if(A)H.push(`author_${A}`);if(E)H.push(`story_${E}`);if(H.length>0)N.searchParams.append("tags",H.join(","));if(X.length>0){let $G=X.map((z)=>`${z.field}${z.operator}${z.value}`);N.searchParams.append("numericFilters",$G.join(","))}if(N.searchParams.append("page",W.toString()),N.searchParams.append("hitsPerPage",P.toString()),q.length>0)N.searchParams.append("restrictSearchableAttributes",q.join(","));let L=await T(N.toString());if(!L.ok){if(L.status===429)throw new S(`Rate limit exceeded with status code ${L.status}. Check retryAfterSeconds for wait time.`,L);throw new Error(`Search request failed: ${L.statusText}`)}let ZG=await L.json();return bG.parse(ZG)})},_={searchStories:U,getFrontPageStories:async($={})=>{return U("",{...$,tags:["front_page"]})},invalidateSearchCache:($,O={})=>{let B=GG($,O);h.invalidate(B)},clearSearchCache:()=>{h.clear()},use:($)=>{return D.register($),_},clearHooks:()=>{return D.clear(),_}};return _},gG=QG(),{searchStories:zG,getFrontPageStories:fG,invalidateSearchCache:yG,clearSearchCache:uG}=gG; //# debugId=6EAB47BD85FE052C64756E2164756E21 //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2FwaS50cyIsICIuLi9zcmMvY2FjaGUudHMiLCAiLi4vc3JjL2hvb2tzLnRzIiwgIi4uL3NyYy9zY2hlbWFzLnRzIiwgIi4uL3NyYy9lcnJvcnMudHMiLCAiLi4vc3JjL3V0aWxpdGllcy50cyIsICIuLi9zcmMvc2VhcmNoLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWwogICAgImltcG9ydCBCb3R0bGVuZWNrIGZyb20gJ2JvdHRsZW5lY2snO1xuaW1wb3J0IHsgQ2FjaGUgfSBmcm9tICcuL2NhY2hlJztcbmltcG9ydCB7IEhvb2tzTWFuYWdlciB9IGZyb20gJy4vaG9va3MnO1xuaW1wb3J0IHtcbiAgSGFja2VyTmV3c0lkTGlzdFNjaGVtYSxcbiAgSGFja2VyTmV3c0lkU2NoZW1hLFxuICBIYWNrZXJOZXdzSXRlbVNjaGVtYSxcbiAgSGFja2VyTmV3c1VwZGF0ZXNTY2hlbWEsXG4gIEhhY2tlck5ld3NVc2VyU2NoZW1hLFxufSBmcm9tICcuL3NjaGVtYXMnO1xuaW1wb3J0IHR5cGUge1xuICBDbGllbnRPcHRpb25zLFxuICBIYWNrZXJOZXdzQ29tbWVudFRyZWUsXG4gIEhhY2tlck5ld3NJZCxcbiAgSGFja2VyTmV3c0lkTGlzdCxcbiAgSGFja2VyTmV3c0l0ZW0sXG4gIEhhY2tlck5ld3NVcGRhdGVzLFxuICBIYWNrZXJOZXdzVXNlcixcbiAgSGFja2VyTmV3c1VzZXJuYW1lLFxuICBSZXF1ZXN0SW5mbyxcbiAgUmVxdWVzdEluaXQsXG59IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHR5cGUgeyBDbGllbnRIb29rcyB9IGZyb20gJy4vaG9va3MnO1xuXG5pbXBvcnQgeyBmZXRjaFdpdGhSZXRyeSB9IGZyb20gJy4vdXRpbGl0aWVzJztcblxuY29uc3QgYmFzZVVybCA9ICdodHRwczovL2hhY2tlci1uZXdzLmZpcmViYXNlaW8uY29tLyc7XG5cbi8qKlxuICogQ2FjaGUgY29uZmlndXJhdGlvbiBmb3IgZGlmZmVyZW50IGRhdGEgdHlwZXMgd2l0aCBhcHByb3ByaWF0ZSBUVExzXG4gKi9cblxuLyoqXG4gKiBJdGVtcyBjYWNoZSAtIHJhcmVseSBjaGFuZ2UgYWZ0ZXIgY3JlYXRpb25cbiAqIC0gNSBtaW51dGVzIGZyZXNoIGRhdGFcbiAqIC0gMSBob3VyIHN0YWxlIGRhdGFcbiAqIC0gMjAwMCBtYXhpbXVtIGVudHJpZXNcbiAqL1xuY29uc3QgaXRlbUNhY2hlID0gbmV3IENhY2hlPEhhY2tlck5ld3NJdGVtPih7XG4gIG1heEFnZTogNSAqIDYwICogMTAwMCxcbiAgc3RhbGVXaGlsZVJldmFsaWRhdGU6IDYwICogNjAgKiAxMDAwLFxuICBtYXhFbnRyaWVzOiAyMDAwLFxufSk7XG5cbi8qKlxuICogTGlzdHMgY2FjaGUgLSBjaGFuZ2UgZnJlcXVlbnRseVxuICogLSAzMCBzZWNvbmRzIGZyZXNoIGRhdGFcbiAqIC0gMiBtaW51dGVzIHN0YWxlIGRhdGFcbiAqIC0gMjAgbWF4aW11bSBlbnRyaWVzIChoYW5kZnVsIG9mIGxpc3QgdHlwZXMpXG4gKi9cbmNvbnN0IGxpc3RDYWNoZSA9IG5ldyBDYWNoZTxIYWNrZXJOZXdzSWRMaXN0Pih7XG4gIG1heEFnZTogMzAgKiAxMDAwLFxuICBzdGFsZVdoaWxlUmV2YWxpZGF0ZTogMiAqIDYwICogMTAwMCxcbiAgbWF4RW50cmllczogMjAsXG59KTtcblxuLyoqXG4gKiBVc2VyIGNhY2hlIC0gY2hhbmdlcyBsZXNzIGZyZXF1ZW50bHlcbiAqIC0gNSBtaW51dGVzIGZyZXNoIGRhdGFcbiAqIC0gMzAgbWludXRlcyBzdGFsZSBkYXRhXG4gKiAtIDUwMCBtYXhpbXVtIGVudHJpZXNcbiAqL1xuY29uc3QgdXNlckNhY2hlID0gbmV3IENhY2hlPEhhY2tlck5ld3NVc2VyPih7XG4gIG1heEFnZTogNSAqIDYwICogMTAwMCxcbiAgc3RhbGVXaGlsZVJldmFsaWRhdGU6IDMwICogNjAgKiAxMDAwLFxuICBtYXhFbnRyaWVzOiA1MDAsXG59KTtcblxuLyoqXG4gKiBVcGRhdGVzIGNhY2hlIC0gY2hhbmdlcyBmcmVxdWVudGx5XG4gKiAtIDMwIHNlY29uZHMgZnJlc2ggZGF0YVxuICogLSAxIG1pbnV0ZSBzdGFsZSBkYXRhXG4gKiAtIDUgbWF4aW11bSBlbnRyaWVzXG4gKi9cbmNvbnN0IHVwZGF0ZXNDYWNoZSA9IG5ldyBDYWNoZTxIYWNrZXJOZXdzVXBkYXRlcz4oe1xuICBtYXhBZ2U6IDMwICogMTAwMCxcbiAgc3RhbGVXaGlsZVJldmFsaWRhdGU6IDYwICogMTAwMCxcbiAgbWF4RW50cmllczogNSxcbn0pO1xuXG4vKipcbiAqIE1heEl0ZW0gY2FjaGUgLSBzaW5nbGUgZW50cnkgdGhhdCBjaGFuZ2VzIGZyZXF1ZW50bHlcbiAqIC0gMzAgc2Vjb25kcyBmcmVzaCBkYXRhXG4gKiAtIDEgbWludXRlIHN0YWxlIGRhdGFcbiAqIC0gMSBtYXhpbXVtIGVudHJ5XG4gKi9cbmNvbnN0IG1heEl0ZW1DYWNoZSA9IG5ldyBDYWNoZTxIYWNrZXJOZXdzSWQ+KHtcbiAgbWF4QWdlOiAzMCAqIDEwMDAsXG4gIHN0YWxlV2hpbGVSZXZhbGlkYXRlOiA2MCAqIDEwMDAsXG4gIG1heEVudHJpZXM6IDEsXG59KTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgY2xpZW50IHdpdGggY29uZmlndXJhYmxlIGZldGNoIGltcGxlbWVudGF0aW9uXG4gKiBAcGFyYW0gb3B0aW9ucyBDbGllbnQgb3B0aW9ucyBpbmNsdWRpbmcgb3B0aW9uYWwgZmV0Y2ggZnVuY3Rpb24sIGxpbWl0ZXIgY29uZmlndXJhdGlvbiwgYW5kIEFib3J0U2lnbmFsXG4gKiBAcmV0dXJucyBPYmplY3QgY29udGFpbmluZyBhbGwgSGFja2VyTmV3cyBBUEkgbWV0aG9kc1xuICpcbiAqIEV4YW1wbGUgd2l0aCBBYm9ydFNpZ25hbDpcbiAqIGBgYHRzXG4gKiAvLyBDcmVhdGUgYW4gQWJvcnRDb250cm9sbGVyIHRvIGNhbmNlbCByZXF1ZXN0cyB3aGVuIG5lZWRlZFxuICogY29uc3QgY29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAqIGNvbnN0IGNsaWVudCA9IGNyZWF0ZUNsaWVudCh7IHNpZ25hbDogY29udHJvbGxlci5zaWduYWwgfSk7XG4gKlxuICogLy8gTGF0ZXIsIHRvIGNhbmNlbCBhbGwgaW4tZmxpZ2h0IHJlcXVlc3RzOlxuICogY29udHJvbGxlci5hYm9ydCgpO1xuICogYGBgXG4gKlxuICogRXhhbXBsZSB3aXRoIGN1c3RvbSByYXRlIGxpbWl0aW5nOlxuICogYGBgdHNcbiAqIC8vIENyZWF0ZSBhIGNsaWVudCB3aXRoIGN1c3RvbSByYXRlIGxpbWl0aW5nXG4gKiBjb25zdCBjbGllbnQgPSBjcmVhdGVDbGllbnQoe1xuICogICBsaW1pdGVyOiB7XG4gKiAgICAgbWF4Q29uY3VycmVudDogMTAsICAgICAgIC8vIEFsbG93IHVwIHRvIDEwIGNvbmN1cnJlbnQgcmVxdWVzdHNcbiAqICAgICBtaW5UaW1lOiAxMDAsICAgICAgICAgICAgLy8gTWluaW11bSAxMDBtcyBiZXR3ZWVuIHJlcXVlc3RzXG4gKiAgICAgcmVzZXJ2b2lyOiA1MCwgICAgICAgICAgIC8vIEFsbG93IGJ1cnN0cyB1cCB0byA1MCByZXF1ZXN0c1xuICogICAgIHJlc2Vydm9pclJlZnJlc2hBbW91bnQ6IDEwLCAgLy8gUmVmaWxsIDEwIHRva2VucyBhdCBhIHRpbWVcbiAqICAgICByZXNlcnZvaXJSZWZyZXNoSW50ZXJ2YWw6IDEwMDAgIC8vIFJlZmlsbCBldmVyeSAxIHNlY29uZFxuICogICB9XG4gKiB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgY29uc3QgY3JlYXRlQ2xpZW50ID0gKG9wdGlvbnM6IENsaWVudE9wdGlvbnMgPSB7fSkgPT4ge1xuICAvLyBVc2UgcHJvdmlkZWQgZmV0Y2ggZnVuY3Rpb24gb3IgZmFsbCBiYWNrIHRvIGdsb2JhbCBmZXRjaFxuICBjb25zdCBfZmV0Y2ggPSBvcHRpb25zLmZldGNoIHx8IGZldGNoO1xuXG4gIC8vIERlZmF1bHQgbGltaXRlciBvcHRpb25zIGZvciB0aGUgSGFja2VyIE5ld3MgQVBJXG4gIGNvbnN0IGRlZmF1bHRMaW1pdGVyT3B0aW9ucyA9IHtcbiAgICBtYXhDb25jdXJyZW50OiA1LCAvLyBEZWZhdWx0IG1heCBjb25jdXJyZW50IHJlcXVlc3RzXG4gICAgc3RyYXRlZ3k6IEJvdHRsZW5lY2suc3RyYXRlZ3kuQkxPQ0ssIC8vIERlZmF1bHQgc3RyYXRlZ3lcbiAgfTtcblxuICAvLyBDcmVhdGUgYSBnbG9iYWwgcmF0ZSBsaW1pdGVyIHRoYXQgY2FuIGJlIHNoYXJlZCBhY3Jvc3MgbWV0aG9kc1xuICBjb25zdCBnbG9iYWxMaW1pdGVyID0gbmV3IEJvdHRsZW5lY2soXG4gICAgb3B0aW9ucy5saW1pdGVyID09PSB1bmRlZmluZWQgfHwgb3B0aW9ucy5saW1pdGVyID09PSBudWxsXG4gICAgICA/IGRlZmF1bHRMaW1pdGVyT3B0aW9ucyAvLyBVc2UgZGVmYXVsdHMgaWYgbm8gb3B0aW9ucyBwcm92aWRlZFxuICAgICAgOiBvcHRpb25zLmxpbWl0ZXIgPT09IGZhbHNlXG4gICAgICAgID8geyBtYXhDb25jdXJyZW50OiBJbmZpbml0eSB9IC8vIEVmZmVjdGl2ZWx5IGRpc2FibGUgbGltaXRpbmcgaWYgZXhwbGljaXRseSBzZXQgdG8gZmFsc2VcbiAgICAgICAgOiB7IC4uLmRlZmF1bHRMaW1pdGVyT3B0aW9ucywgLi4ub3B0aW9ucy5saW1pdGVyIH0sIC8vIFVzZSBwcm92aWRlZCBvcHRpb25zIHdpdGggZGVmYXVsdHNcbiAgKTtcblxuICAvLyBJbml0aWFsaXplIHRoZSBob29rcyBtYW5hZ2VyXG4gIGNvbnN0IGhvb2tzTWFuYWdlciA9IG5ldyBIb29rc01hbmFnZXIoKTtcblxuICAvLyBSZWdpc3RlciBpbml0aWFsIGhvb2tzIGlmIHByb3ZpZGVkXG4gIGlmIChvcHRpb25zLmhvb2tzKSB7XG4gICAgaG9va3NNYW5hZ2VyLnJlZ2lzdGVyKG9wdGlvbnMuaG9va3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ha2VzIGEgZmV0Y2ggcmVxdWVzdCB1c2luZyBlaXRoZXIgdGhlIGN1c3RvbSBmZXRjaCBmdW5jdGlvbiBvciB0aGUgcmV0cnktZW5hYmxlZCBmZXRjaFxuICAgKiBBcHBsaWVzIGhvb2tzIGJlZm9yZSBhbmQgYWZ0ZXIgZmV0Y2gsIHBsdXMgZXJyb3IgaGFuZGxpbmdcbiAgICogQHBhcmFtIHVybCBUaGUgVVJMIHRvIGZldGNoXG4gICAqIEBwYXJhbSBpbml0IE9wdGlvbmFsIHJlcXVlc3QgaW5pdCBvcHRpb25zXG4gICAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZXNwb25zZVxuICAgKi9cbiAgY29uc3QgY2xpZW50RmV0Y2ggPSBhc3luYyAodXJsOiBSZXF1ZXN0SW5mbywgaW5pdD86IFJlcXVlc3RJbml0KTogUHJvbWlzZTxSZXNwb25zZT4gPT4ge1xuICAgIC8vIE1lcmdlIGluaXQgd2l0aCB0aGUgZ2xvYmFsIHNpZ25hbCBpZiBwcm92aWRlZFxuICAgIGNvbnN0IHJlcXVlc3RJbml0ID0gb3B0aW9ucy5zaWduYWwgPyB7IC4uLmluaXQsIHNpZ25hbDogaW5pdD8uc2lnbmFsIHx8IG9wdGlvbnMuc2lnbmFsIH0gOiBpbml0O1xuXG4gICAgdHJ5IHtcbiAgICAgIC8vIFJ1biBiZWZvcmVGZXRjaCBob29rcyB0byBwb3RlbnRpYWxseSBtb2RpZnkgcmVxdWVzdFxuICAgICAgY29uc3QgeyB1cmw6IG1vZGlmaWVkVXJsLCBvcHRpb25zOiBtb2RpZmllZE9wdGlvbnMgfSA9IGF3YWl0IGhvb2tzTWFuYWdlci5ydW5CZWZvcmVGZXRjaEhvb2tzKHVybCwgcmVxdWVzdEluaXQpO1xuXG4gICAgICAvLyBNYWtlIHRoZSBhY3R1YWwgZmV0Y2ggcmVxdWVzdFxuICAgICAgbGV0IHJlc3BvbnNlOiBSZXNwb25zZTtcblxuICAgICAgLy8gSWYgYSBjdXN0b20gZmV0Y2ggZnVuY3Rpb24gd2FzIHByb3ZpZGVkIChub3QgdGhlIGRlZmF1bHQpLCB1c2UgaXRcbiAgICAgIGlmIChvcHRpb25zLmZldGNoICYmIG9wdGlvbnMuZmV0Y2ggIT09IGdsb2JhbFRoaXMuZmV0Y2gpIHtcbiAgICAgICAgcmVzcG9uc2UgPSBhd2FpdCBfZmV0Y2gobW9kaWZpZWRVcmwsIG1vZGlmaWVkT3B0aW9ucyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBPdGhlcndpc2UgdXNlIHRoZSByZXRyeS1lbmFibGVkIGZldGNoXG4gICAgICAgIHJlc3BvbnNlID0gYXdhaXQgZmV0Y2hXaXRoUmV0cnkobW9kaWZpZWRVcmwsIG1vZGlmaWVkT3B0aW9ucywgb3B0aW9ucy5yZXRyeSk7XG4gICAgICB9XG5cbiAgICAgIC8vIFJ1biBhZnRlckZldGNoIGhvb2tzXG4gICAgICByZXR1cm4gYXdhaXQgaG9va3NNYW5hZ2VyLnJ1bkFmdGVyRmV0Y2hIb29rcyhyZXNwb25zZSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIFJ1biBvbkVycm9yIGhvb2tzXG4gICAgICBjb25zdCBwcm9jZXNzZWRFcnJvciA9IGF3YWl0IGhvb2tzTWFuYWdlci5ydW5PbkVycm9ySG9va3MoXG4gICAgICAgIGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKSxcbiAgICAgICk7XG4gICAgICB0aHJvdyBwcm9jZXNzZWRFcnJvcjtcbiAgICB9XG4gIH07XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gYXN5bmNocm9ub3VzIGZ1bmN0aW9uIHRoYXQgZmV0Y2hlcyBhIGxpc3Qgb2YgSGFja2VyIE5ld3MgSURzIGZyb20gYSBnaXZlbiBlbmRwb2ludC5cbiAgICogSW5jbHVkZXMgaW4tbWVtb3J5IGNhY2hpbmcgd2l0aCBzdGFsZS13aGlsZS1yZXZhbGlkYXRlIHNlbWFudGljcy5cbiAgICpcbiAgICogQHBhcmFtIGVuZHBvaW50IC0gVGhlIGVuZHBvaW50IFVSTCB0byBmZXRjaCB0aGUgSGFja2VyIE5ld3MgSUQgbGlzdCBmcm9tLlxuICAgKiBAcmV0dXJucyBBIGZhY3RvcnkgZnVuY3Rpb24gZm9yIGZldGNoaW5nIHRoZSBsaXN0IG9mIEhhY2tlciBOZXdzIElEcy5cbiAgICovXG4gIGNvbnN0IGNyZWF0ZUxpc3RFbmRwb2ludCA9IChlbmRwb2ludDogc3RyaW5nKSA9PiBhc3luYyAoKTogUHJvbWlzZTxIYWNrZXJOZXdzSWRMaXN0PiA9PiB7XG4gICAgY29uc3QgY2FjaGVLZXkgPSBgbGlzdDoke2VuZHBvaW50fWA7XG5cbiAgICByZXR1cm4gbGlzdENhY2hlLmdldChjYWNoZUtleSwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdXJsID0gbmV3IFVSTChlbmRwb2ludCwgYmFzZVVybCk7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNsaWVudEZldGNoKHVybCk7XG5cbiAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBITiBBUEkgZXJyb3IgJHtyZXNwb25zZS5zdGF0dXN9OiBGYWlsZWQgdG8gZmV0Y2ggbGlzdCBmcm9tICR7ZW5kcG9pbnR9YCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7XG5cbiAgICAgIHJldHVybiBIYWNrZXJOZXdzSWRMaXN0U2NoZW1hLnBhcnNlKGNvbnRlbnQpO1xuICAgIH0pO1xuICB9O1xuXG4gIC8qKlxuICAgKiBGZXRjaGVzIGEgc3BlY2lmaWMgSGFja2VyIE5ld3MgaXRlbSBieSBpdHMgSUQuXG4gICAqIFVzZXMgaW4tbWVtb3J5IGNhY2hlIHdpdGggc3RhbGUtd2hpbGUtcmV2YWxpZGF0ZSBzZW1hbnRpY3MuXG4gICAqL1xuICBjb25zdCBnZXRJdGVtID0gYXN5bmMgKGlkOiBIYWNrZXJOZXdzSWQpOiBQcm9taXNlPEhhY2tlck5ld3NJdGVtPiA9PiB7XG4gICAgY29uc3QgY2FjaGVLZXkgPSBgaXRlbToke2lkfWA7XG5cbiAgICByZXR1cm4gaXRlbUNhY2hlLmdldChjYWNoZUtleSwgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gQ29uc3RydWN0IHRoZSBVUkwgZm9yIGZldGNoaW5nIGEgc3BlY2lmaWMgSGFja2VyIE5ld3MgaXRlbSBieSBpdHMgSUQuXG4gICAgICBjb25zdCB1cmwgPSBuZXcgVVJMKGB2MC9pdGVtLyR7aWR9Lmpzb25gLCBiYXNlVXJsKTtcblxuICAgICAgLy8gRmV0Y2ggdGhlIGl0ZW0gZGF0YSBmcm9tIHRoZSBjb25zdHJ1Y3RlZCBVUkwuXG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNsaWVudEZldGNoKHVybCk7XG5cbiAgICAgIC8vIENoZWNrIGlmIHRoZSByZXNwb25zZSB3YXMgc3VjY2Vzc2Z1bFxuICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEhOIEFQSSBlcnJvciAke3Jlc3BvbnNlLnN0YXR1c306IEZhaWxlZCB0byBmZXRjaCBpdGVtICR7aWR9YCk7XG4gICAgICB9XG5cbiAgICAgIC8vIFBhcnNlIHRoZSBKU09OIHJlc3BvbnNlIGNvbnRlbnQuXG4gICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xuXG4gICAgICAvLyBWYWxpZGF0ZSBhbmQgcmV0dXJuIHRoZSBwYXJzZWQgY29udGVudCB1c2luZyB0aGUgSGFja2VyTmV3c0l0ZW1TY2hlbWEuXG4gICAgICByZXR1cm4gSGFja2VyTmV3c0l0ZW1TY2hlbWEucGFyc2UoY29udGVudCk7XG4gICAgfSk7XG4gIH07XG5cbiAgLyoqXG4gICAqIEZldGNoZXMgbXVsdGlwbGUgSGFja2VyIE5ld3MgaXRlbXMgYmFzZWQgb24gdGhlaXIgSURzLlxuICAgKiBVc2VzIHRoZSBnbG9iYWwgcmF0ZSBsaW1pdGVyIHRvIGNvbnRyb2wgY29uY3VycmVudCByZXF1ZXN0cy5cbiAgICpcbiAgICogQHBhcmFtIGlkcyAtIEFuIGFycmF5IG9mIEhhY2tlciBOZXdzIGl0ZW0gSURzIHRvIGZldGNoLlxuICAgKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIGFuIGFycmF5IG9mIEhhY2tlciBOZXdzIGl0ZW1zLlxuICAgKi9cbiAgY29uc3QgZ2V0SXRlbXMgPSBhc3luYyAoaWRzOiBIYWNrZXJOZXdzSWRMaXN0KTogUHJvbWlzZTxIYWNrZXJOZXdzSXRlbVtdPiA9PiB7XG4gICAgLy8gVXNlIHRoZSBnbG9iYWwgbGltaXRlciBmb3IgcmF0ZSBsaW1pdGluZ1xuICAgIGNvbnN0IGxpbWl0ZXIgPSBnbG9iYWxMaW1pdGVyO1xuXG4gICAgLy8gTWFwIGVhY2ggSUQgdG8gYSBzY2hlZHVsZWQgcHJvbWlzZVxuICAgIGNvbnN0IHByb21pc2VzID0gaWRzLm1hcCgoaWQpID0+IHtcbiAgICAgIHJldHVybiBsaW1pdGVyLnNjaGVkdWxlKCgpID0+IGdldEl0ZW0oaWQpKTtcbiAgICB9KTtcblxuICAgIC8vIFdhaXQgZm9yIGFsbCBzY2hlZHVsZWQgcHJvbWlzZXMgdG8gcmVzb2x2ZVxuICAgIHJldHVybiBQcm9taXNlLmFsbChwcm9taXNlcyk7XG4gIH07XG5cbiAgY29uc3QgZ2V0VXNlciA9IGFzeW5jICh1c2VybmFtZTogSGFja2VyTmV3c1VzZXJuYW1lKTogUHJvbWlzZTxIYWNrZXJOZXdzVXNlcj4gPT4ge1xuICAgIGNvbnN0IGNhY2hlS2V5ID0gYHVzZXI6JHt1c2VybmFtZX1gO1xuXG4gICAgcmV0dXJuIHVzZXJDYWNoZS5nZXQoY2FjaGVLZXksIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIENvbnN0cnVjdCB0aGUgVVJMIGZvciBmZXRjaGluZyBhIHNwZWNpZmljIEhhY2tlciBOZXdzIHVzZXIgYnkgdGhlaXIgdXNlcm5hbWUuXG4gICAgICBjb25zdCB1cmwgPSBuZXcgVVJMKGB2MC91c2VyLyR7dXNlcm5hbWV9Lmpzb25gLCBiYXNlVXJsKTtcblxuICAgICAgLy8gRmV0Y2ggdGhlIHVzZXIgZGF0YSBmcm9tIHRoZSBjb25zdHJ1Y3RlZCBVUkwuXG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNsaWVudEZldGNoKHVybCk7XG5cbiAgICAgIC8vIENoZWNrIGlmIHRoZSByZXNwb25zZSB3YXMgc3VjY2Vzc2Z1bFxuICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEhOIEFQSSBlcnJvciAke3Jlc3BvbnNlLnN0YXR1c306IEZhaWxlZCB0byBmZXRjaCB1c2VyICR7dXNlcm5hbWV9YCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHVzZXIgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7XG5cbiAgICAgIC8vIFZhbGlkYXRlIGFuZCByZXR1cm4gdGhlIHBhcnNlZCBjb250ZW50IHVzaW5nIHRoZSBIYWNrZXJOZXdzVXNlclNjaGVtYS5cbiAgICAgIHJldHVybiBIYWNrZXJOZXdzVXNlclNjaGVtYS5wYXJzZSh1c2VyKTtcbiAgICB9KTtcbiAgfTtcblxuICAvKipcbiAgICogRmV0Y2hlcyB0aGUgbWF4aW11bSBIYWNrZXIgTmV3cyBpdGVtIElELlxuICAgKiBVc2VzIGluLW1lbW9yeSBjYWNoZSB3aXRoIHN0YWxlLXdoaWxlLXJldmFsaWRhdGUgc2VtYW50aWNzLlxuICAgKlxuICAgKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBtYXhpbXVtIEhhY2tlciBOZXdzIGl0ZW0gSUQuXG4gICAqL1xuICBjb25zdCBnZXRNYXhJdGVtSWQgPSBhc3luYyAoKTogUHJvbWlzZTxIYWNrZXJOZXdzSWQ+ID0+IHtcbiAgICBjb25zdCBjYWNoZUtleSA9ICdtYXhpdGVtJztcblxuICAgIHJldHVybiBtYXhJdGVtQ2FjaGUuZ2V0KGNhY2hlS2V5LCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB1cmwgPSBuZXcgVVJMKCd2MC9tYXhpdGVtLmpzb24nLCBiYXNlVXJsKTtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50RmV0Y2godXJsKTtcblxuICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEhOIEFQSSBlcnJvciAke3Jlc3BvbnNlLnN0YXR1c306IEZhaWxlZCB0byBmZXRjaCBtYXggaXRlbSBJRGApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xuICAgICAgcmV0dXJuIEhhY2tlck5ld3NJZFNjaGVtYS5wYXJzZShjb250ZW50KTtcbiAgICB9KTtcbiAgfTtcblxuICAvKipcbiAgICogRmV0Y2hlcyB0aGUgbGF0ZXN0IHVwZGF0ZXMgZnJvbSBIYWNrZXIgTmV3cy5cbiAgICogVXNlcyBpbi1tZW1vcnkgY2FjaGUgd2l0aCBzdGFsZS13aGlsZS1yZXZhbGlkYXRlIHNlbWFudGljcy5cbiAgICpcbiAgICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgSGFja2VyIE5ld3MgdXBkYXRlcy5cbiAgICovXG4gIGNvbnN0IGdldFVwZGF0ZXMgPSBhc3luYyAoKTogUHJvbWlzZTxIYWNrZXJOZXdzVXBkYXRlcz4gPT4ge1xuICAgIGNvbnN0IGNhY2hlS2V5ID0gJ3VwZGF0ZXMnO1xuXG4gICAgcmV0dXJuIHVwZGF0ZXNDYWNoZS5nZXQoY2FjaGVLZXksIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHVybCA9IG5ldyBVUkwoJ3YwL3VwZGF0ZXMuanNvbicsIGJhc2VVcmwpO1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBjbGllbnRGZXRjaCh1cmwpO1xuXG4gICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSE4gQVBJIGVycm9yICR7cmVzcG9uc2Uuc3RhdHVzfTogRmFpbGVkIHRvIGZldGNoIHVwZGF0ZXNgKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcbiAgICAgIHJldHVybiBIYWNrZXJOZXdzVXBkYXRlc1NjaGVtYS5wYXJzZShjb250ZW50KTtcbiAgICB9KTtcbiAgfTtcblxuICAvKipcbiAgICogU2FmZSBkZWZhdWx0IGZvciB0aGUgbWF4aW11bSBkZXB0aCBvZiBjb21tZW50cyB0byBmZXRjaFxuICAgKiBQcmV2ZW50cyBzdGFjayBvdmVyZmxvd3Mgd2l0aCBkZWVwbHkgbmVzdGVkIGNvbW1lbnRzXG4gICAqL1xuICBjb25zdCBERUZBVUxUX01BWF9DT01NRU5UX0RFUFRIID0gMjU7XG5cbiAgLyoqXG4gICAqIFJlY3Vyc2l2ZWx5IGZldGNoZXMgYW4gaXRlbSBhbmQgYWxsIGl0cyBjb21tZW50cy9yZXBsaWVzLCBjcmVhdGluZyBhIG5lc3RlZCB0cmVlIHN0cnVjdHVyZS5cbiAgICpcbiAgICogQHBhcmFtIGl0ZW1JZCAtIFRoZSBJRCBvZiB0aGUgaXRlbSAoc3Rvcnkgb3IgY29tbWVudCkgdG8gZmV0Y2ggd2l0aCBpdHMgY29tbWVudHNcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcHRpb25zIGZvciBmZXRjaGluZyB0aGUgY29tbWVudHNcbiAgICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgaXRlbSBhbmQgaXRzIG5lc3RlZCBjb21tZW50c1xuICAgKi9cbiAgY29uc3QgZ2V0SXRlbVdpdGhDb21tZW50cyA9IGFzeW5jIChcbiAgICBpdGVtSWQ6IEhhY2tlck5ld3NJZCxcbiAgICBvcHRpb25zOiB7XG4gICAgICAvKiogTWF4aW11bSBkZXB0aCBvZiBjb21tZW50cyB0byBmZXRjaCAoZGVmYXVsdDogMjUpICovXG4gICAgICBtYXhEZXB0aD86IG51bWJlcjtcbiAgICAgIC8qKiBDdXJyZW50IGRlcHRoIGluIHRoZSByZWN1cnNpb24gKHVzZWQgaW50ZXJuYWxseSkgKi9cbiAgICAgIGN1cnJlbnREZXB0aD86IG51bWJlcjtcbiAgICAgIC8qKiBNYXhpbXVtIG51bWJlciBvZiBjb25jdXJyZW50IHJlcXVlc3RzIHBlciBsZXZlbCAoZGVmYXVsdDogNSkgKi9cbiAgICAgIGNvbmN1cnJlbmN5PzogbnVtYmVyO1xuICAgIH0gPSB7fSxcbiAgKTogUHJvbWlzZTxIYWNrZXJOZXdzQ29tbWVudFRyZWU+ID0+IHtcbiAgICBjb25zdCB7IG1heERlcHRoID0gREVGQVVMVF9NQVhfQ09NTUVOVF9ERVBUSCwgY3VycmVudERlcHRoID0gMCwgY29uY3VycmVuY3kgPSA1IH0gPSBvcHRpb25zO1xuXG4gICAgLy8gR2V0IHRoZSBpdGVtXG4gICAgY29uc3QgaXRlbSA9IGF3YWl0IGdldEl0ZW0oaXRlbUlkKTtcblxuICAgIC8vIEJhc2UgY2FzZTogbm8ga2lkcyBvciByZWFjaGVkIG1heCBkZXB0aFxuICAgIGlmICghaXRlbS5raWRzIHx8IGl0ZW0ua2lkcy5sZW5ndGggPT09IDAgfHwgY3VycmVudERlcHRoID49IG1heERlcHRoKSB7XG4gICAgICByZXR1cm4geyAuLi5pdGVtLCByZXBsaWVzOiBbXSB9O1xuICAgIH1cblxuICAgIC8vIFVzZSB0aGUgZ2xvYmFsIGxpbWl0ZXIgdG8gcmVzdHJpY3QgY29uY3VycmVudCByZXF1ZXN0c1xuICAgIGNvbnN0IGxpbWl0ZXIgPSBnbG9iYWxMaW1pdGVyO1xuXG4gICAgLy8gUmVjdXJzaXZlbHkgZmV0Y2ggYWxsIGNoaWxkIGNvbW1lbnRzIHdpdGggY29uY3VycmVuY3kgbGltaXRcbiAgICBjb25zdCByZXBsaWVzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBpdGVtLmtpZHMubWFwKChraWRJZCkgPT4ge1xuICAgICAgICByZXR1cm4gbGltaXRlci5zY2hlZHVsZShhc3luYyAoKSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBnZXRJdGVtV2l0aENvbW1lbnRzKGtpZElkLCB7XG4gICAgICAgICAgICAgIG1heERlcHRoLFxuICAgICAgICAgICAgICBjdXJyZW50RGVwdGg6IGN1cnJlbnREZXB0aCArIDEsXG4gICAgICAgICAgICAgIGNvbmN1cnJlbmN5LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAvLyBJZiBhIGNvbW1lbnQgZmFpbHMgdG8gbG9hZCwgcmV0dXJuIGEgcGxhY2Vob2xkZXJcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIGlkOiBraWRJZCxcbiAgICAgICAgICAgICAgZGVsZXRlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgdHlwZTogJ2NvbW1lbnQnIGFzIGNvbnN0LFxuICAgICAgICAgICAgICB0ZXh0OiAnRmFpbGVkIHRvIGxvYWQgY29tbWVudCcsXG4gICAgICAgICAgICAgIHJlcGxpZXM6IFtdLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSksXG4gICAgKTtcblxuICAgIC8vIEZpbHRlciBvdXQgZGVsZXRlZCBvciBkZWFkIGNvbW1lbnRzXG4gICAgY29uc3QgdmFsaWRSZXBsaWVzID0gcmVwbGllcy5maWx0ZXIoKHJlcGx5KSA9PiAhcmVwbHkuZGVsZXRlZCAmJiAhcmVwbHkuZGVhZCk7XG5cbiAgICAvLyBSZXR1cm4gdGhlIGl0ZW0gd2l0aCBpdHMgcmVwbGllc1xuICAgIHJldHVybiB7XG4gICAgICAuLi5pdGVtLFxuICAgICAgcmVwbGllczogdmFsaWRSZXBsaWVzLFxuICAgIH07XG4gIH07XG5cbiAgLy8gUmV0dXJuIHRoZSBjbGllbnQgb2JqZWN0IHdpdGggYWxsIG1ldGhvZHNcbiAgY29uc3QgY2xpZW50ID0ge1xuICAgIC8vIE1haW4gQVBJIG1ldGhvZHNcbiAgICBnZXRJdGVtLFxuICAgIGdldEl0ZW1zLFxuICAgIGdldFVzZXIsXG4gICAgZ2V0TWF4SXRlbUlkLFxuICAgIGdldFVwZGF0ZXMsXG4gICAgZ2V0SXRlbVdpdGhDb21tZW50cyxcblxuICAgIC8vIFN0b3J5IGxpc3QgbWV0aG9kc1xuICAgIGdldFRvcFN0b3JpZXM6IGNyZWF0ZUxpc3RFbmRwb2ludCgndjAvdG9wc3Rvcmllcy5qc29uJyksXG4gICAgZ2V0TmV3U3RvcmllczogY3JlYXRlTGlzdEVuZHBvaW50KCd2MC9uZXdzdG9yaWVzLmpzb24nKSxcbiAgICBnZXRCZXN0U3RvcmllczogY3JlYXRlTGlzdEVuZHBvaW50KCd2MC9iZXN0c3Rvcmllcy5qc29uJyksXG4gICAgZ2V0QXNrU3RvcmllczogY3JlYXRlTGlzdEVuZHBvaW50KCd2MC9hc2tzdG9yaWVzLmpzb24nKSxcbiAgICBnZXRTaG93U3RvcmllczogY3JlYXRlTGlzdEVuZHBvaW50KCd2MC9zaG93c3Rvcmllcy5qc29uJyksXG4gICAgZ2V0Sm9iU3RvcmllczogY3JlYXRlTGlzdEVuZHBvaW50KCd2MC9qb2JzdG9yaWVzLmpzb24nKSxcblxuICAgIC8vIENhY2hlIGNvbnRyb2wgbWV0aG9kc1xuICAgIGludmFsaWRhdGVJdGVtQ2FjaGU6IChpZDogSGFja2VyTmV3c0lkKTogdm9pZCA9PiB7XG4gICAgICBpdGVtQ2FjaGUuaW52YWxpZGF0ZShgaXRlbToke2lkfWApO1xuICAgIH0sXG4gICAgaW52YWxpZGF0ZVVzZXJDYWNoZTogKHVzZXJuYW1lOiBIYWNrZXJOZXdzVXNlcm5hbWUpOiB2b2lkID0+IHtcbiAgICAgIHVzZXJDYWNoZS5pbnZhbGlkYXRlKGB1c2VyOiR7dXNlcm5hbWV9YCk7XG4gICAgfSxcbiAgICBpbnZhbGlkYXRlTGlzdENhY2hlczogKCk6IHZvaWQgPT4ge1xuICAgICAgY29uc3QgZW5kcG9pbnRzID0gW1xuICAgICAgICAndjAvdG9wc3Rvcmllcy5qc29uJyxcbiAgICAgICAgJ3YwL25ld3N0b3JpZXMuanNvbicsXG4gICAgICAgICd2MC9iZXN0c3Rvcmllcy5qc29uJyxcbiAgICAgICAgJ3YwL2Fza3N0b3JpZXMuanNvbicsXG4gICAgICAgICd2MC9zaG93c3Rvcmllcy5qc29uJyxcbiAgICAgICAgJ3YwL2pvYnN0b3JpZXMuanNvbicsXG4gICAgICBdO1xuXG4gICAgICBlbmRwb2ludHMuZm9yRWFjaCgoZW5kcG9pbnQpID0+IHtcbiAgICAgICAgbGlzdENhY2hlLmludmFsaWRhdGUoYGxpc3Q6JHtlbmRwb2ludH1gKTtcbiAgICAgIH0pO1xuICAgIH0sXG4gICAgY2xlYXJBbGxDYWNoZXM6ICgpOiB2b2lkID0+IHtcbiAgICAgIGl0ZW1DYWNoZS5jbGVhcigpO1xuICAgICAgbGlzdENhY2hlLmNsZWFyKCk7XG4gICAgICB1c2VyQ2FjaGUuY2xlYXIoKTtcbiAgICAgIHVwZGF0ZXNDYWNoZS5jbGVhcigpO1xuICAgICAgbWF4SXRlbUNhY2hlLmNsZWFyKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJlZ2lzdGVyIGhvb2tzIHdpdGggdGhlIGNsaWVudFxuICAgICAqIEBwYXJhbSBob29rcyBPYmplY3Qgd2l0aCBiZWZvcmVGZXRjaCwgYWZ0ZXJGZXRjaCwgYW5kL29yIG9uRXJyb3IgZnVuY3Rpb25zXG4gICAgICogQHJldHVybnMgVGhlIGNsaWVudCBpbnN0YW5jZSBmb3IgY2hhaW5pbmdcbiAgICAgKlxuICAgICAqIEV4YW1wbGU6XG4gICAgICogYGBgdHNcbiAgICAgKiBjbGllbnQudXNlKHtcbiAgICAgKiAgIGJlZm9yZUZldGNoOiAodXJsLCBvcHRzKSA9PiB7XG4gICAgICogICAgIGNvbnNvbGUubG9nKGBGZXRjaGluZyAke3VybH1gKTtcbiAgICAgKiAgICAgcmV0dXJuIHsgdXJsLCBvcHRpb25zOiBvcHRzIH07XG4gICAgICogICB9LFxuICAgICAqICAgYWZ0ZXJGZXRjaDogKHJlc3BvbnNlKSA9PiB7XG4gICAgICogICAgIGNvbnNvbGUubG9nKGBSZWNlaXZlZCAke3Jlc3BvbnNlLnN0YXR1c30gZnJvbSAke3Jlc3BvbnNlLnVybH1gKTtcbiAgICAgKiAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgICAqICAgfSxcbiAgICAgKiAgIG9uRXJyb3I6IChlcnIpID0+IHtcbiAgICAgKiAgICAgY29uc29sZS5lcnJvcihgRXJyb3IgaW4gZmV0Y2g6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgICogICB9XG4gICAgICogfSk7XG4gICAgICogYGBgXG4gICAgICovXG4gICAgdXNlOiAoaG9va3M6IENsaWVudEhvb2tzKSA9PiB7XG4gICAgICBob29rc01hbmFnZXIucmVnaXN0ZXIoaG9va3MpO1xuICAgICAgcmV0dXJuIGNsaWVudDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ2xlYXIgYWxsIHJlZ2lzdGVyZWQgaG9va3NcbiAgICAgKiBAcmV0dXJucyBUaGUgY2xpZW50IGluc3RhbmNlIGZvciBjaGFpbmluZ1xuICAgICAqL1xuICAgIGNsZWFySG9va3M6ICgpID0+IHtcbiAgICAgIGhvb2tzTWFuYWdlci5jbGVhcigpO1xuICAgICAgcmV0dXJuIGNsaWVudDtcbiAgICB9LFxuICB9O1xuXG4gIHJldHVybiBjbGllbnQ7XG59O1xuXG4vLyBDcmVhdGUgZGVmYXVsdCBjbGllbnQgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHlcbmNvbnN0IGRlZmF1bHRDbGllbnQgPSBjcmVhdGVDbGllbnQoKTtcblxuLy8gRXhwb3J0IGFsbCBtZXRob2RzIGZyb20gdGhlIGRlZmF1bHQgY2xpZW50IGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5XG5leHBvcnQgY29uc3Qge1xuICBnZXRJdGVtLFxuICBnZXRJdGVtcyxcbiAgZ2V0VXNlcixcbiAgZ2V0TWF4SXRlbUlkLFxuICBnZXRVcGRhdGVzLFxuICBnZXRJdGVtV2l0aENvbW1lbnRzLFxuICBnZXRUb3BTdG9yaWVzLFxuICBnZXROZXdTdG9yaWVzLFxuICBnZXRCZXN0U3RvcmllcyxcbiAgZ2V0QXNrU3RvcmllcyxcbiAgZ2V0U2hvd1N0b3JpZXMsXG4gIGdldEpvYlN0b3JpZXMsXG4gIGludmFsaWRhdGVJdGVtQ2FjaGUsXG4gIGludmFsaWRhdGVVc2VyQ2FjaGUsXG4gIGludmFsaWRhdGVMaXN0Q2FjaGVzLFxuICBjbGVhckFsbENhY2hlcyxcbn0gPSBkZWZhdWx0Q2xpZW50O1xuIiwKICAgICIvKipcbiAqIENhY2hlIGVudHJ5IHdpdGggZGF0YSBhbmQgdGltZXN0YW1wc1xuICovXG5pbnRlcmZhY2UgQ2FjaGVFbnRyeTxUPiB7XG4gIC8qKiBUaGUgY2FjaGVkIGRhdGEgKi9cbiAgZGF0YTogVDtcbiAgLyoqIFdoZW4gdGhlIGRhdGEgd2FzIGNhY2hlZCAqL1xuICB0aW1lc3RhbXA6IG51bWJlcjtcbiAgLyoqIFdoZW4gdGhlIGRhdGEgd2FzIGxhc3QgYWNjZXNzZWQgKGZvciBMUlUgdHJhY2tpbmcpICovXG4gIGxhc3RBY2Nlc3NlZDogbnVtYmVyO1xufVxuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNhY2hlXG4gKi9cbmludGVyZmFjZSBDYWNoZU9wdGlvbnMge1xuICAvKiogTWF4aW11bSBhZ2UgaW4gbXMgZm9yIGZyZXNoIGRhdGEgKi9cbiAgbWF4QWdlOiBudW1iZXI7XG4gIC8qKiBNYXhpbXVtIGFnZSBpbiBtcyBmb3Igc3RhbGUgZGF0YSAqL1xuICBzdGFsZVdoaWxlUmV2YWxpZGF0ZTogbnVtYmVyO1xuICAvKiogTWF4aW11bSBudW1iZXIgb2YgZW50cmllcyBiZWZvcmUgTFJVIGV2aWN0aW9uICovXG4gIG1heEVudHJpZXM/OiBudW1iZXI7XG59XG5cbi8qKlxuICogSW4tbWVtb3J5IGNhY2hlIHdpdGggc3RhbGUtd2hpbGUtcmV2YWxpZGF0ZSBzZW1hbnRpY3MuXG4gKiAtIFJldHVybnMgZnJlc2ggZGF0YSBpZiB3aXRoaW4gbWF4QWdlXG4gKiAtIFJldHVybnMgc3RhbGUgZGF0YSBpZiB3aXRoaW4gc3RhbGVXaGlsZVJldmFsaWRhdGUgd2hpbGUgcmVmcmVzaGluZyBpbiB0aGUgYmFja2dyb3VuZFxuICogLSBGZXRjaGVzIG5ldyBkYXRhIGlmIGJleW9uZCBzdGFsZVdoaWxlUmV2YWxpZGF0ZVxuICovXG5leHBvcnQgY2xhc3MgQ2FjaGU8VD4ge1xuICBwcml2YXRlIGNhY2hlOiBNYXA8c3RyaW5nLCBDYWNoZUVudHJ5PFQ+PiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBvcHRpb25zOiBDYWNoZU9wdGlvbnM7XG4gIHByaXZhdGUgZmV0Y2hQcm9taXNlczogTWFwPHN0cmluZywgUHJvbWlzZTxUPj4gPSBuZXcgTWFwKCk7XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogUGFydGlhbDxDYWNoZU9wdGlvbnM+ID0ge30pIHtcbiAgICB0aGlzLm9wdGlvbnMgPSB7XG4gICAgICBtYXhBZ2U6IDYwICogMTAwMCwgLy8gMSBtaW51dGUgZGVmYXVsdFxuICAgICAgc3RhbGVXaGlsZVJldmFsaWRhdGU6IDUgKiA2MCAqIDEwMDAsIC8vIDUgbWludXRlcyBkZWZhdWx0XG4gICAgICBtYXhFbnRyaWVzOiAxMDAwLCAvLyBEZWZhdWx0IG1heCBlbnRyaWVzIHRvIHByZXZlbnQgbWVtb3J5IGxlYWtzXG4gICAgICAuLi5vcHRpb25zLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRXZpY3QgdGhlIGxlYXN0IHJlY2VudGx5IHVzZWQgZW50cmllcyBpZiB3ZSBleGNlZWQgdGhlIG1heGltdW0gc2l6ZVxuICAgKi9cbiAgcHJpdmF0ZSBldmljdExSVUlmTmVlZGVkKCk6IHZvaWQge1xuICAgIGNvbnN0IHsgbWF4RW50cmllcyB9ID0gdGhpcy5vcHRpb25zO1xuXG4gICAgLy8gU2tpcCBpZiBtYXhFbnRyaWVzIGlzIG5vdCBzZXQgb3Igd2UgaGF2ZW4ndCBleGNlZWRlZCBpdFxuICAgIGlmICghbWF4RW50cmllcyB8fCB0aGlzLmNhY2hlLnNpemUgPD0gbWF4RW50cmllcykgcmV0dXJuO1xuXG4gICAgLy8gQ2FsY3VsYXRlIGhvdyBtYW55IGVudHJpZXMgdG8gcmVtb3ZlXG4gICAgY29uc3QgZW50cmllc1RvUmVtb3ZlID0gdGhpcy5jYWNoZS5zaXplIC0gbWF4RW50cmllcztcblxuICAgIC8vIEdldCBhbGwgZW50cmllcyBhbmQgc29ydCBieSBsYXN0QWNjZXNzZWQgKG9sZGVzdCBmaXJzdClcbiAgICBjb25zdCBlbnRyaWVzID0gQXJyYXkuZnJvbSh0aGlzLmNhY2hlLmVudHJpZXMoKSlcbiAgICAgIC5tYXAoKFtrZXksIHZhbHVlXSkgPT4gKHtcbiAgICAgICAga2V5LFxuICAgICAgICAvLyBVc2UgdGltZXN0YW1wIGFzIGZhbGxiYWNrIGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5IHdpdGggZXhpc3RpbmcgY2FjaGUgZW50cmllc1xuICAgICAgICBsYXN0QWNjZXNzZWQ6IHZhbHVlLmxhc3RBY2Nlc3NlZCAhPT0gdW5kZWZpbmVkID8gdmFsdWUubGFzdEFjY2Vzc2VkIDogdmFsdWUudGltZXN0YW1wLFxuICAgICAgfSkpXG4gICAgICAuc29ydCgoYSwgYikgPT4gYS5sYXN0QWNjZXNzZWQgLSBiLmxhc3RBY2Nlc3NlZCk7XG5cbiAgICAvLyBSZW1vdmUgdGhlIG9sZGVzdCBlbnRyaWVzICh3ZSdyZSBhbHJlYWR5IGNoZWNraW5nIGkgPCBlbnRyaWVzLmxlbmd0aCBhYm92ZSlcbiAgICBlbnRyaWVzLnNsaWNlKDAsIGVudHJpZXNUb1JlbW92ZSkuZm9yRWFjaCgoZW50cnkpID0+IHtcbiAgICAgIHRoaXMuY2FjaGUuZGVsZXRlKGVudHJ5LmtleSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFuIGl0ZW0gZnJvbSB0aGUgY2FjaGUgb3IgZmV0Y2ggaXRcbiAgICogQHBhcmFtIGtleSBDYWNoZSBrZXlcbiAgICogQHBhcmFtIGZldGNoRm4gRnVuY3Rpb24gdG8gZmV0Y2ggdGhlIGRhdGEgaWYgbm90IGluIGNhY2hlXG4gICAqIEByZXR1cm5zIFRoZSBjYWNoZWQgb3IgbmV3bHkgZmV0Y2hlZCBkYXRhXG4gICAqL1xuICBhc3luYyBnZXQoa2V5OiBzdHJpbmcsIGZldGNoRm46ICgpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IGNhY2hlZEVudHJ5ID0gdGhpcy5jYWNoZS5nZXQoa2V5KTtcblxuICAgIC8vIElmIGRhdGEgaXMgZnJlc2ggKHdpdGhpbiBtYXhBZ2UpLCB1cGRhdGUgbGFzdCBhY2Nlc3NlZCB0aW1lIGFuZCByZXR1cm4gaW1tZWRpYXRlbHlcbiAgICBpZiAoY2FjaGVkRW50cnkgJiYgbm93IC0gY2FjaGVkRW50cnkudGltZXN0YW1wIDwgdGhpcy5vcHRpb25zLm1heEFnZSkge1xuICAgICAgLy8gVXBkYXRlIGxhc3QgYWNjZXNzZWQgdGltZSB3aXRob3V0IGNoYW5naW5nIHRpbWVzdGFtcFxuICAgICAgdGhpcy5jYWNoZS5zZXQoa2V5LCB7XG4gICAgICAgIC4uLmNhY2hlZEVudHJ5LFxuICAgICAgICBsYXN0QWNjZXNzZWQ6IG5vdyxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIGNhY2hlZEVudHJ5LmRhdGE7XG4gICAgfVxuXG4gICAgLy8gSWYgZGF0YSBpcyBzdGFsZSBidXQgc3RpbGwgd2l0aGluIHN0YWxlV2hpbGVSZXZhbGlkYXRlIHdpbmRvdywgcmV0dXJuIGl0IGJ1dCByZWZyZXNoIGluIGJhY2tncm91bmRcbiAgICBpZiAoY2FjaGVkRW50cnkgJiYgbm93IC0gY2FjaGVkRW50cnkudGltZXN0YW1wIDwgdGhpcy5vcHRpb25zLnN0YWxlV2hpbGVSZXZhbGlkYXRlKSB7XG4gICAgICAvLyBSZWZyZXNoIGluIGJhY2tncm91bmQgd2l0aG91dCBibG9ja2luZ1xuICAgICAgdGhpcy5yZWZyZXNoSW5CYWNrZ3JvdW5kKGtleSwgZmV0Y2hGbik7XG5cbiAgICAgIC8vIFVwZGF0ZSBsYXN0IGFjY2Vzc2VkIHRpbWUgd2l0aG91dCBjaGFuZ2luZyB0aW1lc3RhbXBcbiAgICAgIHRoaXMuY2FjaGUuc2V0KGtleSwge1xuICAgICAgICAuLi5jYWNoZWRFbnRyeSxcbiAgICAgICAgbGFzdEFjY2Vzc2VkOiBub3csXG4gICAgICB9KTtcblxuICAgICAgLy8gUmV0dXJuIHN0YWxlIGRhdGEgaW1tZWRpYXRlbHlcbiAgICAgIHJldHVybiBjYWNoZWRFbnRyeS5kYXRhO1xuICAgIH1cblxuICAgIC8vIElmIGEgZmV0Y2ggaXMgYWxyZWFkeSBpbiBwcm9ncmVzcywgcmV0dXJuIHBlbmRpbmcgcHJvbWlzZVxuICAgIGlmICh0aGlzLmZldGNoUHJvbWlzZXMuaGFzKGtleSkpIHtcbiAgICAgIGNvbnN0IHByb21pc2UgPSB0aGlzLmZldGNoUHJvbWlzZXMuZ2V0KGtleSk7XG4gICAgICBpZiAocHJvbWlzZSkgcmV0dXJuIHByb21pc2U7XG4gICAgfVxuXG4gICAgLy8gT3RoZXJ3aXNlIGZldGNoIG5ldyBkYXRhIGFuZCBibG9jayB1bnRpbCBpdCdzIGF2YWlsYWJsZVxuICAgIHJldHVybiB0aGlzLmZldGNoQW5kQ2FjaGUoa2V5LCBmZXRjaEZuKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JjZSBhIHJlZnJlc2ggb2YgdGhlIGNhY2hlZCBpdGVtXG4gICAqIEBwYXJhbSBrZXkgQ2FjaGUga2V5XG4gICAqIEBwYXJhbSBmZXRjaEZuIEZ1bmN0aW9uIHRvIGZldGNoIHRoZSBkYXRhXG4gICAqIEByZXR1cm5zIFRoZSBuZXdseSBmZXRjaGVkIGRhdGFcbiAgICovXG4gIGFzeW5jIHJlZnJlc2goa2V5OiBzdHJpbmcsIGZldGNoRm46ICgpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgICByZXR1cm4gdGhpcy5mZXRjaEFuZENhY2hlKGtleSwgZmV0Y2hGbik7XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXIgYSBzcGVjaWZpYyBpdGVtIGZyb20gdGhlIGNhY2hlXG4gICAqIEBwYXJhbSBrZXkgQ2FjaGUga2V5IHRvIGNsZWFyXG4gICAqL1xuICBpbnZhbGlkYXRlKGtleTogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5jYWNoZS5kZWxldGUoa2V5KTtcbiAgICB0aGlzLmZldGNoUHJvbWlzZXMuZGVsZXRlKGtleSk7XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXIgdGhlIGVudGlyZSBjYWNoZVxuICAgKi9cbiAgY2xlYXIoKTogdm9pZCB7XG4gICAgdGhpcy5jYWNoZS5jbGVhcigpO1xuICAgIHRoaXMuZmV0Y2hQcm9taXNlcy5jbGVhcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIGFuIGl0ZW0gZXhpc3RzIGluIHRoZSBjYWNoZVxuICAgKiBAcGFyYW0ga2V5IENhY2hlIGtleVxuICAgKiBAcmV0dXJucyBUcnVlIGlmIHRoZSBpdGVtIGV4aXN0cyBpbiB0aGUgY2FjaGVcbiAgICovXG4gIGhhcyhrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNhY2hlLmhhcyhrZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZnJlc2ggZGF0YSBpbiB0aGUgYmFja2dyb3VuZCB3aXRob3V0IGJsb2NraW5nXG4gICAqL1xuICBwcml2YXRlIHJlZnJlc2hJbkJhY2tncm91bmQoa2V5OiBzdHJpbmcsIGZldGNoRm46ICgpID0+IFByb21pc2U8VD4pOiB2b2lkIHtcbiAgICAvLyBEb24ndCBhd2FpdCAtIGludGVudGlvbmFsbHkgcnVubmluZyBpbiBiYWNrZ3JvdW5kXG4gICAgdGhpcy5mZXRjaEFuZENhY2hlKGtleSwgZmV0Y2hGbikuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAvLyBMb2cgZXJyb3JzIGluIGRldmVsb3BtZW50IGJ1dCBkb24ndCBjcmFzaCB0aGUgYXBwbGljYXRpb25cbiAgICAgIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ2RldmVsb3BtZW50Jykge1xuICAgICAgICBjb25zb2xlLmVycm9yKGBCYWNrZ3JvdW5kIGNhY2hlIHJlZnJlc2ggZmFpbGVkIGZvciBrZXkgXCIke2tleX1cIjpgLCBlcnJvcik7XG4gICAgICB9XG5cbiAgICAgIC8vIENsZWFuIHVwIHRoZSBwZW5kaW5nIHByb21pc2VcbiAgICAgIHRoaXMuZmV0Y2hQcm9taXNlcy5kZWxldGUoa2V5KTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaCBhbmQgY2FjaGUgZGF0YVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaEFuZENhY2hlKGtleTogc3RyaW5nLCBmZXRjaEZuOiAoKSA9PiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUPiB7XG4gICAgY29uc3QgZmV0Y2hQcm9taXNlID0gKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBmZXRjaEZuKCk7XG4gICAgICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG5cbiAgICAgICAgdGhpcy5jYWNoZS5zZXQoa2V5LCB7XG4gICAgICAgICAgZGF0YSxcbiAgICAgICAgICB0aW1lc3RhbXA6IG5vdyxcbiAgICAgICAgICBsYXN0QWNjZXNzZWQ6IG5vdywgLy8gSW5pdGlhbGl6ZSBsYXN0IGFjY2Vzc2VkIHRpbWVcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQ2hlY2sgaWYgd2UgbmVlZCB0byBldmljdCBvbGRlciBlbnRyaWVzXG4gICAgICAgIHRoaXMuZXZpY3RMUlVJZk5lZWRlZCgpO1xuXG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgLy8gQ2xlYW4gdXAgdGhlIGZldGNoIHByb21pc2Ugd2hlbiBkb25lXG4gICAgICAgIHRoaXMuZmV0Y2hQcm9taXNlcy5kZWxldGUoa2V5KTtcbiAgICAgIH1cbiAgICB9KSgpO1xuXG4gICAgLy8gU3RvcmUgdGhlIHByb21pc2Ugc28gd2UgZG9uJ3QgaGF2ZSBkdXBsaWNhdGUgaW4tZmxpZ2h0IHJlcXVlc3RzXG4gICAgdGhpcy5mZXRjaFByb21pc2VzLnNldChrZXksIGZldGNoUHJvbWlzZSk7XG4gICAgcmV0dXJuIGZldGNoUHJvbWlzZTtcbiAgfVxufVxuIiwKICAgICJpbXBvcnQgdHlwZSB7IFJlcXVlc3RJbmZvLCBSZXF1ZXN0SW5pdCB9IGZyb20gJy4vdHlwZXMnO1xuXG4vKipcbiAqIEhvb2sgdGhhdCBydW5zIGJlZm9yZSBhIGZldGNoIHJlcXVlc3QgaXMgbWFkZVxuICogQ2FuIG1vZGlmeSB0aGUgcmVxdWVzdCBVUkwgYW5kIG9wdGlvbnMgYmVmb3JlIHNlbmRpbmdcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCZWZvcmVGZXRjaEhvb2sge1xuICAodXJsOiBSZXF1ZXN0SW5mbywgb3B0aW9ucz86IFJlcXVlc3RJbml0KTogeyB1cmw6IFJlcXVlc3RJbmZvOyBvcHRpb25zOiBSZXF1ZXN0SW5pdCB8IHVuZGVmaW5lZCB9O1xufVxuXG4vKipcbiAqIEhvb2sgdGhhdCBydW5zIGFmdGVyIGEgc3VjY2Vzc2Z1bCBmZXRjaCByZXF1ZXN0XG4gKiBDYW4gaW5zcGVjdCBvciBtb2RpZnkgdGhlIHJlc3BvbnNlXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQWZ0ZXJGZXRjaEhvb2sge1xuICAocmVzcG9uc2U6IFJlc3BvbnNlKTogUmVzcG9uc2UgfCBQcm9taXNlPFJlc3BvbnNlPjtcbn1cblxuLyoqXG4gKiBIb29rIHRoYXQgcnVucyB3aGVuIGFuIGVycm9yIG9jY3VycyBkdXJpbmcgZmV0Y2hcbiAqIENhbiBoYW5kbGUgdGhlIGVycm9yIG9yIHRocm93IGEgZGlmZmVyZW50IG9uZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIE9uRXJyb3JIb29rIHtcbiAgKGVycm9yOiBFcnJvcik6IEVycm9yIHwgUHJvbWlzZTxFcnJvcj4gfCB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogQ29tcGxldGUgc2V0IG9mIGhvb2tzIHRoYXQgY2FuIGJlIHJlZ2lzdGVyZWQgd2l0aCB0aGUgY2xpZW50XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2xpZW50SG9va3Mge1xuICAvKipcbiAgICogUnVucyBiZWZvcmUgZWFjaCBmZXRjaCByZXF1ZXN0XG4gICAqIENhbiBtb2RpZnkgdGhlIHJlcXVlc3QgVVJMIGFuZCBvcHRpb25zXG4gICAqL1xuICBiZWZvcmVGZXRjaD86IEJlZm9yZUZldGNoSG9vaztcblxuICAvKipcbiAgICogUnVucyBhZnRlciBlYWNoIHN1Y2Nlc3NmdWwgZmV0Y2ggcmVxdWVzdFxuICAgKiBDYW4gaW5zcGVjdCBvciBtb2RpZnkgdGhlIHJlc3BvbnNlXG4gICAqL1xuICBhZnRlckZldGNoPzogQWZ0ZXJGZXRjaEhvb2s7XG5cbiAgLyoqXG4gICAqIFJ1bnMgd2hlbiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIGZldGNoXG4gICAqIENhbiBoYW5kbGUgdGhlIGVycm9yIG9yIHRocm93IGEgZGlmZmVyZW50IG9uZVxuICAgKi9cbiAgb25FcnJvcj86IE9uRXJyb3JIb29rO1xufVxuXG4vKipcbiAqIENsYXNzIHRvIG1hbmFnZSBtdWx0aXBsZSBob29rc1xuICogQWxsb3dzIHJlZ2lzdGVyaW5nIGFuZCBzZXF1ZW50aWFsbHkgcnVubmluZyBtdWx0aXBsZSBob29rc1xuICovXG5leHBvcnQgY2xhc3MgSG9va3NNYW5hZ2VyIHtcbiAgcHJpdmF0ZSBiZWZvcmVGZXRjaEhvb2tzOiBCZWZvcmVGZXRjaEhvb2tbXSA9IFtdO1xuICBwcml2YXRlIGFmdGVyRmV0Y2hIb29rczogQWZ0ZXJGZXRjaEhvb2tbXSA9IFtdO1xuICBwcml2YXRlIG9uRXJyb3JIb29rczogT25FcnJvckhvb2tbXSA9IFtdO1xuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBob29rcyB3aXRoIHRoZSBtYW5hZ2VyXG4gICAqIEBwYXJhbSBob29rcyBPYmplY3QgY29udGFpbmluZyBob29rIGZ1bmN0aW9uc1xuICAgKi9cbiAgcHVibGljIHJlZ2lzdGVyKGhvb2tzOiBDbGllbnRIb29rcyk6IHZvaWQge1xuICAgIGlmIChob29rcy5iZWZvcmVGZXRjaCkge1xuICAgICAgdGhpcy5iZWZvcmVGZXRjaEhvb2tzLnB1c2goaG9va3MuYmVmb3JlRmV0Y2gpO1xuICAgIH1cblxuICAgIGlmIChob29rcy5hZnRlckZldGNoKSB7XG4gICAgICB0aGlzLmFmdGVyRmV0Y2hIb29rcy5wdXNoKGhvb2tzLmFmdGVyRmV0Y2gpO1xuICAgIH1cblxuICAgIGlmIChob29rcy5vbkVycm9yKSB7XG4gICAgICB0aGlzLm9uRXJyb3JIb29rcy5wdXNoKGhvb2tzLm9uRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBVbnJlZ2lzdGVyIGFsbCBob29rc1xuICAgKi9cbiAgcHVibGljIGNsZWFyKCk6IHZvaWQge1xuICAgIHRoaXMuYmVmb3JlRmV0Y2hIb29rcyA9IFtdO1xuICAgIHRoaXMuYWZ0ZXJGZXRjaEhvb2tzID0gW107XG4gICAgdGhpcy5vbkVycm9ySG9va3MgPSBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW4gYWxsIHJlZ2lzdGVyZWQgYmVmb3JlRmV0Y2ggaG9va3MgaW4gc2VxdWVuY2VcbiAgICogQHBhcmFtIHVybCBUaGUgcmVxdWVzdCBVUkxcbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIHJlcXVlc3Qgb3B0aW9uc1xuICAgKiBAcmV0dXJucyBNb2RpZmllZCBVUkwgYW5kIG9wdGlvbnNcbiAgICovXG4gIHB1YmxpYyBhc3luYyBydW5CZWZvcmVGZXRjaEhvb2tzKFxuICAgIHVybDogUmVxdWVzdEluZm8sXG4gICAgb3B0aW9ucz86IFJlcXVlc3RJbml0LFxuICApOiBQcm9taXNlPHsgdXJsOiBSZXF1ZXN0SW5mbzsgb3B0aW9uczogUmVxdWVzdEluaXQgfCB1bmRlZmluZWQgfT4ge1xuICAgIGxldCByZXN1bHQgPSB7IHVybCwgb3B0aW9ucyB9O1xuXG4gICAgZm9yIChjb25zdCBob29rIG9mIHRoaXMuYmVmb3JlRmV0Y2hIb29rcykge1xuICAgICAgcmVzdWx0ID0gaG9vayhyZXN1bHQudXJsLCByZXN1bHQub3B0aW9ucyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW4gYWxsIHJlZ2lzdGVyZWQgYWZ0ZXJGZXRjaCBob29rcyBpbiBzZXF1ZW5jZVxuICAgKiBAcGFyYW0gcmVzcG9uc2UgVGhlIGZldGNoIHJlc3BvbnNlXG4gICAqIEByZXR1cm5zIE1vZGlmaWVkIHJlc3BvbnNlXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgcnVuQWZ0ZXJGZXRjaEhvb2tzKHJlc3BvbnNlOiBSZXNwb25zZSk6IFByb21pc2U8UmVzcG9uc2U+IHtcbiAgICBsZXQgcmVzdWx0ID0gcmVzcG9uc2U7XG5cbiAgICBmb3IgKGNvbnN0IGhvb2sgb2YgdGhpcy5hZnRlckZldGNoSG9va3MpIHtcbiAgICAgIHJlc3VsdCA9IGF3YWl0IGhvb2socmVzdWx0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1biBhbGwgcmVnaXN0ZXJlZCBvbkVycm9yIGhvb2tzIGluIHNlcXVlbmNlXG4gICAqIEBwYXJhbSBlcnJvciBUaGUgZXJyb3IgdGhhdCBvY2N1cnJlZFxuICAgKiBAcmV0dXJucyBUaGUgcG9zc2libHkgbW9kaWZpZWQgZXJyb3JcbiAgICovXG4gIHB1YmxpYyBhc3luYyBydW5PbkVycm9ySG9va3MoZXJyb3I6IEVycm9yKTogUHJvbWlzZTxFcnJvcj4ge1xuICAgIGxldCBjdXJyZW50RXJyb3IgPSBlcnJvcjtcblxuICAgIGZvciAoY29uc3QgaG9vayBvZiB0aGlzLm9uRXJyb3JIb29rcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgaG9vayhjdXJyZW50RXJyb3IpO1xuICAgICAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICBjdXJyZW50RXJyb3IgPSByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGUgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICAgIGN1cnJlbnRFcnJvciA9IGU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gY3VycmVudEVycm9yO1xuICB9XG59XG4iLAogICAgImltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xuaW1wb3J0IHR5cGUge1xuICBIYWNrZXJOZXdzSWQsXG4gIEhhY2tlck5ld3NJZExpc3QsXG4gIEhhY2tlck5ld3NJdGVtLFxuICBIYWNrZXJOZXdzSXRlbVR5cGUsXG4gIEhhY2tlck5ld3NVcGRhdGVzLFxuICBIYWNrZXJOZXdzVXNlcixcbiAgSGFja2VyTmV3c1VzZXJuYW1lLFxufSBmcm9tICcuL3R5cGVzJztcblxuLyoqXG4gKiBAZmlsZSBEZWZpbmVzIHNjaGVtYXMgZm9yIEhhY2tlciBOZXdzIEFQSSByZXNwb25zZXMgdXNpbmcgWm9kLlxuICpcbiAqIFRoaXMgZmlsZSBjb250YWlucyBUeXBlU2NyaXB0IGRlZmluaXRpb25zIGFuZCBab2Qgc2NoZW1hcyBmb3IgdmFsaWRhdGl