rehiver
Version:
Super-charge your S3 hive partitioned based file operations with intelligent pattern matching, change detection, optimized data-fetching, and out-of-the-box time series support.
2 lines • 141 kB
JavaScript
"use strict";var X=Object.create;var k=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var ee=Object.getOwnPropertyNames;var te=Object.getPrototypeOf,ne=Object.prototype.hasOwnProperty;var re=(a,e)=>{for(var t in e)k(a,t,{get:e[t],enumerable:!0})},H=(a,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of ee(e))!ne.call(a,n)&&n!==t&&k(a,n,{get:()=>e[n],enumerable:!(r=_(e,n))||r.enumerable});return a};var S=(a,e,t)=>(t=a!=null?X(te(a)):{},H(e||!a||!a.__esModule?k(t,"default",{value:a,enumerable:!0}):t,a)),se=a=>H(k({},"__esModule",{value:!0}),a);var le={};re(le,{ChangeDetectionEngine:()=>M,ChangeType:()=>Y,ConsoleLogger:()=>q,ContentType:()=>K,HivePartitionParser:()=>R,LogLevel:()=>W,NoopLogger:()=>F,PathMatcher:()=>z,Rehiver:()=>O,S3PathMatcher:()=>D,TimeGranularity:()=>J,TimePartitionGenerator:()=>b,decodeS3Key:()=>w,default:()=>ge,encodeS3Key:()=>ce,getGlobalLogger:()=>ae,isValidBucketName:()=>V,setGlobalLogger:()=>ie});module.exports=se(le);var L=S(require("fs/promises")),I=S(require("path")),y=require("@aws-sdk/client-s3"),U=require("lru-cache"),T=S(require("micromatch")),$=S(require("mime-types")),B=S(require("p-limit"));function V(a){return!(!a||a.length<3||a.length>63||!/^[a-z0-9].*[a-z0-9]$/i.test(a)||!/^[a-z0-9.-]+$/i.test(a)||a.includes("..")||/^\d+\.\d+\.\d+\.\d+$/.test(a)||a.startsWith("xn--")||a.endsWith("-s3alias"))}var W=(s=>(s[s.Debug=0]="Debug",s[s.Info=1]="Info",s[s.Warn=2]="Warn",s[s.Error=3]="Error",s[s.None=100]="None",s))(W||{}),K={detect(a){return $.default.lookup(a)||"application/octet-stream"},charset(a){return $.default.charset(a)||null},extension(a){return $.default.extension(a)},isText(a){return a.startsWith("text/")||a==="application/json"||a==="application/xml"||a==="application/javascript"||a==="application/typescript"},isBinary(a){return!this.isText(a)}},q=class{level=1;constructor(e){e!==void 0&&(this.level=e)}debug(e,...t){this.level<=0&&console.debug(`[DEBUG] ${e}`,...t)}info(e,...t){this.level<=1&&console.info(`[INFO] ${e}`,...t)}warn(e,...t){this.level<=2&&console.warn(`[WARN] ${e}`,...t)}error(e,...t){this.level<=3&&console.error(`[ERROR] ${e}`,...t)}setLevel(e){this.level=e}getLevel(){return this.level}},F=class{debug(){}info(){}warn(){}error(){}setLevel(){}getLevel(){return 100}},j=new q;function ie(a){j=a}function ae(){return j}var oe=a=>new Promise(e=>setTimeout(e,a));async function A(a,e=5,t=100,r=3e4,n=j){let s;for(let i=0;i<e;i++)try{return await a()}catch(o){s=o;let c=(o==null?void 0:o.Code)||(o==null?void 0:o.code),g=(o==null?void 0:o.message)||"";if(!(c==="ThrottlingException"||c==="RequestTimeout"||c==="NetworkingError"||c==="TimeoutError"||c==="RequestTimeTooSkewed"||c==="ProvisionedThroughputExceededException"||c==="SlowDown"||c==="InternalError"||c==="ServiceUnavailable"||c==="429"||c==="500"||c==="503"||g.includes("timeout")||g.includes("throttl")||g.includes("network")||g.includes("connection")))throw o;let C=Math.min(r,t*2**i*(.8+Math.random()*.4));n.debug(`S3 operation failed (attempt ${i+1}/${e}), retrying in ${Math.round(C)}ms: ${c||g}`),await oe(C)}throw s}function ce(a){return a.split("/").map(e=>encodeURIComponent(e)).join("/")}function w(a){return a.split("/").map(e=>decodeURIComponent(e)).join("/")}var Y=(n=>(n.Added="added",n.Modified="modified",n.Deleted="deleted",n.Unchanged="unchanged",n))(Y||{}),M=class{previousState=new Map;currentState=new Map;options;constructor(e={}){this.options={stateFilePath:"change-detection-state.json",compareMode:"full",ignoreEtagOnSize:!1,trackDeleted:!0,...e}}async loadPreviousState(){if(this.options.stateFilePath)try{let e=await L.default.readFile(this.options.stateFilePath,"utf-8"),t=JSON.parse(e);this.previousState=new Map(Object.entries(t).map(([r,n])=>{let s=n;return s.lastModified&&typeof s.lastModified=="string"&&(s.lastModified=new Date(s.lastModified)),[r,s]}))}catch{this.previousState=new Map}}async saveCurrentState(){if(!this.options.stateFilePath)return;let e=Object.fromEntries(this.currentState),t=JSON.stringify(e,null,2),r=I.default.dirname(this.options.stateFilePath);await L.default.mkdir(r,{recursive:!0}),await L.default.writeFile(this.options.stateFilePath,t,"utf-8")}addObject(e){this.currentState.set(e.key,e)}addObjects(e){for(let t of e)this.addObject(t)}static fromS3Object(e){return{key:e.key||"",size:e.size||0,etag:(e.etag||"").replace(/"/g,""),lastModified:e.lastModified||new Date}}hasObjectChanged(e,t){return this.options.compareMode==="quick"?e.size!==t.size||e.lastModified.getTime()!==t.lastModified.getTime():this.options.ignoreEtagOnSize&&e.size===t.size?e.lastModified.getTime()!==t.lastModified.getTime():e.size!==t.size||e.etag!==t.etag||e.lastModified.getTime()!==t.lastModified.getTime()}detectChanges(){let e=[];return this.currentState.forEach((t,r)=>{let n=this.previousState.get(r);n?this.hasObjectChanged(t,n)?e.push({changeType:"modified",object:t,previousVersion:n}):e.push({changeType:"unchanged",object:t,previousVersion:n}):e.push({changeType:"added",object:t})}),this.options.trackDeleted&&this.previousState.forEach((t,r)=>{this.currentState.has(r)||e.push({changeType:"deleted",object:t})}),e}static filterChangesByType(e,t){return e.filter(r=>t.includes(r.changeType))}commitChanges(){this.previousState=new Map(this.currentState)}resetCurrentState(){this.currentState=new Map}resetAllState(){this.previousState=new Map,this.currentState=new Map}},z=class{constructor(e={}){this.options=e}patternCache=new Map;isMatch(e,t,r){return T.default.isMatch(e,t,{...this.options,...r})}match(e,t,r){return(0,T.default)(e,t,{...this.options,...r})}getRegex(e,t){let r=`${e}:${JSON.stringify({...this.options,...t})}`;if(!this.patternCache.has(r)){let s=T.default.makeRe(e,{...this.options,...t});this.patternCache.set(r,s)}let n=this.patternCache.get(r);if(!n)throw new Error(`Failed to create or retrieve regex for pattern: ${e}`);return n}matchFast(e,t,r){let s=(Array.isArray(t)?t:[t]).map(i=>this.getRegex(i,r));return e.filter(i=>s.some(o=>o.test(i)))}not(e,t,r){return T.default.not(e,t,{...this.options,...r})}all(e,t,r){return T.default.all(e,t,{...this.options,...r})}capture(e,t,r){let n=/:[^\/\.]+/g,s=e.match(n)||[],i=e.replace(/\//g,"\\/");i=i.replace(/\./g,"\\.");for(let g of s)i=i.replace(g,"([^/\\.]+)");i=i.replace(/\*/g,"([^/]+)");let o=new RegExp(`^${i}$`,r!=null&&r.nocase?"i":""),c=t.match(o);return c?c.slice(1):null}},D=class extends z{s3Client;metadataCache;cacheConfig;pendingRefreshes=new Set;logger;constructor(e={},t={},r={},n=j){super(e),this.logger=n,this.s3Client=new y.S3Client({region:t.region||"us-east-1",endpoint:t.endpoint,credentials:t.credentials,forcePathStyle:t.forcePathStyle,maxAttempts:t.maxRetries||3}),this.cacheConfig={enabled:r.enabled??!0,maxSize:r.maxSize??1e3,ttl:r.ttl??5*60*1e3,refreshThreshold:r.refreshThreshold??80},this.metadataCache=new U.LRUCache({max:this.cacheConfig.maxSize,ttl:this.cacheConfig.ttl})}validateBucket(e){if(!V(e))throw new Error(`Invalid bucket name: ${e}. S3 bucket names must be 3-63 characters, contain only lowercase letters, numbers, periods, and hyphens, and cannot be formatted as an IP address.`)}async getObjectMetadata(e,t){this.validateBucket(e);let r=t.includes("%")?w(t):t,n=`${e}:${r}`;if(this.cacheConfig.enabled){let s=this.metadataCache.get(n);if(s){let i=Date.now()-(this.metadataCache.getRemainingTTL(n)||0),o=this.cacheConfig.ttl*(this.cacheConfig.refreshThreshold/100);return i>o&&!this.pendingRefreshes.has(n)&&(this.pendingRefreshes.add(n),this.refreshMetadataInBackground(e,r,n)),s}}try{let s=await A(async()=>{var i;try{let o=new y.HeadObjectCommand({Bucket:e,Key:r}),c=await this.s3Client.send(o);return{key:r,size:c.ContentLength||0,etag:c.ETag?c.ETag.replace(/^"(.+)"$/,"$1"):"",lastModified:c.LastModified||new Date,contentType:c.ContentType||K.detect(r)}}catch(o){if(typeof o=="object"&&o!==null&&(o.name==="NotFound"||((i=o.$metadata)==null?void 0:i.httpStatusCode)===404))return null;throw o}},5,100,3e4,this.logger);return s&&this.cacheConfig.enabled&&this.metadataCache.set(n,s),s}catch(s){return this.logger.error(`Error fetching S3 object metadata: ${s}`),null}finally{this.pendingRefreshes.delete(n)}}async refreshMetadataInBackground(e,t,r){try{let n=new y.HeadObjectCommand({Bucket:e,Key:t}),s=await this.s3Client.send(n),i={key:t,size:s.ContentLength||0,etag:s.ETag?s.ETag.replace(/^"(.+)"$/,"$1"):"",lastModified:s.LastModified||new Date,contentType:s.ContentType||K.detect(t)};this.metadataCache.set(r,i)}catch(n){this.logger.debug(`Background refresh failed for ${r}: ${n}`)}finally{this.pendingRefreshes.delete(r)}}invalidateCache(e,t){if(this.cacheConfig.enabled){let r=t.includes("%")?w(t):t;this.metadataCache.delete(`${e}:${r}`)}}clearCache(){this.cacheConfig.enabled&&(this.metadataCache.clear(),this.pendingRefreshes.clear())}async listObjects(e,t="",r={}){this.validateBucket(e);let{maxConcurrentRequests:n=5,maxKeysPerRequest:s=1e3,abortSignal:i}=r,o=new Set,c=[void 0],g=(0,B.default)(n),l=[],C=async(x,P)=>{try{let d=await A(()=>x.send(new y.ListObjectsV2Command(P)),5,100,3e4,this.logger),h=[];if(d.Contents){for(let u of d.Contents)if(u.Key){let p=u.Key.includes("%")?w(u.Key):u.Key;h.push(p)}}return{objects:h,nextToken:d.NextContinuationToken}}catch(d){throw this.logger.error(`Error listing S3 objects: ${d}`),d}};for(;c.length>0&&!(i!=null&&i.aborted);){let x=c.shift(),P=g(async()=>{if(i!=null&&i.aborted)return;let d={Bucket:e,Prefix:t,MaxKeys:s};x&&(d.ContinuationToken=x);try{let{objects:h,nextToken:u}=await C(this.s3Client,d);for(let p of h)o.add(p);u&&c.push(u)}catch(h){this.logger.error(`Error processing page: ${h}`)}});l.push(P)}if(await Promise.all(l),i!=null&&i.aborted)throw new Error("S3 object listing was aborted");return Array.from(o)}async putObject(e,t,r,n={}){this.validateBucket(e);let s=n.contentType||K.detect(t);try{let i=new y.PutObjectCommand({Bucket:e,Key:t,Body:r,ContentType:s,ContentEncoding:n.contentEncoding,ContentDisposition:n.contentDisposition,CacheControl:n.cacheControl,Metadata:n.metadata,Tagging:n.tagging}),o=await A(()=>this.s3Client.send(i),5,100,3e4,this.logger);return this.invalidateCache(e,t),o.ETag?o.ETag.replace(/^"(.+)"$/,"$1"):""}catch(i){throw this.logger.error(`Error uploading object to S3: ${i}`),i}}async findMatchingObjects(e,t,r){let n,s,i={};typeof e=="string"?(n=e,s=t||"**",i=r||{}):(n=e.bucket,s=e.patterns,i={prefix:e.prefix,maxConcurrentRequests:e.maxConcurrentRequests,maxKeysPerRequest:e.maxKeysPerRequest,matchOptions:e.matchOptions,useNegation:e.useNegation,abortSignal:e.abortSignal,onProgress:e.onProgress,concurrency:e.concurrency,localCache:e.localCache,handleSpecialChars:e.handleSpecialChars}),this.validateBucket(n);let{prefix:o="",maxConcurrentRequests:c=5,maxKeysPerRequest:g=1e3,matchOptions:l={},useNegation:C=!1,abortSignal:x,onProgress:P,concurrency:d={},localCache:h={enabled:!1,basePath:""},handleSpecialChars:u=!0}=i,p=await this.listObjects(n,o,{maxConcurrentRequests:d.requestLimit||c,maxKeysPerRequest:g,abortSignal:x});u&&(p=p.map(f=>f.includes("%")?w(f):f));let v;return C?v=this.not(p,s,l):v=this.match(p,s,l),P&&P({processed:p.length,total:p.length,matched:v.length,skippedExisting:0}),v}async streamMatchingObjects(e,t,r,n){let s,i,o,c={};typeof e=="string"?(s=e,i=t||"**",o=r||(async()=>{}),c=n||{}):(s=e.bucket,i=e.patterns,o=e.processor,c={prefix:e.prefix,batchSize:e.batchSize,maxConcurrentRequests:e.maxConcurrentRequests,maxKeysPerRequest:e.maxKeysPerRequest,matchOptions:e.matchOptions,maxConcurrentProcessing:e.maxConcurrentProcessing,abortSignal:e.abortSignal,onProgress:e.onProgress,localCache:e.localCache,handleSpecialChars:e.handleSpecialChars}),this.validateBucket(s);let{prefix:g="",batchSize:l=100,maxConcurrentRequests:C=5,maxKeysPerRequest:x=1e3,matchOptions:P={},maxConcurrentProcessing:d=10,abortSignal:h,onProgress:u,localCache:p={enabled:!1,basePath:""},handleSpecialChars:v=!0}=c,f=await this.findMatchingObjects({bucket:s,patterns:i,prefix:g,maxConcurrentRequests:C,maxKeysPerRequest:x,matchOptions:P,abortSignal:h,handleSpecialChars:v}),N=(0,B.default)(d),m={processed:0,matched:f.length,skipped:0,skippedExisting:0};for(let E=0;E<f.length&&!(h!=null&&h.aborted);E+=l){let Z=f.slice(E,E+l).map(G=>N(async()=>{if(!(h!=null&&h.aborted)){try{await o(G),m.processed++}catch(Q){console.warn(`Error processing object ${G}: ${Q}`),m.skipped++}u&&(m.processed+m.skipped)%100===0&&u({processed:m.processed+m.skipped,total:f.length,matched:m.matched,skippedExisting:m.skippedExisting})}}));await Promise.all(Z),u&&u({processed:m.processed+m.skipped,total:f.length,matched:m.matched,skippedExisting:m.skippedExisting})}return m}},R=class{schema;partitionKeys;constructor(e){this.schema=e,this.partitionKeys=Object.keys(e.shape||{})}parse(e){let t=e.split("/").filter(n=>n.length>0),r={};for(let n of t)if(n.includes("=")){let[s,i]=n.split("=",2);s&&i!==void 0&&(r[s]=i)}return this.schema.parse(r)}safeParse(e){let t=e.split("/").filter(n=>n.length>0),r={};for(let n of t)if(n.includes("=")){let[s,i]=n.split("=",2);s&&i!==void 0&&(r[s]=i)}return this.schema.safeParse(r)}format(e){let t=this.schema.parse(e),r=[];for(let n of this.partitionKeys){let s=t[n];s!==void 0&&r.push(`${n}=${s}`)}return r.join("/")}createGlobPattern(e){let t=[];for(let r of this.partitionKeys){let n=r;n in e&&e[n]!==void 0?t.push(`${r}=${e[n]}`):t.push(`${r}=*`)}return t.join("/")}isValid(e){return this.safeParse(e).success}getValidationErrors(e){let t=this.safeParse(e);return t.success?[]:t.error.errors.map(r=>`${r.path.join(".")}: ${r.message}`)}getMissingKeys(e){let t=e.split("/").filter(n=>n.length>0),r=new Set;for(let n of t)if(n.includes("=")){let[s]=n.split("=",1);s&&r.add(s)}return this.partitionKeys.filter(n=>!r.has(n))}extractKeys(e,t){let r=this.safeParse(e);if(!r.success)throw new Error(`Invalid partition path: ${e}`);let n={};for(let s of t)s in r.data&&(n[s]=r.data[s]);return n}transform(e,t){let r=this.parse(e),n={...r,...t(r)};return this.format(n)}matchesGlob(e,t){let r=e.split("/").filter(s=>s.length>0),n=t.split("/").filter(s=>s.length>0);if(r.length!==n.length)return!1;for(let s=0;s<r.length;s++){let i=r[s],o=n[s];if(!this.segmentMatchesPattern(i,o))return!1}return!0}segmentMatchesPattern(e,t){if(e===t)return!0;if(t.includes("=*")){let[n]=t.split("=",1),[s]=e.split("=",1);return n===s}return new RegExp(`^${t.replace(/\*/g,".*").replace(/\?/g,".")}$`).test(e)}},J=(n=>(n.Hourly="hourly",n.Daily="daily",n.Monthly="monthly",n.Yearly="yearly",n))(J||{}),b=class{config;constructor(e){this.config={includeHour:!1,includeMinute:!1,format:"hive",prefix:"",dateFormat:{year:"yyyy",month:"MM",day:"dd",hour:"HH",minute:"mm"},...e},this.config.granularity!=="hourly"&&this.config.includeMinute&&(this.config.includeHour=!0),this.config.granularity==="hourly"&&(this.config.includeHour=!0)}generatePath(e=new Date){let t=e.getFullYear().toString(),r=(e.getMonth()+1).toString().padStart(2,"0"),n=e.getDate().toString().padStart(2,"0"),s=e.getHours().toString().padStart(2,"0"),i=e.getMinutes().toString().padStart(2,"0"),o=[],{format:c,prefix:g,granularity:l}=this.config;return g&&g.length>0&&o.push(g),c==="hive"?o.push(`year=${t}`):o.push(t),(l==="monthly"||l==="daily"||l==="hourly")&&(c==="hive"?o.push(`month=${r}`):o.push(r)),(l==="daily"||l==="hourly")&&(c==="hive"?o.push(`day=${n}`):o.push(n)),this.config.includeHour&&(c==="hive"?o.push(`hour=${s}`):o.push(s)),this.config.includeMinute&&(c==="hive"?o.push(`minute=${i}`):o.push(i)),o.join("/")}generatePathsForRange(e,t){let r=[],n=new Date(e);for(;n<=t;)switch(r.push(this.generatePath(n)),this.config.granularity){case"yearly":n.setFullYear(n.getFullYear()+1);break;case"monthly":n.setMonth(n.getMonth()+1);break;case"daily":n.setDate(n.getDate()+1);break;case"hourly":n.setHours(n.getHours()+1);break;default:n.setDate(n.getDate()+1)}return r}generateCurrentPath(){return this.generatePath(new Date)}},O=class a extends D{static partition={create:e=>new R(e)};static time={daily:e=>new b({granularity:"daily",...e}),hourly:e=>new b({granularity:"hourly",...e}),monthly:e=>new b({granularity:"monthly",...e}),yearly:e=>new b({granularity:"yearly",...e}),custom:e=>new b(e)};static changes={detect:e=>new M(e)};partition=a.partition;time=a.time;changes=a.changes;logger;constructor(e={}){var r,n;let t=((r=e.loggerOptions)==null?void 0:r.logger)||j;super(e.matchOptions||{},e.s3Options||{},e.cacheOptions||{},t),this.logger=t,((n=e.loggerOptions)==null?void 0:n.level)!==void 0&&this.logger.setLevel(e.loggerOptions.level)}setLogger(e){Object.defineProperty(this,"logger",{value:e,writable:!0,configurable:!0})}getLogger(){return this.logger}partitionParser(e){return new R(e)}timePartitioner(e){return new b(e)}changeDetector(e={}){return new M(e)}isMatch(e,t,r){return super.isMatch(e,t,r)}match(e,t,r){return super.match(e,t,r)}matchFast(e,t,r){return super.matchFast(e,t,r)}not(e,t,r){return super.not(e,t,r)}capture(e,t,r){return super.capture(e,t,r)}async findMatchingObjects(e,t,r){if(typeof e=="object"){let{bucket:s,patterns:i,...o}=e;this.validateBucket(s);let c={handleSpecialChars:!0,...o};return super.findMatchingObjects(s,i,c)}this.validateBucket(e);let n={handleSpecialChars:!0,...r};return super.findMatchingObjects(e,t||"",n)}async streamMatchingObjects(e,t,r,n){if(typeof e=="object"){let{bucket:s,patterns:i,processor:o,...c}=e;return super.streamMatchingObjects(s,i,o,c)}if(!r)throw new Error("Processor function is required when using positional parameters");return super.streamMatchingObjects(e,t||"",r,n||{})}},ge=O;0&&(module.exports={ChangeDetectionEngine,ChangeType,ConsoleLogger,ContentType,HivePartitionParser,LogLevel,NoopLogger,PathMatcher,Rehiver,S3PathMatcher,TimeGranularity,TimePartitionGenerator,decodeS3Key,encodeS3Key,getGlobalLogger,isValidBucketName,setGlobalLogger});
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2luZGV4LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJpbXBvcnQgZnMgZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7XG5cdEhlYWRPYmplY3RDb21tYW5kLFxuXHRMaXN0T2JqZWN0c1YyQ29tbWFuZCxcblx0dHlwZSBMaXN0T2JqZWN0c1YyQ29tbWFuZElucHV0LFxuXHRQdXRPYmplY3RDb21tYW5kLFxuXHRTM0NsaWVudCxcbn0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zM1wiO1xuaW1wb3J0IHsgTFJVQ2FjaGUgfSBmcm9tIFwibHJ1LWNhY2hlXCI7XG5pbXBvcnQgbWljcm9tYXRjaCBmcm9tIFwibWljcm9tYXRjaFwiO1xuaW1wb3J0IG1pbWUgZnJvbSBcIm1pbWUtdHlwZXNcIjtcbmltcG9ydCBwTGltaXQgZnJvbSBcInAtbGltaXRcIjtcbmltcG9ydCB0eXBlIHsgeiB9IGZyb20gXCJ6b2RcIjtcblxuLy8gSGVscGVyIGZ1bmN0aW9uIHRvIGNoZWNrIGlmIGEgZmlsZSBleGlzdHNcbmNvbnN0IHBhdGhFeGlzdHMgPSBhc3luYyAoZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4gPT4ge1xuXHR0cnkge1xuXHRcdGF3YWl0IGZzLmFjY2VzcyhmaWxlUGF0aCk7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH0gY2F0Y2ggKGUpIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cbn07XG5cbi8qKlxuICogVmFsaWRhdGUgUzMgYnVja2V0IG5hbWUgYWNjb3JkaW5nIHRvIEFXUyBuYW1pbmcgcnVsZXNcbiAqIEBwYXJhbSBidWNrZXROYW1lIE5hbWUgb2YgdGhlIGJ1Y2tldCB0byB2YWxpZGF0ZVxuICogQHJldHVybnMgVHJ1ZSBpZiB2YWxpZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1ZhbGlkQnVja2V0TmFtZShidWNrZXROYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcblx0Ly8gQVdTIGJ1Y2tldCBuYW1pbmcgcnVsZXNcblx0Ly8gLSAzLTYzIGNoYXJhY3RlcnMgbG9uZ1xuXHQvLyAtIENhbiBjb250YWluIGxvd2VyY2FzZSBsZXR0ZXJzLCBudW1iZXJzLCBkb3RzLCBhbmQgaHlwaGVuc1xuXHQvLyAtIE11c3Qgc3RhcnQgYW5kIGVuZCB3aXRoIGEgbGV0dGVyIG9yIG51bWJlclxuXHQvLyAtIENhbm5vdCBjb250YWluIHR3byBhZGphY2VudCBwZXJpb2RzXG5cdC8vIC0gQ2Fubm90IGJlIGZvcm1hdHRlZCBhcyBhbiBJUCBhZGRyZXNzIChlLmcuLCAxOTIuMTY4LjUuNClcblx0Ly8gLSBDYW5ub3Qgc3RhcnQgd2l0aCB0aGUgcHJlZml4ICd4bi0tJ1xuXHQvLyAtIENhbm5vdCBlbmQgd2l0aCB0aGUgc3VmZml4ICctczNhbGlhcydcblxuXHRpZiAoIWJ1Y2tldE5hbWUgfHwgYnVja2V0TmFtZS5sZW5ndGggPCAzIHx8IGJ1Y2tldE5hbWUubGVuZ3RoID4gNjMpIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHQvLyBDaGVjayBpZiBzdGFydHMvZW5kcyB3aXRoIGxldHRlciBvciBudW1iZXJcblx0aWYgKCEvXlthLXowLTldLipbYS16MC05XSQvaS50ZXN0KGJ1Y2tldE5hbWUpKSB7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG5cblx0Ly8gQ2hlY2sgZm9yIHZhbGlkIGNoYXJhY3RlcnNcblx0aWYgKCEvXlthLXowLTkuLV0rJC9pLnRlc3QoYnVja2V0TmFtZSkpIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHQvLyBDaGVjayBmb3IgYWRqYWNlbnQgcGVyaW9kc1xuXHRpZiAoYnVja2V0TmFtZS5pbmNsdWRlcyhcIi4uXCIpKSB7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG5cblx0Ly8gQ2hlY2sgZm9yIElQIGFkZHJlc3MgZm9ybWF0XG5cdGlmICgvXlxcZCtcXC5cXGQrXFwuXFxkK1xcLlxcZCskLy50ZXN0KGJ1Y2tldE5hbWUpKSB7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG5cblx0Ly8gQ2hlY2sgZm9yIGZvcmJpZGRlbiBwcmVmaXhlcy9zdWZmaXhlc1xuXHRpZiAoYnVja2V0TmFtZS5zdGFydHNXaXRoKFwieG4tLVwiKSB8fCBidWNrZXROYW1lLmVuZHNXaXRoKFwiLXMzYWxpYXNcIikpIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHRyZXR1cm4gdHJ1ZTtcbn1cblxuLyoqXG4gKiBMb2cgbGV2ZWxzIGZvciB0aGUgbG9nZ2VyXG4gKi9cbmV4cG9ydCBlbnVtIExvZ0xldmVsIHtcblx0RGVidWcgPSAwLFxuXHRJbmZvID0gMSxcblx0V2FybiA9IDIsXG5cdEVycm9yID0gMyxcblx0Tm9uZSA9IDEwMCxcbn1cblxuLyoqXG4gKiBMb2dnZXIgaW50ZXJmYWNlIGZvciBjdXN0b20gbG9nZ2luZyBpbXBsZW1lbnRhdGlvbnNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2dnZXIge1xuXHRkZWJ1ZyhtZXNzYWdlOiBzdHJpbmcsIC4uLmFyZ3M6IHVua25vd25bXSk6IHZvaWQ7XG5cdGluZm8obWVzc2FnZTogc3RyaW5nLCAuLi5hcmdzOiB1bmtub3duW10pOiB2b2lkO1xuXHR3YXJuKG1lc3NhZ2U6IHN0cmluZywgLi4uYXJnczogdW5rbm93bltdKTogdm9pZDtcblx0ZXJyb3IobWVzc2FnZTogc3RyaW5nLCAuLi5hcmdzOiB1bmtub3duW10pOiB2b2lkO1xuXHRzZXRMZXZlbChsZXZlbDogTG9nTGV2ZWwpOiB2b2lkO1xuXHRnZXRMZXZlbCgpOiBMb2dMZXZlbDtcbn1cblxuLyoqXG4gKiBDb250ZW50IHR5cGUgZGV0ZWN0aW9uIGFuZCBoYW5kbGluZyB1dGlsaXRpZXNcbiAqL1xuZXhwb3J0IGNvbnN0IENvbnRlbnRUeXBlID0ge1xuXHQvKipcblx0ICogRGV0ZWN0IGNvbnRlbnQgdHlwZSBmcm9tIGEgZmlsZSBwYXRoIG9yIGtleVxuXHQgKiBAcGFyYW0gcGF0aCBQYXRoIG9yIGtleSB0byBkZXRlcm1pbmUgY29udGVudCB0eXBlIGZyb21cblx0ICogQHJldHVybnMgVGhlIGRldGVjdGVkIE1JTUUgdHlwZSBvciBhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0gaWYgdW5rbm93blxuXHQgKi9cblx0ZGV0ZWN0KHBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG5cdFx0Y29uc3QgY29udGVudFR5cGUgPSBtaW1lLmxvb2t1cChwYXRoKTtcblx0XHRyZXR1cm4gY29udGVudFR5cGUgfHwgXCJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW1cIjtcblx0fSxcblxuXHQvKipcblx0ICogR2V0IGNoYXJzZXQgZm9yIGEgZ2l2ZW4gY29udGVudCB0eXBlXG5cdCAqIEBwYXJhbSBjb250ZW50VHlwZSBNSU1FIHR5cGUgdG8gZ2V0IGNoYXJzZXQgZm9yXG5cdCAqIEByZXR1cm5zIENoYXJzZXQgc3RyaW5nIG9yIG51bGwgaWYgbm90IGFwcGxpY2FibGVcblx0ICovXG5cdGNoYXJzZXQoY29udGVudFR5cGU6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuXHRcdHJldHVybiBtaW1lLmNoYXJzZXQoY29udGVudFR5cGUpIHx8IG51bGw7XG5cdH0sXG5cblx0LyoqXG5cdCAqIEdldCBmaWxlIGV4dGVuc2lvbiBmb3IgYSBjb250ZW50IHR5cGVcblx0ICogQHBhcmFtIGNvbnRlbnRUeXBlIE1JTUUgdHlwZVxuXHQgKiBAcmV0dXJucyBGaWxlIGV4dGVuc2lvbiAod2l0aCBkb3QpIG9yIGZhbHNlIGlmIG5vdCBmb3VuZFxuXHQgKi9cblx0ZXh0ZW5zaW9uKGNvbnRlbnRUeXBlOiBzdHJpbmcpOiBzdHJpbmcgfCBmYWxzZSB7XG5cdFx0cmV0dXJuIG1pbWUuZXh0ZW5zaW9uKGNvbnRlbnRUeXBlKTtcblx0fSxcblxuXHQvKipcblx0ICogQ2hlY2sgaWYgYSBjb250ZW50IHR5cGUgcmVwcmVzZW50cyB0ZXh0IGRhdGFcblx0ICogQHBhcmFtIGNvbnRlbnRUeXBlIE1JTUUgdHlwZSB0byBjaGVja1xuXHQgKiBAcmV0dXJucyBUcnVlIGlmIGNvbnRlbnQgdHlwZSBpcyB0ZXh0LWJhc2VkXG5cdCAqL1xuXHRpc1RleHQoY29udGVudFR5cGU6IHN0cmluZyk6IGJvb2xlYW4ge1xuXHRcdHJldHVybiAoXG5cdFx0XHRjb250ZW50VHlwZS5zdGFydHNXaXRoKFwidGV4dC9cIikgfHxcblx0XHRcdGNvbnRlbnRUeXBlID09PSBcImFwcGxpY2F0aW9uL2pzb25cIiB8fFxuXHRcdFx0Y29udGVudFR5cGUgPT09IFwiYXBwbGljYXRpb24veG1sXCIgfHxcblx0XHRcdGNvbnRlbnRUeXBlID09PSBcImFwcGxpY2F0aW9uL2phdmFzY3JpcHRcIiB8fFxuXHRcdFx0Y29udGVudFR5cGUgPT09IFwiYXBwbGljYXRpb24vdHlwZXNjcmlwdFwiXG5cdFx0KTtcblx0fSxcblxuXHQvKipcblx0ICogQ2hlY2sgaWYgYSBjb250ZW50IHR5cGUgcmVwcmVzZW50cyBiaW5hcnkgZGF0YVxuXHQgKiBAcGFyYW0gY29udGVudFR5cGUgTUlNRSB0eXBlIHRvIGNoZWNrXG5cdCAqIEByZXR1cm5zIFRydWUgaWYgY29udGVudCB0eXBlIGlzIGJpbmFyeVxuXHQgKi9cblx0aXNCaW5hcnkoY29udGVudFR5cGU6IHN0cmluZyk6IGJvb2xlYW4ge1xuXHRcdHJldHVybiAhdGhpcy5pc1RleHQoY29udGVudFR5cGUpO1xuXHR9LFxufTtcblxuLyoqXG4gKiBEZWZhdWx0IGxvZ2dlciBpbXBsZW1lbnRhdGlvbiB1c2luZyBjb25zb2xlXG4gKi9cbmV4cG9ydCBjbGFzcyBDb25zb2xlTG9nZ2VyIGltcGxlbWVudHMgTG9nZ2VyIHtcblx0cHJpdmF0ZSBsZXZlbDogTG9nTGV2ZWwgPSBMb2dMZXZlbC5JbmZvO1xuXG5cdGNvbnN0cnVjdG9yKGxldmVsPzogTG9nTGV2ZWwpIHtcblx0XHRpZiAobGV2ZWwgIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0dGhpcy5sZXZlbCA9IGxldmVsO1xuXHRcdH1cblx0fVxuXG5cdGRlYnVnKG1lc3NhZ2U6IHN0cmluZywgLi4uYXJnczogdW5rbm93bltdKTogdm9pZCB7XG5cdFx0aWYgKHRoaXMubGV2ZWwgPD0gTG9nTGV2ZWwuRGVidWcpIHtcblx0XHRcdGNvbnNvbGUuZGVidWcoYFtERUJVR10gJHttZXNzYWdlfWAsIC4uLmFyZ3MpO1xuXHRcdH1cblx0fVxuXG5cdGluZm8obWVzc2FnZTogc3RyaW5nLCAuLi5hcmdzOiB1bmtub3duW10pOiB2b2lkIHtcblx0XHRpZiAodGhpcy5sZXZlbCA8PSBMb2dMZXZlbC5JbmZvKSB7XG5cdFx0XHRjb25zb2xlLmluZm8oYFtJTkZPXSAke21lc3NhZ2V9YCwgLi4uYXJncyk7XG5cdFx0fVxuXHR9XG5cblx0d2FybihtZXNzYWdlOiBzdHJpbmcsIC4uLmFyZ3M6IHVua25vd25bXSk6IHZvaWQge1xuXHRcdGlmICh0aGlzLmxldmVsIDw9IExvZ0xldmVsLldhcm4pIHtcblx0XHRcdGNvbnNvbGUud2FybihgW1dBUk5dICR7bWVzc2FnZX1gLCAuLi5hcmdzKTtcblx0XHR9XG5cdH1cblxuXHRlcnJvcihtZXNzYWdlOiBzdHJpbmcsIC4uLmFyZ3M6IHVua25vd25bXSk6IHZvaWQge1xuXHRcdGlmICh0aGlzLmxldmVsIDw9IExvZ0xldmVsLkVycm9yKSB7XG5cdFx0XHRjb25zb2xlLmVycm9yKGBbRVJST1JdICR7bWVzc2FnZX1gLCAuLi5hcmdzKTtcblx0XHR9XG5cdH1cblxuXHRzZXRMZXZlbChsZXZlbDogTG9nTGV2ZWwpOiB2b2lkIHtcblx0XHR0aGlzLmxldmVsID0gbGV2ZWw7XG5cdH1cblxuXHRnZXRMZXZlbCgpOiBMb2dMZXZlbCB7XG5cdFx0cmV0dXJuIHRoaXMubGV2ZWw7XG5cdH1cbn1cblxuLyoqXG4gKiBOby1vcCBsb2dnZXIgdGhhdCBkaXNjYXJkcyBhbGwgbG9nIG1lc3NhZ2VzXG4gKi9cbmV4cG9ydCBjbGFzcyBOb29wTG9nZ2VyIGltcGxlbWVudHMgTG9nZ2VyIHtcblx0ZGVidWcoKTogdm9pZCB7fVxuXHRpbmZvKCk6IHZvaWQge31cblx0d2FybigpOiB2b2lkIHt9XG5cdGVycm9yKCk6IHZvaWQge31cblx0c2V0TGV2ZWwoKTogdm9pZCB7fVxuXHRnZXRMZXZlbCgpOiBMb2dMZXZlbCB7XG5cdFx0cmV0dXJuIExvZ0xldmVsLk5vbmU7XG5cdH1cbn1cblxuLy8gR2xvYmFsIGxvZ2dlciBpbnN0YW5jZVxubGV0IGdsb2JhbExvZ2dlcjogTG9nZ2VyID0gbmV3IENvbnNvbGVMb2dnZXIoKTtcblxuLyoqXG4gKiBTZXQgdGhlIGdsb2JhbCBsb2dnZXIgaW5zdGFuY2VcbiAqIEBwYXJhbSBsb2dnZXIgVGhlIGxvZ2dlciBpbnN0YW5jZSB0byB1c2UgZ2xvYmFsbHlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldEdsb2JhbExvZ2dlcihsb2dnZXI6IExvZ2dlcik6IHZvaWQge1xuXHRnbG9iYWxMb2dnZXIgPSBsb2dnZXI7XG59XG5cbi8qKlxuICogR2V0IHRoZSBjdXJyZW50IGdsb2JhbCBsb2dnZXIgaW5zdGFuY2VcbiAqIEByZXR1cm5zIFRoZSBjdXJyZW50IGdsb2JhbCBsb2dnZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEdsb2JhbExvZ2dlcigpOiBMb2dnZXIge1xuXHRyZXR1cm4gZ2xvYmFsTG9nZ2VyO1xufVxuXG4vKipcbiAqIFNsZWVwIGZ1bmN0aW9uIGZvciByZXRyeSBkZWxheXNcbiAqIEBwYXJhbSBtcyBNaWxsaXNlY29uZHMgdG8gc2xlZXBcbiAqL1xuY29uc3Qgc2xlZXAgPSAobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4gPT5cblx0bmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcblxuLyoqXG4gKiBSZXRyeSBhIGZ1bmN0aW9uIHdpdGggZXhwb25lbnRpYWwgYmFja29mZlxuICogQHBhcmFtIGZuIEZ1bmN0aW9uIHRvIHJldHJ5XG4gKiBAcGFyYW0gcmV0cmllcyBNYXhpbXVtIG51bWJlciBvZiByZXRyaWVzXG4gKiBAcGFyYW0gYmFzZURlbGF5IEJhc2UgZGVsYXkgaW4gbWlsbGlzZWNvbmRzXG4gKiBAcGFyYW0gbWF4RGVsYXkgTWF4aW11bSBkZWxheSBpbiBtaWxsaXNlY29uZHNcbiAqIEBwYXJhbSBsb2dnZXIgT3B0aW9uYWwgbG9nZ2VyIHRvIHVzZSBpbnN0ZWFkIG9mIGdsb2JhbCBsb2dnZXJcbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmV0cnlXaXRoQmFja29mZjxUPihcblx0Zm46ICgpID0+IFByb21pc2U8VD4sXG5cdHJldHJpZXMgPSA1LFxuXHRiYXNlRGVsYXkgPSAxMDAsXG5cdG1heERlbGF5ID0gMzAwMDAsXG5cdGxvZ2dlcjogTG9nZ2VyID0gZ2xvYmFsTG9nZ2VyLFxuKTogUHJvbWlzZTxUPiB7XG5cdGxldCBsYXN0RXJyb3I6IEVycm9yIHwgdW5kZWZpbmVkO1xuXG5cdGZvciAobGV0IGkgPSAwOyBpIDwgcmV0cmllczsgaSsrKSB7XG5cdFx0dHJ5IHtcblx0XHRcdHJldHVybiBhd2FpdCBmbigpO1xuXHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRsYXN0RXJyb3IgPSBlcnJvciBhcyBFcnJvcjtcblxuXHRcdFx0Ly8gT25seSByZXRyeSBvbiB0aHJvdHRsaW5nLCB0aW1lb3V0LCBvciBuZXR3b3JrIGVycm9yc1xuXHRcdFx0Y29uc3QgZXJyb3JDb2RlID1cblx0XHRcdFx0KGVycm9yIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KT8uQ29kZSB8fFxuXHRcdFx0XHQoZXJyb3IgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pPy5jb2RlO1xuXHRcdFx0Y29uc3QgZXJyb3JNZXNzYWdlID0gKGVycm9yIGFzIEVycm9yKT8ubWVzc2FnZSB8fCBcIlwiO1xuXHRcdFx0Y29uc3QgaXNSZXRyeWFibGUgPVxuXHRcdFx0XHRlcnJvckNvZGUgPT09IFwiVGhyb3R0bGluZ0V4Y2VwdGlvblwiIHx8XG5cdFx0XHRcdGVycm9yQ29kZSA9PT0gXCJSZXF1ZXN0VGltZW91dFwiIHx8XG5cdFx0XHRcdGVycm9yQ29kZSA9PT0gXCJOZXR3b3JraW5nRXJyb3JcIiB8fFxuXHRcdFx0XHRlcnJvckNvZGUgPT09IFwiVGltZW91dEVycm9yXCIgfHxcblx0XHRcdFx0ZXJyb3JDb2RlID09PSBcIlJlcXVlc3RUaW1lVG9vU2tld2VkXCIgfHxcblx0XHRcdFx0ZXJyb3JDb2RlID09PSBcIlByb3Zpc2lvbmVkVGhyb3VnaHB1dEV4Y2VlZGVkRXhjZXB0aW9uXCIgfHxcblx0XHRcdFx0ZXJyb3JDb2RlID09PSBcIlNsb3dEb3duXCIgfHxcblx0XHRcdFx0ZXJyb3JDb2RlID09PSBcIkludGVybmFsRXJyb3JcIiB8fFxuXHRcdFx0XHRlcnJvckNvZGUgPT09IFwiU2VydmljZVVuYXZhaWxhYmxlXCIgfHxcblx0XHRcdFx0ZXJyb3JDb2RlID09PSBcIjQyOVwiIHx8XG5cdFx0XHRcdGVycm9yQ29kZSA9PT0gXCI1MDBcIiB8fFxuXHRcdFx0XHRlcnJvckNvZGUgPT09IFwiNTAzXCIgfHxcblx0XHRcdFx0ZXJyb3JNZXNzYWdlLmluY2x1ZGVzKFwidGltZW91dFwiKSB8fFxuXHRcdFx0XHRlcnJvck1lc3NhZ2UuaW5jbHVkZXMoXCJ0aHJvdHRsXCIpIHx8XG5cdFx0XHRcdGVycm9yTWVzc2FnZS5pbmNsdWRlcyhcIm5ldHdvcmtcIikgfHxcblx0XHRcdFx0ZXJyb3JNZXNzYWdlLmluY2x1ZGVzKFwiY29ubmVjdGlvblwiKTtcblxuXHRcdFx0aWYgKCFpc1JldHJ5YWJsZSkge1xuXHRcdFx0XHR0aHJvdyBlcnJvcjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ2FsY3VsYXRlIGV4cG9uZW50aWFsIGJhY2tvZmYgd2l0aCBqaXR0ZXJcblx0XHRcdGNvbnN0IGRlbGF5ID0gTWF0aC5taW4oXG5cdFx0XHRcdG1heERlbGF5LFxuXHRcdFx0XHRiYXNlRGVsYXkgKiAyICoqIGkgKiAoMC44ICsgTWF0aC5yYW5kb20oKSAqIDAuNCksXG5cdFx0XHQpO1xuXG5cdFx0XHQvLyBMb2cgcmV0cnkgYXR0ZW1wdFxuXHRcdFx0bG9nZ2VyLmRlYnVnKFxuXHRcdFx0XHRgUzMgb3BlcmF0aW9uIGZhaWxlZCAoYXR0ZW1wdCAke2kgKyAxfS8ke3JldHJpZXN9KSwgcmV0cnlpbmcgaW4gJHtNYXRoLnJvdW5kKGRlbGF5KX1tczogJHtlcnJvckNvZGUgfHwgZXJyb3JNZXNzYWdlfWAsXG5cdFx0XHQpO1xuXG5cdFx0XHRhd2FpdCBzbGVlcChkZWxheSk7XG5cdFx0fVxuXHR9XG5cblx0dGhyb3cgbGFzdEVycm9yO1xufVxuXG4vKipcbiAqIFNhZmVseSBlbmNvZGVzIFMzIGtleXMgZm9yIHVzZSBpbiBVUkxzIGFuZCBoYW5kbGluZyBzcGVjaWFsIGNoYXJhY3RlcnNcbiAqIEBwYXJhbSBrZXkgUzMga2V5IHRvIGVuY29kZVxuICogQHJldHVybnMgVVJMLWVuY29kZWQga2V5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBlbmNvZGVTM0tleShrZXk6IHN0cmluZyk6IHN0cmluZyB7XG5cdC8vIEVuY29kZSBhbGwgc3BlY2lhbCBjaGFyYWN0ZXJzIGV4Y2VwdCBmb3J3YXJkIHNsYXNoZXNcblx0Ly8gVGhpcyBtYWtlcyB0aGUga2V5IHNhZmUgZm9yIFVSTCB1c2UgYW5kIGZpbGUgb3BlcmF0aW9uc1xuXHRyZXR1cm4ga2V5XG5cdFx0LnNwbGl0KFwiL1wiKVxuXHRcdC5tYXAoKHNlZ21lbnQpID0+IGVuY29kZVVSSUNvbXBvbmVudChzZWdtZW50KSlcblx0XHQuam9pbihcIi9cIik7XG59XG5cbi8qKlxuICogU2FmZWx5IGRlY29kZXMgUzMga2V5cyBmcm9tIFVSTHNcbiAqIEBwYXJhbSBlbmNvZGVkS2V5IFVSTC1lbmNvZGVkIFMzIGtleVxuICogQHJldHVybnMgRGVjb2RlZCBrZXlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlY29kZVMzS2V5KGVuY29kZWRLZXk6IHN0cmluZyk6IHN0cmluZyB7XG5cdC8vIERlY29kZSBhbGwgVVJMLWVuY29kZWQgY29tcG9uZW50c1xuXHRyZXR1cm4gZW5jb2RlZEtleVxuXHRcdC5zcGxpdChcIi9cIilcblx0XHQubWFwKChzZWdtZW50KSA9PiBkZWNvZGVVUklDb21wb25lbnQoc2VnbWVudCkpXG5cdFx0LmpvaW4oXCIvXCIpO1xufVxuXG4vKipcbiAqIEludGVyZmFjZSBmb3Igb2JqZWN0IG1ldGFkYXRhXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT2JqZWN0TWV0YWRhdGEge1xuXHRrZXk6IHN0cmluZztcblx0c2l6ZTogbnVtYmVyO1xuXHRldGFnOiBzdHJpbmc7XG5cdGxhc3RNb2RpZmllZDogRGF0ZTtcblx0Y29udGVudFR5cGU/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUzMgb2JqZWN0IGludGVyZmFjZSBtYXRjaGluZyBBV1MgU0RLIHN0cnVjdHVyZSB3aXRoIGNhbWVsQ2FzZSBwcm9wZXJ0aWVzXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUzNPYmplY3Qge1xuXHRrZXk/OiBzdHJpbmc7XG5cdHNpemU/OiBudW1iZXI7XG5cdGV0YWc/OiBzdHJpbmc7XG5cdGxhc3RNb2RpZmllZD86IERhdGU7XG59XG5cbi8qKlxuICogQ2hhbmdlIHR5cGVzIGZvciB0cmFja2luZyBvYmplY3QgbW9kaWZpY2F0aW9uc1xuICovXG5leHBvcnQgZW51bSBDaGFuZ2VUeXBlIHtcblx0QWRkZWQgPSBcImFkZGVkXCIsXG5cdE1vZGlmaWVkID0gXCJtb2RpZmllZFwiLFxuXHREZWxldGVkID0gXCJkZWxldGVkXCIsXG5cdFVuY2hhbmdlZCA9IFwidW5jaGFuZ2VkXCIsXG59XG5cbi8qKlxuICogUmVzdWx0IG9mIGEgY2hhbmdlIGRldGVjdGlvbiBjb21wYXJpc29uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2hhbmdlUmVzdWx0IHtcblx0Y2hhbmdlVHlwZTogQ2hhbmdlVHlwZTtcblx0b2JqZWN0OiBPYmplY3RNZXRhZGF0YTtcblx0cHJldmlvdXNWZXJzaW9uPzogT2JqZWN0TWV0YWRhdGE7XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgY2hhbmdlIGRldGVjdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIENoYW5nZURldGVjdGlvbk9wdGlvbnMge1xuXHRzdGF0ZUZpbGVQYXRoPzogc3RyaW5nO1xuXHRjb21wYXJlTW9kZT86IFwicXVpY2tcIiB8IFwiZnVsbFwiO1xuXHRpZ25vcmVFdGFnT25TaXplPzogYm9vbGVhbjtcblx0dHJhY2tEZWxldGVkPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBFbmdpbmUgZm9yIGRldGVjdGluZyBjaGFuZ2VzIGluIFMzIG9iamVjdHMgYmV0d2VlbiBydW5zXG4gKi9cbmV4cG9ydCBjbGFzcyBDaGFuZ2VEZXRlY3Rpb25FbmdpbmUge1xuXHRwcml2YXRlIHByZXZpb3VzU3RhdGU6IE1hcDxzdHJpbmcsIE9iamVjdE1ldGFkYXRhPiA9IG5ldyBNYXAoKTtcblx0cHJpdmF0ZSBjdXJyZW50U3RhdGU6IE1hcDxzdHJpbmcsIE9iamVjdE1ldGFkYXRhPiA9IG5ldyBNYXAoKTtcblx0cHJpdmF0ZSBvcHRpb25zOiBDaGFuZ2VEZXRlY3Rpb25PcHRpb25zO1xuXG5cdC8qKlxuXHQgKiBDcmVhdGVzIGEgbmV3IENoYW5nZURldGVjdGlvbkVuZ2luZVxuXHQgKiBAcGFyYW0gb3B0aW9ucyBFbmdpbmUgY29uZmlndXJhdGlvbiBvcHRpb25zXG5cdCAqL1xuXHRjb25zdHJ1Y3RvcihvcHRpb25zOiBDaGFuZ2VEZXRlY3Rpb25PcHRpb25zID0ge30pIHtcblx0XHR0aGlzLm9wdGlvbnMgPSB7XG5cdFx0XHRzdGF0ZUZpbGVQYXRoOiBcImNoYW5nZS1kZXRlY3Rpb24tc3RhdGUuanNvblwiLFxuXHRcdFx0Y29tcGFyZU1vZGU6IFwiZnVsbFwiLFxuXHRcdFx0aWdub3JlRXRhZ09uU2l6ZTogZmFsc2UsXG5cdFx0XHR0cmFja0RlbGV0ZWQ6IHRydWUsXG5cdFx0XHQuLi5vcHRpb25zLFxuXHRcdH07XG5cdH1cblxuXHQvKipcblx0ICogTG9hZHMgdGhlIHByZXZpb3VzIHN0YXRlIGZyb20gYSBKU09OIGZpbGUgb3IgY3JlYXRlcyBhIG5ldyBzdGF0ZSBpZiBub25lIGV4aXN0c1xuXHQgKi9cblx0YXN5bmMgbG9hZFByZXZpb3VzU3RhdGUoKTogUHJvbWlzZTx2b2lkPiB7XG5cdFx0aWYgKCF0aGlzLm9wdGlvbnMuc3RhdGVGaWxlUGF0aCkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRyeSB7XG5cdFx0XHRjb25zdCBzdGF0ZURhdGEgPSBhd2FpdCBmcy5yZWFkRmlsZSh0aGlzLm9wdGlvbnMuc3RhdGVGaWxlUGF0aCwgXCJ1dGYtOFwiKTtcblx0XHRcdGNvbnN0IHBhcnNlZFN0YXRlID0gSlNPTi5wYXJzZShzdGF0ZURhdGEpO1xuXG5cdFx0XHQvLyBDb252ZXJ0IHRoZSBhcnJheSBiYWNrIHRvIGEgTWFwXG5cdFx0XHR0aGlzLnByZXZpb3VzU3RhdGUgPSBuZXcgTWFwKFxuXHRcdFx0XHRPYmplY3QuZW50cmllcyhwYXJzZWRTdGF0ZSkubWFwKChba2V5LCB2YWx1ZV0pID0+IHtcblx0XHRcdFx0XHRjb25zdCBtZXRhZGF0YSA9IHZhbHVlIGFzIE9iamVjdE1ldGFkYXRhO1xuXHRcdFx0XHRcdC8vIENvbnZlcnQgSVNPIHN0cmluZyBiYWNrIHRvIERhdGUgb2JqZWN0XG5cdFx0XHRcdFx0aWYgKFxuXHRcdFx0XHRcdFx0bWV0YWRhdGEubGFzdE1vZGlmaWVkICYmXG5cdFx0XHRcdFx0XHR0eXBlb2YgbWV0YWRhdGEubGFzdE1vZGlmaWVkID09PSBcInN0cmluZ1wiXG5cdFx0XHRcdFx0KSB7XG5cdFx0XHRcdFx0XHRtZXRhZGF0YS5sYXN0TW9kaWZpZWQgPSBuZXcgRGF0ZShtZXRhZGF0YS5sYXN0TW9kaWZpZWQpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRyZXR1cm4gW2tleSwgbWV0YWRhdGFdO1xuXHRcdFx0XHR9KSxcblx0XHRcdCk7XG5cdFx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHRcdC8vIElmIGZpbGUgZG9lc24ndCBleGlzdCBvciBpcyBpbnZhbGlkLCBzdGFydCB3aXRoIGFuIGVtcHR5IHN0YXRlXG5cdFx0XHR0aGlzLnByZXZpb3VzU3RhdGUgPSBuZXcgTWFwKCk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFNhdmVzIHRoZSBjdXJyZW50IHN0YXRlIHRvIGEgSlNPTiBmaWxlXG5cdCAqL1xuXHRhc3luYyBzYXZlQ3VycmVudFN0YXRlKCk6IFByb21pc2U8dm9pZD4ge1xuXHRcdGlmICghdGhpcy5vcHRpb25zLnN0YXRlRmlsZVBhdGgpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBDb252ZXJ0IE1hcCB0byBhIHBsYWluIG9iamVjdCBmb3Igc2VyaWFsaXphdGlvblxuXHRcdGNvbnN0IHN0YXRlT2JqZWN0ID0gT2JqZWN0LmZyb21FbnRyaWVzKHRoaXMuY3VycmVudFN0YXRlKTtcblx0XHRjb25zdCBzdGF0ZURhdGEgPSBKU09OLnN0cmluZ2lmeShzdGF0ZU9iamVjdCwgbnVsbCwgMik7XG5cblx0XHQvLyBFbnN1cmUgZGlyZWN0b3J5IGV4aXN0c1xuXHRcdGNvbnN0IGRpciA9IHBhdGguZGlybmFtZSh0aGlzLm9wdGlvbnMuc3RhdGVGaWxlUGF0aCk7XG5cdFx0YXdhaXQgZnMubWtkaXIoZGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuXHRcdC8vIFdyaXRlIHN0YXRlIGZpbGVcblx0XHRhd2FpdCBmcy53cml0ZUZpbGUodGhpcy5vcHRpb25zLnN0YXRlRmlsZVBhdGgsIHN0YXRlRGF0YSwgXCJ1dGYtOFwiKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBBZGRzIGFuIG9iamVjdCB0byB0aGUgY3VycmVudCBzdGF0ZVxuXHQgKiBAcGFyYW0gb2JqZWN0IE9iamVjdCBtZXRhZGF0YSB0byB0cmFja1xuXHQgKi9cblx0YWRkT2JqZWN0KG9iamVjdDogT2JqZWN0TWV0YWRhdGEpOiB2b2lkIHtcblx0XHR0aGlzLmN1cnJlbnRTdGF0ZS5zZXQob2JqZWN0LmtleSwgb2JqZWN0KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBBZGRzIG11bHRpcGxlIG9iamVjdHMgdG8gdGhlIGN1cnJlbnQgc3RhdGVcblx0ICogQHBhcmFtIG9iamVjdHMgQXJyYXkgb2Ygb2JqZWN0IG1ldGFkYXRhXG5cdCAqL1xuXHRhZGRPYmplY3RzKG9iamVjdHM6IE9iamVjdE1ldGFkYXRhW10pOiB2b2lkIHtcblx0XHRmb3IgKGNvbnN0IG9iamVjdCBvZiBvYmplY3RzKSB7XG5cdFx0XHR0aGlzLmFkZE9iamVjdChvYmplY3QpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBDb252ZXJ0cyBhbiBTMyBvYmplY3QgdG8gb3VyIG1ldGFkYXRhIGZvcm1hdFxuXHQgKiBAcGFyYW0gczNPYmplY3QgUzMgb2JqZWN0IGZyb20gQVdTIFNES1xuXHQgKiBAcmV0dXJucyBOb3JtYWxpemVkIG9iamVjdCBtZXRhZGF0YVxuXHQgKi9cblx0c3RhdGljIGZyb21TM09iamVjdChzM09iamVjdDogUzNPYmplY3QpOiBPYmplY3RNZXRhZGF0YSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdGtleTogczNPYmplY3Qua2V5IHx8IFwiXCIsXG5cdFx0XHRzaXplOiBzM09iamVjdC5zaXplIHx8IDAsXG5cdFx0XHRldGFnOiAoczNPYmplY3QuZXRhZyB8fCBcIlwiKS5yZXBsYWNlKC9cIi9nLCBcIlwiKSwgLy8gUmVtb3ZlIHF1b3RlcyBmcm9tIEVUYWdcblx0XHRcdGxhc3RNb2RpZmllZDogczNPYmplY3QubGFzdE1vZGlmaWVkIHx8IG5ldyBEYXRlKCksXG5cdFx0fTtcblx0fVxuXG5cdC8qKlxuXHQgKiBEZXRlcm1pbmVzIGlmIGFuIG9iamVjdCBoYXMgY2hhbmdlZCBiZXR3ZWVuIHN0YXRlc1xuXHQgKiBAcGFyYW0gY3VycmVudCBDdXJyZW50IG9iamVjdCBtZXRhZGF0YVxuXHQgKiBAcGFyYW0gcHJldmlvdXMgUHJldmlvdXMgb2JqZWN0IG1ldGFkYXRhXG5cdCAqIEByZXR1cm5zIFRydWUgaWYgdGhlIG9iamVjdCBoYXMgY2hhbmdlZFxuXHQgKi9cblx0cHJpdmF0ZSBoYXNPYmplY3RDaGFuZ2VkKFxuXHRcdGN1cnJlbnQ6IE9iamVjdE1ldGFkYXRhLFxuXHRcdHByZXZpb3VzOiBPYmplY3RNZXRhZGF0YSxcblx0KTogYm9vbGVhbiB7XG5cdFx0aWYgKHRoaXMub3B0aW9ucy5jb21wYXJlTW9kZSA9PT0gXCJxdWlja1wiKSB7XG5cdFx0XHQvLyBRdWljayBjb21wYXJpc29uIC0gb25seSBjaGVjayBzaXplIGFuZCBsYXN0IG1vZGlmaWVkIGRhdGVcblx0XHRcdHJldHVybiAoXG5cdFx0XHRcdGN1cnJlbnQuc2l6ZSAhPT0gcHJldmlvdXMuc2l6ZSB8fFxuXHRcdFx0XHRjdXJyZW50Lmxhc3RNb2RpZmllZC5nZXRUaW1lKCkgIT09IHByZXZpb3VzLmxhc3RNb2RpZmllZC5nZXRUaW1lKClcblx0XHRcdCk7XG5cdFx0fVxuXG5cdFx0Ly8gRnVsbCBjb21wYXJpc29uIC0gY2hlY2sgRVRhZyAoaGFzaCkgYXMgd2VsbFxuXHRcdC8vIElmIGlnbm9yZUV0YWdPblNpemUgaXMgdHJ1ZSwgc2tpcCBFVGFnIGNoZWNrIHdoZW4gc2l6ZXMgbWF0Y2hcblx0XHRpZiAodGhpcy5vcHRpb25zLmlnbm9yZUV0YWdPblNpemUgJiYgY3VycmVudC5zaXplID09PSBwcmV2aW91cy5zaXplKSB7XG5cdFx0XHRyZXR1cm4gY3VycmVudC5sYXN0TW9kaWZpZWQuZ2V0VGltZSgpICE9PSBwcmV2aW91cy5sYXN0TW9kaWZpZWQuZ2V0VGltZSgpO1xuXHRcdH1cblxuXHRcdHJldHVybiAoXG5cdFx0XHRjdXJyZW50LnNpemUgIT09IHByZXZpb3VzLnNpemUgfHxcblx0XHRcdGN1cnJlbnQuZXRhZyAhPT0gcHJldmlvdXMuZXRhZyB8fFxuXHRcdFx0Y3VycmVudC5sYXN0TW9kaWZpZWQuZ2V0VGltZSgpICE9PSBwcmV2aW91cy5sYXN0TW9kaWZpZWQuZ2V0VGltZSgpXG5cdFx0KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDb21wYXJlcyBjdXJyZW50IHN0YXRlIHdpdGggcHJldmlvdXMgc3RhdGUgdG8gZGV0ZWN0IGNoYW5nZXNcblx0ICogQHJldHVybnMgQXJyYXkgb2YgY2hhbmdlIHJlc3VsdHNcblx0ICovXG5cdGRldGVjdENoYW5nZXMoKTogQ2hhbmdlUmVzdWx0W10ge1xuXHRcdGNvbnN0IGNoYW5nZXM6IENoYW5nZVJlc3VsdFtdID0gW107XG5cblx0XHQvLyBDaGVjayBmb3IgbmV3IGFuZCBtb2RpZmllZCBvYmplY3RzXG5cdFx0dGhpcy5jdXJyZW50U3RhdGUuZm9yRWFjaCgoY3VycmVudE9iamVjdCwga2V5KSA9PiB7XG5cdFx0XHRjb25zdCBwcmV2aW91c09iamVjdCA9IHRoaXMucHJldmlvdXNTdGF0ZS5nZXQoa2V5KTtcblxuXHRcdFx0aWYgKCFwcmV2aW91c09iamVjdCkge1xuXHRcdFx0XHQvLyBOZXcgb2JqZWN0XG5cdFx0XHRcdGNoYW5nZXMucHVzaCh7XG5cdFx0XHRcdFx0Y2hhbmdlVHlwZTogQ2hhbmdlVHlwZS5BZGRlZCxcblx0XHRcdFx0XHRvYmplY3Q6IGN1cnJlbnRPYmplY3QsXG5cdFx0XHRcdH0pO1xuXHRcdFx0fSBlbHNlIGlmICh0aGlzLmhhc09iamVjdENoYW5nZWQoY3VycmVudE9iamVjdCwgcHJldmlvdXNPYmplY3QpKSB7XG5cdFx0XHRcdC8vIE1vZGlmaWVkIG9iamVjdFxuXHRcdFx0XHRjaGFuZ2VzLnB1c2goe1xuXHRcdFx0XHRcdGNoYW5nZVR5cGU6IENoYW5nZVR5cGUuTW9kaWZpZWQsXG5cdFx0XHRcdFx0b2JqZWN0OiBjdXJyZW50T2JqZWN0LFxuXHRcdFx0XHRcdHByZXZpb3VzVmVyc2lvbjogcHJldmlvdXNPYmplY3QsXG5cdFx0XHRcdH0pO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Ly8gVW5jaGFuZ2VkIG9iamVjdFxuXHRcdFx0XHRjaGFuZ2VzLnB1c2goe1xuXHRcdFx0XHRcdGNoYW5nZVR5cGU6IENoYW5nZVR5cGUuVW5jaGFuZ2VkLFxuXHRcdFx0XHRcdG9iamVjdDogY3VycmVudE9iamVjdCxcblx0XHRcdFx0XHRwcmV2aW91c1ZlcnNpb246IHByZXZpb3VzT2JqZWN0LFxuXHRcdFx0XHR9KTtcblx0XHRcdH1cblx0XHR9KTtcblxuXHRcdC8vIENoZWNrIGZvciBkZWxldGVkIG9iamVjdHMgaWYgZW5hYmxlZFxuXHRcdGlmICh0aGlzLm9wdGlvbnMudHJhY2tEZWxldGVkKSB7XG5cdFx0XHR0aGlzLnByZXZpb3VzU3RhdGUuZm9yRWFjaCgocHJldmlvdXNPYmplY3QsIGtleSkgPT4ge1xuXHRcdFx0XHRpZiAoIXRoaXMuY3VycmVudFN0YXRlLmhhcyhrZXkpKSB7XG5cdFx0XHRcdFx0Y2hhbmdlcy5wdXNoKHtcblx0XHRcdFx0XHRcdGNoYW5nZVR5cGU6IENoYW5nZVR5cGUuRGVsZXRlZCxcblx0XHRcdFx0XHRcdG9iamVjdDogcHJldmlvdXNPYmplY3QsXG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdHJldHVybiBjaGFuZ2VzO1xuXHR9XG5cblx0LyoqXG5cdCAqIEZpbHRlciBjaGFuZ2VzIGJ5IHR5cGVcblx0ICogQHBhcmFtIGNoYW5nZXMgQXJyYXkgb2YgY2hhbmdlIHJlc3VsdHNcblx0ICogQHBhcmFtIHR5cGVzIFR5cGVzIG9mIGNoYW5nZXMgdG8gaW5jbHVkZVxuXHQgKiBAcmV0dXJucyBGaWx0ZXJlZCBhcnJheSBvZiBjaGFuZ2UgcmVzdWx0c1xuXHQgKi9cblx0c3RhdGljIGZpbHRlckNoYW5nZXNCeVR5cGUoXG5cdFx0Y2hhbmdlczogQ2hhbmdlUmVzdWx0W10sXG5cdFx0dHlwZXM6IENoYW5nZVR5cGVbXSxcblx0KTogQ2hhbmdlUmVzdWx0W10ge1xuXHRcdHJldHVybiBjaGFuZ2VzLmZpbHRlcigoY2hhbmdlKSA9PiB0eXBlcy5pbmNsdWRlcyhjaGFuZ2UuY2hhbmdlVHlwZSkpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZXMgYSBuZXcgc3RhdGUgZnJvbSB0aGUgY3VycmVudCBzdGF0ZVxuXHQgKi9cblx0Y29tbWl0Q2hhbmdlcygpOiB2b2lkIHtcblx0XHR0aGlzLnByZXZpb3VzU3RhdGUgPSBuZXcgTWFwKHRoaXMuY3VycmVudFN0YXRlKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDbGVhcnMgdGhlIGN1cnJlbnQgc3RhdGVcblx0ICovXG5cdHJlc2V0Q3VycmVudFN0YXRlKCk6IHZvaWQge1xuXHRcdHRoaXMuY3VycmVudFN0YXRlID0gbmV3IE1hcCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENsZWFycyBhbGwgc3RhdGUgKHByZXZpb3VzIGFuZCBjdXJyZW50KVxuXHQgKi9cblx0cmVzZXRBbGxTdGF0ZSgpOiB2b2lkIHtcblx0XHR0aGlzLnByZXZpb3VzU3RhdGUgPSBuZXcgTWFwKCk7XG5cdFx0dGhpcy5jdXJyZW50U3RhdGUgPSBuZXcgTWFwKCk7XG5cdH1cbn1cblxuLyoqXG4gKiBBIHV0aWxpdHkgY2xhc3MgZm9yIGVmZmljaWVudCBwYXRoIGxvb2t1cHMgdXNpbmcgbWljcm9tYXRjaFxuICovXG5leHBvcnQgY2xhc3MgUGF0aE1hdGNoZXIge1xuXHQvLyBDYWNoZSBmb3IgY29tcGlsZWQgcGF0dGVybnMgdG8gYXZvaWQgcmUtY29tcGlsYXRpb25cblx0cHJpdmF0ZSByZWFkb25seSBwYXR0ZXJuQ2FjaGU6IE1hcDxzdHJpbmcsIFJlZ0V4cD4gPSBuZXcgTWFwKCk7XG5cblx0LyoqXG5cdCAqIENyZWF0ZXMgYSBuZXcgUGF0aE1hdGNoZXIgaW5zdGFuY2Vcblx0ICogQHBhcmFtIG9wdGlvbnMgRGVmYXVsdCBvcHRpb25zIHRvIHVzZSBmb3IgYWxsIG1hdGNoZXNcblx0ICovXG5cdGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogbWljcm9tYXRjaC5PcHRpb25zID0ge30pIHt9XG5cblx0LyoqXG5cdCAqIENoZWNrIGlmIGEgcGF0aCBtYXRjaGVzIGEgZ2xvYiBwYXR0ZXJuXG5cdCAqIEBwYXJhbSBwYXRoIFBhdGggdG8gY2hlY2tcblx0ICogQHBhcmFtIHBhdHRlcm4gR2xvYiBwYXR0ZXJuIHRvIG1hdGNoIGFnYWluc3Rcblx0ICogQHBhcmFtIG9wdGlvbnMgQWRkaXRpb25hbCBvcHRpb25zIHRvIG92ZXJyaWRlIGRlZmF1bHRzXG5cdCAqIEByZXR1cm5zIFRydWUgaWYgdGhlIHBhdGggbWF0Y2hlcyB0aGUgcGF0dGVyblxuXHQgKi9cblx0aXNNYXRjaChcblx0XHRwYXRoOiBzdHJpbmcsXG5cdFx0cGF0dGVybjogc3RyaW5nIHwgc3RyaW5nW10sXG5cdFx0b3B0aW9ucz86IG1pY3JvbWF0Y2guT3B0aW9ucyxcblx0KTogYm9vbGVhbiB7XG5cdFx0cmV0dXJuIG1pY3JvbWF0Y2guaXNNYXRjaChwYXRoLCBwYXR0ZXJuLCB7IC4uLnRoaXMub3B0aW9ucywgLi4ub3B0aW9ucyB9KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBGaWx0ZXIgYW4gYXJyYXkgb2YgcGF0aHMgYmFzZWQgb24gb25lIG9yIG1vcmUgZ2xvYiBwYXR0ZXJuc1xuXHQgKiBAcGFyYW0gcGF0aHMgQXJyYXkgb2YgcGF0aHMgdG8gZmlsdGVyXG5cdCAqIEBwYXJhbSBwYXR0ZXJucyBPbmUgb3IgbW9yZSBnbG9iIHBhdHRlcm5zXG5cdCAqIEBwYXJhbSBvcHRpb25zIEFkZGl0aW9uYWwgb3B0aW9ucyB0byBvdmVycmlkZSBkZWZhdWx0c1xuXHQgKiBAcmV0dXJucyBGaWx0ZXJlZCBhcnJheSBvZiBwYXRocyB0aGF0IG1hdGNoIHRoZSBwYXR0ZXJuc1xuXHQgKi9cblx0bWF0Y2goXG5cdFx0cGF0aHM6IHN0cmluZ1tdLFxuXHRcdHBhdHRlcm5zOiBzdHJpbmcgfCBzdHJpbmdbXSxcblx0XHRvcHRpb25zPzogbWljcm9tYXRjaC5PcHRpb25zLFxuXHQpOiBzdHJpbmdbXSB7XG5cdFx0cmV0dXJuIG1pY3JvbWF0Y2gocGF0aHMsIHBhdHRlcm5zLCB7IC4uLnRoaXMub3B0aW9ucywgLi4ub3B0aW9ucyB9KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGUgYW5kIGNhY2hlIGEgcmVndWxhciBleHByZXNzaW9uIGZvciBhIGdsb2IgcGF0dGVyblxuXHQgKiBAcGFyYW0gcGF0dGVybiBHbG9iIHBhdHRlcm4gdG8gY29udmVydCB0byByZWdleFxuXHQgKiBAcGFyYW0gb3B0aW9ucyBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gb3ZlcnJpZGUgZGVmYXVsdHNcblx0ICogQHJldHVybnMgUmVndWxhciBleHByZXNzaW9uIGZvciB0aGUgcGF0dGVyblxuXHQgKi9cblx0Z2V0UmVnZXgocGF0dGVybjogc3RyaW5nLCBvcHRpb25zPzogbWljcm9tYXRjaC5PcHRpb25zKTogUmVnRXhwIHtcblx0XHRjb25zdCBjYWNoZUtleSA9IGAke3BhdHRlcm59OiR7SlNPTi5zdHJpbmdpZnkoeyAuLi50aGlzLm9wdGlvbnMsIC4uLm9wdGlvbnMgfSl9YDtcblxuXHRcdGlmICghdGhpcy5wYXR0ZXJuQ2FjaGUuaGFzKGNhY2hlS2V5KSkge1xuXHRcdFx0Y29uc3QgcmVnZXggPSBtaWNyb21hdGNoLm1ha2VSZShwYXR0ZXJuLCB7IC4uLnRoaXMub3B0aW9ucywgLi4ub3B0aW9ucyB9KTtcblx0XHRcdHRoaXMucGF0dGVybkNhY2hlLnNldChjYWNoZUtleSwgcmVnZXgpO1xuXHRcdH1cblxuXHRcdGNvbnN0IGNhY2hlZFJlZ2V4ID0gdGhpcy5wYXR0ZXJuQ2FjaGUuZ2V0KGNhY2hlS2V5KTtcblx0XHRpZiAoIWNhY2hlZFJlZ2V4KSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoXG5cdFx0XHRcdGBGYWlsZWQgdG8gY3JlYXRlIG9yIHJldHJpZXZlIHJlZ2V4IGZvciBwYXR0ZXJuOiAke3BhdHRlcm59YCxcblx0XHRcdCk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNhY2hlZFJlZ2V4O1xuXHR9XG5cblx0LyoqXG5cdCAqIEZpbHRlciBwYXRocyB1c2luZyBwcmUtY29tcGlsZWQgcmVnZXggcGF0dGVybnMgZm9yIG1heGltdW0gcGVyZm9ybWFuY2Vcblx0ICogQHBhcmFtIHBhdGhzIEFycmF5IG9mIHBhdGhzIHRvIGZpbHRlclxuXHQgKiBAcGFyYW0gcGF0dGVybnMgT25lIG9yIG1vcmUgZ2xvYiBwYXR0ZXJuc1xuXHQgKiBAcGFyYW0gb3B0aW9ucyBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gb3ZlcnJpZGUgZGVmYXVsdHNcblx0ICogQHJldHVybnMgRmlsdGVyZWQgYXJyYXkgb2YgcGF0aHMgdGhhdCBtYXRjaCB0aGUgcGF0dGVybnNcblx0ICovXG5cdG1hdGNoRmFzdChcblx0XHRwYXRoczogc3RyaW5nW10sXG5cdFx0cGF0dGVybnM6IHN0cmluZyB8IHN0cmluZ1tdLFxuXHRcdG9wdGlvbnM/OiBtaWNyb21hdGNoLk9wdGlvbnMsXG5cdCk6IHN0cmluZ1tdIHtcblx0XHRjb25zdCBwYXR0ZXJuQXJyYXkgPSBBcnJheS5pc0FycmF5KHBhdHRlcm5zKSA/IHBhdHRlcm5zIDogW3BhdHRlcm5zXTtcblx0XHRjb25zdCByZWdleGVzID0gcGF0dGVybkFycmF5Lm1hcCgocGF0dGVybikgPT5cblx0XHRcdHRoaXMuZ2V0UmVnZXgocGF0dGVybiwgb3B0aW9ucyksXG5cdFx0KTtcblxuXHRcdHJldHVybiBwYXRocy5maWx0ZXIoKHBhdGgpID0+IHJlZ2V4ZXMuc29tZSgocmVnZXgpID0+IHJlZ2V4LnRlc3QocGF0aCkpKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBGaWx0ZXIgcGF0aHMgdGhhdCBkb24ndCBtYXRjaCBhbnkgb2YgdGhlIHByb3ZpZGVkIHBhdHRlcm5zXG5cdCAqIEBwYXJhbSBwYXRocyBBcnJheSBvZiBwYXRocyB0byBmaWx0ZXJcblx0ICogQHBhcmFtIHBhdHRlcm5zIE9uZSBvciBtb3JlIGdsb2IgcGF0dGVybnMgdG8gZXhjbHVkZVxuXHQgKiBAcGFyYW0gb3B0aW9ucyBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gb3ZlcnJpZGUgZGVmYXVsdHNcblx0ICogQHJldHVybnMgRmlsdGVyZWQgYXJyYXkgb2YgcGF0aHMgdGhhdCBkb24ndCBtYXRjaCBhbnkgcGF0dGVyblxuXHQgKi9cblx0bm90KFxuXHRcdHBhdGhzOiBzdHJpbmdbXSxcblx0XHRwYXR0ZXJuczogc3RyaW5nIHwgc3RyaW5nW10sXG5cdFx0b3B0aW9ucz86IG1pY3JvbWF0Y2guT3B0aW9ucyxcblx0KTogc3RyaW5nW10ge1xuXHRcdHJldHVybiBtaWNyb21hdGNoLm5vdChwYXRocywgcGF0dGVybnMsIHsgLi4udGhpcy5vcHRpb25zLCAuLi5vcHRpb25zIH0pO1xuXHR9XG5cblx0LyoqXG5cdCAqIENoZWNrIGlmIGFsbCBvZiB0aGUgcHJvdmlkZWQgcGF0dGVybnMgbWF0Y2ggdGhlIHBhdGhcblx0ICogQHBhcmFtIHBhdGggUGF0aCB0byBjaGVja1xuXHQgKiBAcGFyYW0gcGF0dGVybnMgT25lIG9yIG1vcmUgZ2xvYiBwYXR0ZXJuc1xuXHQgKiBAcGFyYW0gb3B0aW9ucyBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gb3ZlcnJpZGUgZGVmYXVsdHNcblx0ICogQHJldHVybnMgVHJ1ZSBpZiBhbGwgcGF0dGVybnMgbWF0Y2ggdGhlIHBhdGhcblx0ICovXG5cdGFsbChcblx0XHRwYXRoOiBzdHJpbmcsXG5cdFx0cGF0dGVybnM6IHN0cmluZyB8IHN0cmluZ1tdLFxuXHRcdG9wdGlvbnM/OiBtaWNyb21hdGNoLk9wdGlvbnMsXG5cdCk6IGJvb2xlYW4ge1xuXHRcdHJldHVybiBtaWNyb21hdGNoLmFsbChwYXRoLCBwYXR0ZXJucywgeyAuLi50aGlzLm9wdGlvbnMsIC4uLm9wdGlvbnMgfSk7XG5cdH1cblxuXHQvKipcblx0ICogQ2FwdHVyZSB2YWx1ZXMgZnJvbSBhIHBhdGggYmFzZWQgb24gYSBnbG9iIHBhdHRlcm5cblx0ICogQHBhcmFtIHBhdHRlcm4gR2xvYiBwYXR0ZXJuIHdpdGggY2FwdHVyZSBncm91cHNcblx0ICogQHBhcmFtIHBhdGggUGF0aCB0byBleHRyYWN0IHZhbHVlcyBmcm9tXG5cdCAqIEBwYXJhbSBvcHRpb25zIEFkZGl0aW9uYWwgb3B0aW9ucyB0byBvdmVycmlkZSBkZWZhdWx0c1xuXHQgKiBAcmV0dXJucyBBcnJheSBvZiBjYXB0dXJlZCB2YWx1ZXMgb3IgbnVsbCBpZiBubyBtYXRjaFxuXHQgKi9cblx0Y2FwdHVyZShcblx0XHRwYXR0ZXJuOiBzdHJpbmcsXG5cdFx0cGF0aDogc3RyaW5nLFxuXHRcdG9wdGlvbnM/OiBtaWNyb21hdGNoLk9wdGlvbnMsXG5cdCk6IHN0cmluZ1tdIHwgbnVsbCB7XG5cdFx0Ly8gSW1wbGVtZW50YXRpb24gdGhhdCBtaW1pY3MgbWljcm9tYXRjaC5jYXB0dXJlXG5cdFx0Ly8gUGFyc2UgdGhlIHBhdHRlcm4gYW5kIGV4dHJhY3QgY2FwdHVyZSBncm91cHMgZnJvbSB0aGUgcGF0aFxuXHRcdGNvbnN0IHBsYWNlaG9sZGVyUmVnZXggPSAvOlteXFwvXFwuXSsvZztcblx0XHRjb25zdCBwbGFjZWhvbGRlcnMgPSBwYXR0ZXJuLm1hdGNoKHBsYWNlaG9sZGVyUmVnZXgpIHx8IFtdO1xuXG5cdFx0Ly8gUmVwbGFjZSBwbGFjZWhvbGRlcnMgd2l0aCBjYXB0dXJlIGdyb3Vwc1xuXHRcdGxldCByZWdleFBhdHRlcm4gPSBwYXR0ZXJuLnJlcGxhY2UoL1xcLy9nLCBcIlxcXFwvXCIpO1xuXHRcdHJlZ2V4UGF0dGVybiA9IHJlZ2V4UGF0dGVybi5yZXBsYWNlKC9cXC4vZywgXCJcXFxcLlwiKTtcblxuXHRcdGZvciAoY29uc3QgcGxhY2Vob2xkZXIgb2YgcGxhY2Vob2xkZXJzKSB7XG5cdFx0XHQvLyBSZXBsYWNlIDpuYW1lIHdpdGggY2FwdHVyaW5nIGdyb3VwXG5cdFx0XHRyZWdleFBhdHRlcm4gPSByZWdleFBhdHRlcm4ucmVwbGFjZShwbGFjZWhvbGRlciwgXCIoW14vXFxcXC5dKylcIik7XG5cdFx0fVxuXG5cdFx0Ly8gUmVwbGFjZSBhc3Rlcmlza3Mgd2l0aCBjYXB0dXJpbmcgZ3JvdXBzIGZvciBmaWxlbmFtZXNcblx0XHRyZWdleFBhdHRlcm4gPSByZWdleFBhdHRlcm4ucmVwbGFjZSgvXFwqL2csIFwiKFteL10rKVwiKTtcblxuXHRcdC8vIENyZWF0ZSBhIHJlZ2V4IHdpdGggdGhlIHBhdHRlcm5cblx0XHRjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYF4ke3JlZ2V4UGF0dGVybn0kYCwgb3B0aW9ucz8ubm9jYXNlID8gXCJpXCIgOiBcIlwiKTtcblx0XHRjb25zdCBtYXRjaCA9IHBhdGgubWF0Y2gocmVnZXgpO1xuXG5cdFx0aWYgKCFtYXRjaCkge1xuXHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0fVxuXG5cdFx0Ly8gUmV0dXJuIHRoZSBjYXB0dXJlZCB2YWx1ZXMgKHNraXAgdGhlIGZpcnN0IGVsZW1lbnQgd2hpY2ggaXMgdGhlIGZ1bGwgbWF0Y2gpXG5cdFx0cmV0dXJuIG1hdGNoLnNsaWNlKDEpO1xuXHR9XG59XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBpbnRlcmZhY2UgZm9yIFMzIGNsaWVudFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFMzQ2xpZW50Q29uZmlnIHtcblx0cmVnaW9uPzogc3RyaW5nO1xuXHRlbmRwb2ludD86IHN0cmluZztcblx0Y3JlZGVudGlhbHM/OiB7XG5cdFx0YWNjZXNzS2V5SWQ6IHN0cmluZztcblx0XHRzZWNyZXRBY2Nlc3NLZXk6IHN0cmluZztcblx0XHRzZXNzaW9uVG9rZW4/OiBzdHJpbmc7XG5cdH07XG5cdG1heFJldHJpZXM/OiBudW1iZXI7XG5cdHJlcXVlc3RUaW1lb3V0PzogbnVtYmVyO1xuXHRjb25uZWN0VGltZW91dD86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBNZXRhZGF0YSBjYWNoZSBjb25maWd1cmF0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWV0YWRhdGFDYWNoZUNvbmZpZyB7XG5cdGVuYWJsZWQ/OiBib29sZWFuO1xuXHRtYXhTaXplPzogbnVtYmVyO1xuXHR0dGw/OiBudW1iZXI7IC8vIFRpbWUgdG8gbGl2ZSBpbiBtc1xuXHRyZWZyZXNoVGhyZXNob2xkPzogbnVtYmVyOyAvLyAlIG9mIFRUTCB3aGVuIHRvIHJlZnJlc2ggaW4gYmFja2dyb3VuZFxufVxuXG4vKipcbiAqIEEgdXRpbGl0eSBjbGFzcyBmb3Igd29ya2luZyB3aXRoIFMzIHBhdGhzIGFuZCBnbG9iIHBhdHRlcm5zXG4gKi9cbmV4cG9ydCBjbGFzcyBTM1BhdGhNYXRjaGVyIGV4dGVuZHMgUGF0aE1hdGNoZXIge1xuXHRwcml2YXRlIHJlYWRvbmx5IHMzQ2xpZW50OiBTM0NsaWVudDtcblx0cHJpdmF0ZSByZWFkb25seSBtZXRhZGF0YUNhY2hlOiBMUlVDYWNoZTxzdHJpbmcsIE9iamVjdE1ldGFkYXRhPjtcblx0cHJpdmF0ZSByZWFkb25seSBjYWNoZUNvbmZpZzogUmVxdWlyZWQ8TWV0YWRhdGFDYWNoZUNvbmZpZz47XG5cdHByaXZhdGUgcmVhZG9ubHkgcGVuZGluZ1JlZnJlc2hlczogU2V0PHN0cmluZz4gPSBuZXcgU2V0KCk7XG5cdHByb3RlY3RlZCByZWFkb25seSBsb2dnZXI6IExvZ2dlcjtcblxuXHQvKipcblx0ICogQ3JlYXRlcyBhIG5ldyBTM1BhdGhNYXRjaGVyIHdpdGggUzMgY2xpZW50IGFuZCBjYWNoaW5nIGNvbmZpZ3VyYXRpb25cblx0ICogQHBhcmFtIG9wdGlvbnMgTWljcm9tYXRjaCBvcHRpb25zIGZvciBwYXRoIG1hdGNoaW5nXG5cdCAqIEBwYXJhbSBzM09wdGlvbnMgUzMgY2xpZW50IGNvbmZpZ3VyYXRpb25cblx0ICogQHBhcmFtIGNhY2hlT3B0aW9ucyBNZXRhZGF0YSBjYWNoZSBjb25maWd1cmF0aW9uXG5cdCAqIEBwYXJhbSBsb2dnZXIgQ3VzdG9tIGxvZ2dlciB0byB1c2UgKGRlZmF1bHRzIHRvIGdsb2JhbCBsb2dnZXIpXG5cdCAqL1xuXHRjb25zdHJ1Y3Rvcihcblx0XHRvcHRpb25zOiBtaWNyb21hdGNoLk9wdGlvbnMgPSB7fSxcblx0XHRzM09wdGlvbnM6IHtcblx0XHRcdHJlZ2lvbj86IHN0cmluZztcblx0XHRcdGVuZHBvaW50Pzogc3RyaW5nO1xuXHRcdFx0Y3JlZGVudGlhbHM/OiB7IGFjY2Vzc0tleUlkOiBzdHJpbmc7IHNlY3JldEFjY2Vzc0tleTogc3RyaW5nIH07XG5cdFx0XHRmb3JjZVBhdGhTdHlsZT86IGJvb2xlYW47XG5cdFx0XHRtYXhSZXRyaWVzPzogbnVtYmVyO1xuXHRcdH0gPSB7fSxcblx0XHRjYWNoZU9wdGlvbnM6IE1ldGFkYXRhQ2FjaGVDb25maWcgPSB7fSxcblx0XHRsb2dnZXI6IExvZ2dlciA9IGdsb2JhbExvZ2dlcixcblx0KSB7XG5cdFx0c3VwZXIob3B0aW9ucyk7XG5cblx0XHR0aGlzLmxvZ2dlciA9IGxvZ2dlcjtcblxuXHRcdC8vIENvbmZpZ3VyZSBTMyBjbGllbnRcblx0XHR0aGlzLnMzQ2xpZW50ID0gbmV3IFMzQ2xpZW50KHtcblx0XHRcdHJlZ2lvbjogczNPcHRpb25zLnJlZ2lvbiB8fCBcInVzLWVhc3QtMVwiLFxuXHRcdFx0ZW5kcG9pbnQ6IHMzT3B0aW9ucy5lbmRwb2ludCxcblx0XHRcdGNyZWRlbnRpYWxzOiBzM09wdGlvbnMuY3JlZGVudGlhbHMsXG5cdFx0XHRmb3JjZVBhdGhTdHlsZTogczNPcHRpb25zLmZvcmNlUGF0aFN0eWxlLFxuXHRcdFx0bWF4QXR0ZW1wdHM6IHMzT3B0aW9ucy5tYXhSZXRyaWVzIHx8IDMsXG5cdFx0fSk7XG5cblx0XHQvLyBDb25maWd1cmUgbWV0YWRhdGEgY2FjaGVcblx0XHR0aGlzLmNhY2hlQ29uZmlnID0ge1xuXHRcdFx0ZW5hYmxlZDogY2FjaGVPcHRpb25zLmVuYWJsZWQgPz8gdHJ1ZSxcblx0XHRcdG1heFNpemU6IGNhY2hlT3B0aW9ucy5tYXhTaXplID8/IDEwMDAsXG5cdFx0XHR0dGw6IGNhY2hlT3B0aW9ucy50dGwgPz8gNSAqIDYwICogMTAwMCwgLy8gRGVmYXVsdCA1IG1pbnV0ZXNcblx0XHRcdHJlZnJlc2hUaHJlc2hvbGQ6IGNhY2hlT3B0aW9ucy5yZWZyZXNoVGhyZXNob2xkID8/IDgwLCAvLyBSZWZyZXNoIGF0IDgwJSBvZiBUVEwgYnkgZGVmYXVsdFxuXHRcdH07XG5cblx0XHQvLyBJbml0aWFsaXplIExSVSBjYWNoZVxuXHRcdHRoaXMubWV0YWRhdGFDYWNoZSA9IG5ldyBMUlVDYWNoZTxzdHJpbmcsIE9iamVjdE1ldGFkYXRhPih7XG5cdFx0XHRtYXg6I