@pipeline-builder/pipeline-core 4.1.15 → 4.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cdk.d.ts +1 -0
- package/lib/cdk.js +2 -1
- package/lib/config/app-config.d.ts +5 -8
- package/lib/config/app-config.js +36 -38
- package/lib/config/config-types.d.ts +9 -112
- package/lib/config/config-types.js +1 -1
- package/lib/config/handler-constants.d.ts +12 -3
- package/lib/config/handler-constants.js +9 -26
- package/lib/config/infrastructure-config.js +44 -43
- package/lib/config/server-config.d.ts +1 -1
- package/lib/config/server-config.js +33 -32
- package/lib/config/service-client.d.ts +3 -7
- package/lib/config/service-client.js +5 -11
- package/lib/core/artifact-manager.d.ts +0 -17
- package/lib/core/artifact-manager.js +1 -17
- package/lib/core/metadata-helpers.d.ts +16 -0
- package/lib/core/metadata-helpers.js +41 -1
- package/lib/core/pipeline-helpers.js +23 -58
- package/lib/core/plugin-contract.d.ts +126 -0
- package/lib/core/plugin-contract.js +217 -0
- package/lib/core/plugin-lookup-envelope.d.ts +14 -0
- package/lib/core/plugin-lookup-envelope.js +29 -0
- package/lib/core/step-manifest.d.ts +50 -0
- package/lib/core/step-manifest.js +47 -0
- package/lib/handlers/platform-credential.d.ts +47 -0
- package/lib/handlers/platform-credential.js +87 -0
- package/lib/handlers/plugin-lookup-handler.d.ts +1 -1
- package/lib/handlers/plugin-lookup-handler.js +48 -42
- package/lib/index.d.ts +8 -8
- package/lib/index.js +10 -9
- package/lib/pipeline/pipeline-builder.d.ts +7 -0
- package/lib/pipeline/pipeline-builder.js +25 -9
- package/lib/pipeline/pipeline-configuration.js +6 -5
- package/lib/pipeline/plugin-lookup.d.ts +0 -1
- package/lib/pipeline/plugin-lookup.js +55 -23
- package/lib/pipeline/plugin-spec.d.ts +41 -0
- package/lib/pipeline/plugin-spec.js +1 -1
- package/lib/pipeline/stage-builder.d.ts +11 -0
- package/lib/pipeline/stage-builder.js +31 -12
- package/lib/pipeline/step-manifest-recorder.d.ts +22 -0
- package/lib/pipeline/step-manifest-recorder.js +57 -0
- package/lib/pipeline/step-types.d.ts +16 -4
- package/lib/pipeline/step-types.js +1 -1
- package/lib/template/index.d.ts +4 -4
- package/lib/template/index.js +5 -5
- package/lib/template/plugin-resolver.js +5 -5
- package/lib/template/tokenizer.d.ts +4 -0
- package/lib/template/tokenizer.js +11 -7
- package/lib/testing/exports.json +72 -0
- package/package.json +36 -8
- package/lib/config/billing-config.d.ts +0 -27
- package/lib/config/billing-config.js +0 -534
- package/lib/config/entitlements.d.ts +0 -23
- package/lib/config/entitlements.js +0 -46
|
@@ -1,534 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
/**
|
|
4
|
-
* Load billing plan configuration from environment variables.
|
|
5
|
-
*
|
|
6
|
-
* Per-plan prices are the most likely to vary between environments:
|
|
7
|
-
* BILLING_PLAN_{TIER}_MONTHLY / BILLING_PLAN_{TIER}_ANNUAL (in cents)
|
|
8
|
-
*
|
|
9
|
-
* Optional overrides for descriptions and features:
|
|
10
|
-
* BILLING_PLAN_{TIER}_NAME (plain string, display name)
|
|
11
|
-
* BILLING_PLAN_{TIER}_DESCRIPTION (plain string)
|
|
12
|
-
* BILLING_PLAN_{TIER}_FEATURES (JSON string array)
|
|
13
|
-
*
|
|
14
|
-
* All defaults match the original hardcoded seed data.
|
|
15
|
-
*/
|
|
16
|
-
import { QUOTA_TIERS, TIER_FEATURES, FEATURE_METADATA, VALID_TIERS, STANDARD_TIERS, isValidFeatureFlag, isValidTier } from '@pipeline-builder/api-core';
|
|
17
|
-
// -- Default features ---------------------------------------------------------
|
|
18
|
-
// The marketed feature list is built from two derived sources so it can never
|
|
19
|
-
// drift from what the platform actually enforces:
|
|
20
|
-
// 1. LIMIT lines derived from each tier's EFFECTIVE quota limits (QUOTA_TIERS),
|
|
21
|
-
// so they track QUOTA_TIER_* env overrides.
|
|
22
|
-
// 2. INCLUDED-FEATURE lines derived from the enforced entitlement set
|
|
23
|
-
// (TIER_FEATURES) via FEATURE_METADATA labels — so an advertised base
|
|
24
|
-
// feature is always one `requireFeature` actually grants for that tier.
|
|
25
|
-
// Only genuinely non-gated marketing copy (support level, dashboards, RBAC) is
|
|
26
|
-
// hand-authored, passed as `perks`. Purchasable feature add-ons
|
|
27
|
-
// (advanced_reporting, team_usage_analytics, compliance_*) are NOT listed as
|
|
28
|
-
// base perks here — they are sold as bundles (see loadBundles()). `sso` is the
|
|
29
|
-
// other way round: a TIER feature only (Team+), never a bundle, so it DOES
|
|
30
|
-
// appear as a derived base perk on the tiers that include it.
|
|
31
|
-
/** "Up to N plugins" / "Unlimited plugins" from an effective limit (-1 = unlimited). */
|
|
32
|
-
function limitLine(limit, singular, plural) {
|
|
33
|
-
if (limit === -1)
|
|
34
|
-
return `Unlimited ${plural}`;
|
|
35
|
-
return `Up to ${limit.toLocaleString('en-US')} ${limit === 1 ? singular : plural}`;
|
|
36
|
-
}
|
|
37
|
-
function defaultFeatures(tier, perks) {
|
|
38
|
-
const l = QUOTA_TIERS[tier].limits;
|
|
39
|
-
return [
|
|
40
|
-
limitLine(l.seats, 'seat', 'seats'),
|
|
41
|
-
limitLine(l.plugins, 'plugin', 'plugins'),
|
|
42
|
-
limitLine(l.pipelines, 'pipeline', 'pipelines'),
|
|
43
|
-
limitLine(l.apiCalls, 'API call', 'API calls'),
|
|
44
|
-
limitLine(l.aiCalls, 'AI call', 'AI calls'),
|
|
45
|
-
// Enforced entitlements → customer-facing labels (single source of truth).
|
|
46
|
-
...TIER_FEATURES[tier].map((f) => FEATURE_METADATA[f].label),
|
|
47
|
-
...perks,
|
|
48
|
-
];
|
|
49
|
-
}
|
|
50
|
-
// Note: `perks` are non-gated marketing lines only. Enforced features (incl.
|
|
51
|
-
// Priority Support for pro/team/enterprise) come from TIER_FEATURES above.
|
|
52
|
-
// The reporting dashboard is open to every tier (only the DORA/scorecard views
|
|
53
|
-
// are entitlement-gated), so it's listed on each plan rather than implying a
|
|
54
|
-
// lower tier lacks it.
|
|
55
|
-
const DEFAULT_DEVELOPER_FEATURES = defaultFeatures('developer', ['Community support', 'Reporting dashboard']);
|
|
56
|
-
const DEFAULT_PRO_FEATURES = defaultFeatures('pro', ['Reporting dashboard']);
|
|
57
|
-
const DEFAULT_TEAM_FEATURES = defaultFeatures('team', ['RBAC & team roles', 'Reporting dashboard']);
|
|
58
|
-
const DEFAULT_ENTERPRISE_FEATURES = defaultFeatures('enterprise', [
|
|
59
|
-
'RBAC & team roles', 'Reporting dashboard',
|
|
60
|
-
]);
|
|
61
|
-
// Unlimited includes every feature (TIER_FEATURES.unlimited = all).
|
|
62
|
-
const DEFAULT_UNLIMITED_FEATURES = defaultFeatures('unlimited', [
|
|
63
|
-
'Unlimited everything', 'RBAC & team roles', 'Reporting dashboard',
|
|
64
|
-
]);
|
|
65
|
-
/**
|
|
66
|
-
* Parse a price (in cents) from an env var, falling back to the default when
|
|
67
|
-
* unset OR malformed. A NaN (e.g. `BILLING_PLAN_PRO_MONTHLY=abc`) must never
|
|
68
|
-
* flow into the returned config as a price.
|
|
69
|
-
*/
|
|
70
|
-
function envCents(envVar, fallback) {
|
|
71
|
-
if (envVar === undefined || envVar === '')
|
|
72
|
-
return fallback;
|
|
73
|
-
// `parseInt` is too lenient here: '49.99'→49, '49abc'→49, '-100'→-100 would all
|
|
74
|
-
// flow through as a "price". Require a clean, non-negative integer (cents),
|
|
75
|
-
// matching `applyGrantOverride`'s rigor — anything else falls back.
|
|
76
|
-
const n = Number(envVar);
|
|
77
|
-
return Number.isInteger(n) && n >= 0 ? n : fallback;
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Parse a JSON array from an env var, falling back to default.
|
|
81
|
-
*/
|
|
82
|
-
function parseFeatures(envVar, fallback) {
|
|
83
|
-
if (!envVar)
|
|
84
|
-
return fallback;
|
|
85
|
-
try {
|
|
86
|
-
const parsed = JSON.parse(envVar);
|
|
87
|
-
// Array-of-strings only — a JSON array of non-strings (e.g. `[1,2]`) must not
|
|
88
|
-
// ship numbers as feature labels. Filter to strings (mirrors applyTiersOverride).
|
|
89
|
-
if (!Array.isArray(parsed))
|
|
90
|
-
return fallback;
|
|
91
|
-
const strings = parsed.filter((x) => typeof x === 'string');
|
|
92
|
-
return strings.length === parsed.length ? strings : fallback;
|
|
93
|
-
}
|
|
94
|
-
catch {
|
|
95
|
-
return fallback;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Load billing plan configuration from environment variables.
|
|
100
|
-
*/
|
|
101
|
-
export function loadBillingConfig() {
|
|
102
|
-
// Keyed by QuotaTier so the compiler forces a plan for EVERY tier — adding a
|
|
103
|
-
// 5th QuotaTier without a plan here is now a compile error (was a hand-kept
|
|
104
|
-
// 4-element array that silently shipped no plan/price for a new tier). The
|
|
105
|
-
// public `config.plans` shape stays an array, derived below in VALID_TIERS
|
|
106
|
-
// order (developer, pro, team, enterprise, unlimited) to preserve consumer ordering.
|
|
107
|
-
const planByTier = {
|
|
108
|
-
developer: {
|
|
109
|
-
id: 'developer',
|
|
110
|
-
name: process.env.BILLING_PLAN_DEVELOPER_NAME || 'Developer',
|
|
111
|
-
description: process.env.BILLING_PLAN_DEVELOPER_DESCRIPTION
|
|
112
|
-
|| 'Free starter tier for individual developers',
|
|
113
|
-
tier: 'developer',
|
|
114
|
-
prices: {
|
|
115
|
-
monthly: envCents(process.env.BILLING_PLAN_DEVELOPER_MONTHLY, 0),
|
|
116
|
-
annual: envCents(process.env.BILLING_PLAN_DEVELOPER_ANNUAL, 0),
|
|
117
|
-
},
|
|
118
|
-
features: parseFeatures(process.env.BILLING_PLAN_DEVELOPER_FEATURES, DEFAULT_DEVELOPER_FEATURES),
|
|
119
|
-
isActive: true,
|
|
120
|
-
isDefault: true,
|
|
121
|
-
sortOrder: 0,
|
|
122
|
-
},
|
|
123
|
-
pro: {
|
|
124
|
-
id: 'pro',
|
|
125
|
-
name: process.env.BILLING_PLAN_PRO_NAME || 'Pro',
|
|
126
|
-
description: process.env.BILLING_PLAN_PRO_DESCRIPTION
|
|
127
|
-
|| 'For individual power users and production workloads',
|
|
128
|
-
tier: 'pro',
|
|
129
|
-
prices: {
|
|
130
|
-
monthly: envCents(process.env.BILLING_PLAN_PRO_MONTHLY, 3900),
|
|
131
|
-
annual: envCents(process.env.BILLING_PLAN_PRO_ANNUAL, 39000),
|
|
132
|
-
},
|
|
133
|
-
features: parseFeatures(process.env.BILLING_PLAN_PRO_FEATURES, DEFAULT_PRO_FEATURES),
|
|
134
|
-
isActive: true,
|
|
135
|
-
isDefault: false,
|
|
136
|
-
sortOrder: 1,
|
|
137
|
-
},
|
|
138
|
-
team: {
|
|
139
|
-
id: 'team',
|
|
140
|
-
name: process.env.BILLING_PLAN_TEAM_NAME || 'Team',
|
|
141
|
-
description: process.env.BILLING_PLAN_TEAM_DESCRIPTION
|
|
142
|
-
|| 'For teams collaborating on shared pipelines',
|
|
143
|
-
tier: 'team',
|
|
144
|
-
prices: {
|
|
145
|
-
monthly: envCents(process.env.BILLING_PLAN_TEAM_MONTHLY, 7900),
|
|
146
|
-
annual: envCents(process.env.BILLING_PLAN_TEAM_ANNUAL, 79000),
|
|
147
|
-
},
|
|
148
|
-
features: parseFeatures(process.env.BILLING_PLAN_TEAM_FEATURES, DEFAULT_TEAM_FEATURES),
|
|
149
|
-
isActive: true,
|
|
150
|
-
isDefault: false,
|
|
151
|
-
sortOrder: 2,
|
|
152
|
-
},
|
|
153
|
-
enterprise: {
|
|
154
|
-
id: 'enterprise',
|
|
155
|
-
name: process.env.BILLING_PLAN_ENTERPRISE_NAME || 'Enterprise',
|
|
156
|
-
description: process.env.BILLING_PLAN_ENTERPRISE_DESCRIPTION
|
|
157
|
-
|| 'Org-wide scale with a high seat baseline (expandable via Member Seat add-ons) and priority support',
|
|
158
|
-
tier: 'enterprise',
|
|
159
|
-
prices: {
|
|
160
|
-
monthly: envCents(process.env.BILLING_PLAN_ENTERPRISE_MONTHLY, 59900),
|
|
161
|
-
annual: envCents(process.env.BILLING_PLAN_ENTERPRISE_ANNUAL, 599000),
|
|
162
|
-
},
|
|
163
|
-
features: parseFeatures(process.env.BILLING_PLAN_ENTERPRISE_FEATURES, DEFAULT_ENTERPRISE_FEATURES),
|
|
164
|
-
isActive: true,
|
|
165
|
-
isDefault: false,
|
|
166
|
-
sortOrder: 3,
|
|
167
|
-
},
|
|
168
|
-
// The billing-DISABLED default plan: everything uncapped, all features, free.
|
|
169
|
-
// Seeded so the tier→plan mapping resolves, but never offered for sale — the
|
|
170
|
-
// read-plans route filters it out (see createReadPlanRoutes), so it's hidden
|
|
171
|
-
// whenever billing is enabled (the only time /plans is served).
|
|
172
|
-
unlimited: {
|
|
173
|
-
id: 'unlimited',
|
|
174
|
-
name: process.env.BILLING_PLAN_UNLIMITED_NAME || 'Unlimited',
|
|
175
|
-
description: process.env.BILLING_PLAN_UNLIMITED_DESCRIPTION
|
|
176
|
-
|| 'Everything uncapped — the default when billing is disabled',
|
|
177
|
-
tier: 'unlimited',
|
|
178
|
-
prices: {
|
|
179
|
-
monthly: envCents(process.env.BILLING_PLAN_UNLIMITED_MONTHLY, 0),
|
|
180
|
-
annual: envCents(process.env.BILLING_PLAN_UNLIMITED_ANNUAL, 0),
|
|
181
|
-
},
|
|
182
|
-
features: parseFeatures(process.env.BILLING_PLAN_UNLIMITED_FEATURES, DEFAULT_UNLIMITED_FEATURES),
|
|
183
|
-
isActive: true,
|
|
184
|
-
isDefault: false,
|
|
185
|
-
sortOrder: 4,
|
|
186
|
-
},
|
|
187
|
-
};
|
|
188
|
-
// Derive the array consumers read (`config.plans`) in canonical tier order.
|
|
189
|
-
const plans = VALID_TIERS.map((tier) => planByTier[tier]);
|
|
190
|
-
// Build bundles ONCE and thread them into the combo loader (which needs their
|
|
191
|
-
// env-effective prices) — avoids parsing the whole bundle catalog twice per load.
|
|
192
|
-
const bundles = loadBundles();
|
|
193
|
-
return { plans, bundles, comboDiscounts: loadComboDiscounts(bundles) };
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Combo discounts (docs/billing-bundles.md §Combo pricing). When an account owns
|
|
197
|
-
* every member bundle (each at ≥ its minimum quantity), the set is billed at the
|
|
198
|
-
* combined price instead of the sum of the members — realized as a recurring usage
|
|
199
|
-
* credit for the difference. Overlapping combos are resolved by max-weight packing
|
|
200
|
-
* (a shared add-on is never discounted twice); `sortOrder` breaks equal-total ties.
|
|
201
|
-
*
|
|
202
|
-
* Defaults:
|
|
203
|
-
* - "Analytics Suite" — Advanced Reporting (DORA) + Team Usage Analytics, each
|
|
204
|
-
* $30/mo, together $42/mo ($420/yr) → a $18/mo credit (~30% off).
|
|
205
|
-
* - "Team Growth Bundle" — ≥5 Seats ($19.99 ea) + Team Usage Analytics ($30),
|
|
206
|
-
* basket $129.95/mo → together $90.99/mo ($909.90/yr) → a ~$38.96/mo credit (~30% off).
|
|
207
|
-
* - "Scale Bundle" — API Pack ($19.99) + Storage Pack ($19.99), basket $39.98/mo
|
|
208
|
-
* → together $27.99/mo ($279.90/yr) → a ~$11.99/mo credit (~30% off).
|
|
209
|
-
* Prices env-overridable via `BILLING_COMBO_<ID>_MONTHLY` / `_ANNUAL`.
|
|
210
|
-
*/
|
|
211
|
-
function loadComboDiscounts(bundles) {
|
|
212
|
-
const c = (id, name, bundleIds, monthly, annual, sortOrder, minQuantities) => ({
|
|
213
|
-
id,
|
|
214
|
-
name,
|
|
215
|
-
bundleIds,
|
|
216
|
-
...(minQuantities ? { minQuantities } : {}),
|
|
217
|
-
prices: {
|
|
218
|
-
monthly: envCents(process.env[`BILLING_COMBO_${id.toUpperCase()}_MONTHLY`], monthly),
|
|
219
|
-
annual: envCents(process.env[`BILLING_COMBO_${id.toUpperCase()}_ANNUAL`], annual),
|
|
220
|
-
},
|
|
221
|
-
sortOrder,
|
|
222
|
-
isActive: true,
|
|
223
|
-
});
|
|
224
|
-
const combos = [
|
|
225
|
-
c('analytics_suite', 'Analytics Suite', ['advanced_reporting', 'team_usage_analytics'], 4200, 42000, 0),
|
|
226
|
-
// Team Growth — ≥5 Seats ($19.99 ea) + Team Usage Analytics ($30). Basket
|
|
227
|
-
// 5×$19.99 + $30 = $129.95/mo → bundled $90.99/mo (~30% off, ~$38.96 credit).
|
|
228
|
-
c('team_growth', 'Team Growth Bundle', ['seat', 'team_usage_analytics'], 9099, 90990, 1, { seat: 5 }),
|
|
229
|
-
// Compliance Suite — Standard + Advanced at 30% off ($908.60/yr vs $1,298 list).
|
|
230
|
-
c('compliance_suite', 'Compliance Suite', ['compliance_standard', 'compliance_advanced'], 9086, 90860, 2),
|
|
231
|
-
// Scale Bundle — API Pack ($19.99) + Storage Pack ($19.99). Basket $39.98/mo →
|
|
232
|
-
// bundled $27.99/mo (~30% off, ~$11.99 credit). Both members all-tier.
|
|
233
|
-
c('scale_bundle', 'Scale Bundle', ['api_pack', 'storage_pack'], 2799, 27990, 3),
|
|
234
|
-
];
|
|
235
|
-
assertCombosValid(combos, bundles);
|
|
236
|
-
warnOnNonDiscountCombos(combos, bundles);
|
|
237
|
-
return combos;
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Config-load guardrail for combos: every `bundleId` must resolve to an ACTIVE
|
|
241
|
-
* bundle and every `minQuantities` key must be one of the combo's `bundleIds`.
|
|
242
|
-
* A typo'd member or stray minQuantity key otherwise ships a permanently-inert
|
|
243
|
-
* combo (missing bundle treated as unit price 0, or a min never satisfiable),
|
|
244
|
-
* silently never applying. Throws so misconfig fails fast at boot.
|
|
245
|
-
*/
|
|
246
|
-
export function assertCombosValid(combos, bundles) {
|
|
247
|
-
const activeIds = new Set(bundles.filter((b) => b.isActive).map((b) => b.id));
|
|
248
|
-
for (const combo of combos) {
|
|
249
|
-
for (const id of combo.bundleIds) {
|
|
250
|
-
if (!activeIds.has(id)) {
|
|
251
|
-
throw new Error(`Combo "${combo.id}" references bundle "${id}", which is not an active bundle.`);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
for (const key of Object.keys(combo.minQuantities ?? {})) {
|
|
255
|
-
if (!combo.bundleIds.includes(key)) {
|
|
256
|
-
throw new Error(`Combo "${combo.id}" minQuantities key "${key}" is not one of its bundleIds.`);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
/** The volume-discount percent applying to `quantity` units of a bundle — the
|
|
262
|
-
* highest `volumeTiers` entry whose `minQuantity ≤ quantity`, else 0. Mirrors
|
|
263
|
-
* `volumeDiscountPct` in api/billing's combo-pricing (which can't be imported the
|
|
264
|
-
* other way); the combo credit math and this guardrail MUST use the same basis. */
|
|
265
|
-
function volumeDiscountPctAt(bundle, quantity) {
|
|
266
|
-
let pct = 0;
|
|
267
|
-
for (const t of bundle?.volumeTiers ?? [])
|
|
268
|
-
if (quantity >= t.minQuantity)
|
|
269
|
-
pct = t.discountPercent;
|
|
270
|
-
return pct;
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Guardrail: a combo whose combined price is ≥ its minimum-composition basket grants
|
|
274
|
-
* no credit (the credit clamps to $0) and is silently inert. Warn loudly instead so a
|
|
275
|
-
* misconfigured `BILLING_COMBO_*` override is caught. Non-fatal.
|
|
276
|
-
*/
|
|
277
|
-
function warnOnNonDiscountCombos(combos, bundles) {
|
|
278
|
-
// Combo members are always bundles; resolve their (env-effective) unit prices once.
|
|
279
|
-
const byId = new Map(bundles.map((b) => [b.id, b]));
|
|
280
|
-
for (const combo of combos) {
|
|
281
|
-
for (const interval of ['monthly', 'annual']) {
|
|
282
|
-
// Post-volume basis (mirrors `comboBasisCents`): a member with volume tiers is
|
|
283
|
-
// basised on its DISCOUNTED unit at the combo's minQty, so this guardrail can't
|
|
284
|
-
// silently miss a combo that grants no real credit once volume is applied.
|
|
285
|
-
const basket = combo.bundleIds.reduce((s, id) => {
|
|
286
|
-
const b = byId.get(id);
|
|
287
|
-
const qty = combo.minQuantities?.[id] ?? 1;
|
|
288
|
-
const rawUnit = b?.prices[interval] ?? 0;
|
|
289
|
-
const unit = Math.round((rawUnit * (100 - volumeDiscountPctAt(b, qty))) / 100);
|
|
290
|
-
return s + unit * qty;
|
|
291
|
-
}, 0);
|
|
292
|
-
if (combo.prices[interval] >= basket) {
|
|
293
|
-
// eslint-disable-next-line no-console
|
|
294
|
-
console.warn(`[billing-config] Combo "${combo.id}" ${interval} price ${combo.prices[interval]} ≥ member basket ${basket}; it grants no discount.`);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
const BUNDLE_GB = 1024 * 1024 * 1024;
|
|
300
|
-
/**
|
|
301
|
-
* Apply a per-bundle grant override. Each stackable pack grants exactly one
|
|
302
|
-
* quota dimension, so `BILLING_BUNDLE_<ID>_GRANT` retunes that amount (e.g. make
|
|
303
|
-
* the Plugin Pack grant +50 instead of +25) — parallel to the price overrides.
|
|
304
|
-
* Ignored for multi-dimension or feature-only (empty-grant) bundles, and for a
|
|
305
|
-
* malformed/negative value.
|
|
306
|
-
*/
|
|
307
|
-
function applyGrantOverride(id, grants) {
|
|
308
|
-
const raw = process.env[`BILLING_BUNDLE_${id.toUpperCase()}_GRANT`];
|
|
309
|
-
const keys = Object.keys(grants);
|
|
310
|
-
if (raw === undefined || raw === '' || keys.length !== 1)
|
|
311
|
-
return grants;
|
|
312
|
-
const n = parseInt(raw, 10);
|
|
313
|
-
if (Number.isNaN(n) || n < 0)
|
|
314
|
-
return grants;
|
|
315
|
-
// `keys` came from a GrantMap, so its sole key is a QuotaTierLimits field.
|
|
316
|
-
return { [keys[0]]: n };
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* Apply a per-bundle tier-availability override. `BILLING_BUNDLE_<ID>_TIERS` is a
|
|
320
|
-
* JSON array of tier IDs that may purchase the bundle (e.g. `["developer","pro"]`)
|
|
321
|
-
* — parallel to the price/grant overrides. Falls back to `defaultTiers` when
|
|
322
|
-
* unset, malformed, empty, or containing an unknown tier.
|
|
323
|
-
*/
|
|
324
|
-
function applyTiersOverride(id, defaultTiers) {
|
|
325
|
-
const raw = process.env[`BILLING_BUNDLE_${id.toUpperCase()}_TIERS`];
|
|
326
|
-
if (!raw)
|
|
327
|
-
return defaultTiers;
|
|
328
|
-
try {
|
|
329
|
-
const parsed = JSON.parse(raw);
|
|
330
|
-
if (!Array.isArray(parsed) || parsed.length === 0)
|
|
331
|
-
return defaultTiers;
|
|
332
|
-
const valid = parsed.filter((t) => typeof t === 'string' && isValidTier(t));
|
|
333
|
-
return valid.length === parsed.length ? valid : defaultTiers;
|
|
334
|
-
}
|
|
335
|
-
catch {
|
|
336
|
-
return defaultTiers;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Apply a per-bundle volume-tier override. `BILLING_BUNDLE_<ID>_VOLUME_TIERS` is a
|
|
341
|
-
* JSON array of `{ minQuantity, discountPercent }` (e.g.
|
|
342
|
-
* `[{"minQuantity":5,"discountPercent":10}]`) — parallel to the price/grant/tier
|
|
343
|
-
* overrides. Falls back to `defaultTiers` when unset, malformed, or containing an
|
|
344
|
-
* invalid entry (minQuantity ≥ 1, 0 < discountPercent ≤ 100). Sorted ascending by
|
|
345
|
-
* minQuantity so the "highest matching tier wins" lookup is deterministic.
|
|
346
|
-
*/
|
|
347
|
-
function applyVolumeTiersOverride(id, defaultTiers) {
|
|
348
|
-
const raw = process.env[`BILLING_BUNDLE_${id.toUpperCase()}_VOLUME_TIERS`];
|
|
349
|
-
const sortAsc = (t) => [...t].sort((a, b) => a.minQuantity - b.minQuantity);
|
|
350
|
-
const fallback = () => (defaultTiers ? sortAsc(defaultTiers) : undefined);
|
|
351
|
-
if (!raw)
|
|
352
|
-
return fallback();
|
|
353
|
-
try {
|
|
354
|
-
const parsed = JSON.parse(raw);
|
|
355
|
-
if (!Array.isArray(parsed) || parsed.length === 0)
|
|
356
|
-
return fallback();
|
|
357
|
-
// Each entry: integer minQuantity ≥ 1, 0 < discountPercent ≤ 100.
|
|
358
|
-
const valid = parsed.filter((t) => t && typeof t.minQuantity === 'number' && Number.isInteger(t.minQuantity) && t.minQuantity >= 1
|
|
359
|
-
&& typeof t.discountPercent === 'number' && t.discountPercent > 0 && t.discountPercent <= 100);
|
|
360
|
-
if (valid.length !== parsed.length)
|
|
361
|
-
return fallback();
|
|
362
|
-
const sorted = sortAsc(valid);
|
|
363
|
-
// Reject a non-monotonic curve: buying MORE must never earn a SMALLER discount,
|
|
364
|
-
// and duplicate thresholds are ambiguous. (`volumeDiscountPct` picks the last
|
|
365
|
-
// qualifying tier, so a descending percent would penalize higher quantities.)
|
|
366
|
-
for (let i = 1; i < sorted.length; i++) {
|
|
367
|
-
if (sorted[i].minQuantity === sorted[i - 1].minQuantity)
|
|
368
|
-
return fallback();
|
|
369
|
-
if (sorted[i].discountPercent <= sorted[i - 1].discountPercent)
|
|
370
|
-
return fallback();
|
|
371
|
-
}
|
|
372
|
-
return sorted;
|
|
373
|
-
}
|
|
374
|
-
catch {
|
|
375
|
-
return fallback();
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* Purchasable add-on bundles (docs/billing-bundles.md §3). Grants are per-unit
|
|
380
|
-
* deltas on QuotaTierLimits; prices (cents, `BILLING_BUNDLE_<ID>_MONTHLY` /
|
|
381
|
-
* `_ANNUAL`), the single-dimension grant amount (`BILLING_BUNDLE_<ID>_GRANT`),
|
|
382
|
-
* and the purchasable-tier list (`BILLING_BUNDLE_<ID>_TIERS`) are all
|
|
383
|
-
* env-overridable. Annual ≈ 10× monthly.
|
|
384
|
-
*/
|
|
385
|
-
function loadBundles() {
|
|
386
|
-
const b = (id, name, description, grants, monthly, availableForTiers, sortOrder, extra = {}) => {
|
|
387
|
-
// Resolve monthly first so the annual fallback tracks a `_MONTHLY` override
|
|
388
|
-
// (annual ≈ 10× the *effective* monthly, not the hardcoded default).
|
|
389
|
-
const resolvedMonthly = envCents(process.env[`BILLING_BUNDLE_${id.toUpperCase()}_MONTHLY`], monthly);
|
|
390
|
-
const volumeTiers = applyVolumeTiersOverride(id, extra.volumeTiers);
|
|
391
|
-
return {
|
|
392
|
-
id,
|
|
393
|
-
name,
|
|
394
|
-
description,
|
|
395
|
-
grants: applyGrantOverride(id, grants),
|
|
396
|
-
...(extra.features ? { features: extra.features } : {}),
|
|
397
|
-
...(extra.maxQuantity !== undefined ? { maxQuantity: extra.maxQuantity } : {}),
|
|
398
|
-
...(extra.requires ? { requires: extra.requires } : {}),
|
|
399
|
-
...(extra.requiresFeatures ? { requiresFeatures: extra.requiresFeatures } : {}),
|
|
400
|
-
...(volumeTiers ? { volumeTiers } : {}),
|
|
401
|
-
prices: {
|
|
402
|
-
monthly: resolvedMonthly,
|
|
403
|
-
annual: envCents(process.env[`BILLING_BUNDLE_${id.toUpperCase()}_ANNUAL`], resolvedMonthly * 10),
|
|
404
|
-
},
|
|
405
|
-
stackable: extra.stackable ?? true,
|
|
406
|
-
availableForTiers: applyTiersOverride(id, availableForTiers),
|
|
407
|
-
isActive: true,
|
|
408
|
-
sortOrder,
|
|
409
|
-
};
|
|
410
|
-
};
|
|
411
|
-
// Bundles are purchasable on every SELECTABLE tier (excludes `unlimited`, which
|
|
412
|
-
// is the billing-off tier and buys nothing) — so this is exactly STANDARD_TIERS.
|
|
413
|
-
const ALL = [...STANDARD_TIERS];
|
|
414
|
-
const bundles = [
|
|
415
|
-
// `seat` and `pipeline_pack` are the tier differentiators, so both are Team+
|
|
416
|
-
// ONLY — a single-seat Developer/Pro can't cheaply stack seats/pipelines to
|
|
417
|
-
// undercut Team (3 seats / 6 pipelines); they must upgrade. `seat` is granular
|
|
418
|
-
// (per-seat) with volume tiers (5/15/40 → 10/20/30%). The other capacity packs
|
|
419
|
-
// (plugin/api/ai/storage) are NOT differentiators, so they stay all-tier.
|
|
420
|
-
b('seat', 'Member Seat', '1 additional member seat', { seats: 1 }, 1999, ['team', 'enterprise'], 0, { volumeTiers: [{ minQuantity: 5, discountPercent: 10 }, { minQuantity: 15, discountPercent: 20 }, { minQuantity: 40, discountPercent: 30 }] }),
|
|
421
|
-
b('pipeline_pack', 'Pipeline Pack (+5)', '5 additional pipelines', { pipelines: 5 }, 1500, ['team', 'enterprise'], 1),
|
|
422
|
-
b('plugin_pack', 'Plugin Pack (+25)', '25 additional plugins', { plugins: 25 }, 1000, ALL, 2),
|
|
423
|
-
b('api_pack', 'API Pack (+100k)', '100,000 additional API calls / period', { apiCalls: 100_000 }, 1999, ALL, 3),
|
|
424
|
-
b('ai_pack', 'AI Pack (+2.5k)', '2,500 additional AI calls / period', { aiCalls: 2500 }, 1999, ALL, 4),
|
|
425
|
-
b('storage_pack', 'Storage Pack (+10 GB)', '10 GB additional registry storage', { storageBytes: 10 * BUNDLE_GB }, 1999, ALL, 5),
|
|
426
|
-
// NOTE: `sso` is NOT sold as an add-on. It is a TIER feature from Team up
|
|
427
|
-
// (TIER_FEATURES.team) and nothing below Team can buy it. The bundle that
|
|
428
|
-
// used to exist here was $40/mo on Pro only — Pro ($39) + the add-on came to
|
|
429
|
-
// exactly Team ($79), which already includes SSO *and* teams *and* domain
|
|
430
|
-
// registration, so it was strictly dominated. It was also functionally
|
|
431
|
-
// broken below Team: SSO refuses an identity whose email domain the org has
|
|
432
|
-
// not DNS-verified (`assertSsoIdentityTrusted`, which exempts only
|
|
433
|
-
// Google-issued identities), and registering a domain to verify is ITSELF a
|
|
434
|
-
// hard Team/Enterprise tier check (platform `org-domain-service`). So a Pro
|
|
435
|
-
// buyer's Okta / Entra / generic-OIDC / SAML connection failed at callback
|
|
436
|
-
// with OIDC_EMAIL_DOMAIN_NOT_VERIFIED, with no way to fix it on Pro. Selling
|
|
437
|
-
// SSO below Team would mean giving away domain registration too, and that is
|
|
438
|
-
// the Team differentiator.
|
|
439
|
-
// DORA / advanced delivery analytics. INCLUDED in Enterprise (TIER_FEATURES),
|
|
440
|
-
// so the add-on is offered to every other tier (developer/pro/team). Priced
|
|
441
|
-
// as an analytics surface, not an enterprise identity gate.
|
|
442
|
-
// Lead time is MEASURED commit → deploy (reporting's deploy events), not a proxy.
|
|
443
|
-
b('advanced_reporting', 'Advanced Reporting (DORA)', 'DORA delivery metrics — deployment frequency, lead time (commit → deploy), change failure rate, MTTR, performance bands + trend', {}, 3000, ['developer', 'pro', 'team'], 8, { features: ['advanced_reporting'], stackable: false }),
|
|
444
|
-
// Per-team usage breakdown across the org → team subtree. INCLUDED in
|
|
445
|
-
// Enterprise (TIER_FEATURES); the add-on is offered to Team only — Developer
|
|
446
|
-
// and Pro can't nest teams (TEAM_CAPABLE_TIERS), so there'd be nothing to
|
|
447
|
-
// break down. Priced at $30/mo ($300/yr) — parity with DORA, its analytics
|
|
448
|
-
// sibling. Overridable via BILLING_BUNDLE_TEAM_USAGE_ANALYTICS_MONTHLY/_ANNUAL.
|
|
449
|
-
b('team_usage_analytics', 'Team Usage Analytics', 'Per-team usage breakdown across the org → team subtree (all quota dimensions)', {}, 3000, ['team'], 9, { features: ['team_usage_analytics'], stackable: false }),
|
|
450
|
-
// Retention packs (docs/billing-bundles.md). Stackable capacity packs that
|
|
451
|
-
// raise the reporting retention entitlement billing syncs to reporting's
|
|
452
|
-
// `dora_settings`. NOT quota-metered flow — `eventRetentionDays`/`doraRetentionDays`
|
|
453
|
-
// are absent from VALID_QUOTA_TYPES, so they never ride the quota-service leg.
|
|
454
|
-
// Standard Retention Pack: +90d standard-event retention (base 30 → 120 → 210…).
|
|
455
|
-
// Capped at 7 (30 + 7×90 = 660 ≤ the 730-day retention ceiling).
|
|
456
|
-
b('retention_pack', 'Standard Retention Pack (+90d)', '90 additional days of standard pipeline-event retention', { eventRetentionDays: 90 }, 1500, ALL, 10, { maxQuantity: 7 }),
|
|
457
|
-
// DORA History Pack: +365d DORA retention AND per-org report-query window (the
|
|
458
|
-
// window cap tracks doraRetentionDays). Only meaningful with Advanced Reporting
|
|
459
|
-
// — INCLUDED in Enterprise, an add-on on developer/pro/team — so it
|
|
460
|
-
// `requiresFeatures` it (the tier OR a held bundle satisfies it). Capped at 1
|
|
461
|
-
// (180 + 365 = 545 ≤ the 730-day retention ceiling).
|
|
462
|
-
b('dora_history_pack', 'DORA History Pack (+365d)', '365 additional days of DORA history + report-query window (requires Advanced Reporting)', { doraRetentionDays: 365 }, 3000, ALL, 11, { maxQuantity: 1, requiresFeatures: ['advanced_reporting'] }),
|
|
463
|
-
// Compliance content add-ons (docs/plans/compliance-addons.md). Feature bundles
|
|
464
|
-
// gating access to curated system-org published rule sets. INCLUDED in
|
|
465
|
-
// Enterprise/Unlimited (via ALL_FEATURE_FLAGS); sold to Developer/Pro/Team.
|
|
466
|
-
// Standard = ~20 CI/CD best-practice rules. Advanced = SOC2/PCI/CIS framework
|
|
467
|
-
// libraries; REQUIRES Standard (or buy the Suite combo for both at 30% off).
|
|
468
|
-
b('compliance_standard', 'Standard Compliance', 'Curated CI/CD best-practice compliance rules', {}, 2990, ['developer', 'pro', 'team'], 12, { features: ['compliance_standard'], stackable: false }),
|
|
469
|
-
b('compliance_advanced', 'Advanced Compliance', 'Curated framework compliance libraries (SOC2 / PCI-DSS / CIS)', {}, 9990, ['developer', 'pro', 'team'], 13, { features: ['compliance_advanced'], stackable: false, requires: ['compliance_standard'] }),
|
|
470
|
-
];
|
|
471
|
-
assertBundleRequiresValid(bundles);
|
|
472
|
-
return bundles;
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Config-load guardrail for the `requires` / `requiresFeatures` prerequisites. A
|
|
476
|
-
* `requires` entry that doesn't resolve to an ACTIVE bundle — or that participates
|
|
477
|
-
* in a cycle — silently makes the referencing bundle unpurchasable (the addon
|
|
478
|
-
* route rejects with 400 forever because the prerequisite can never be
|
|
479
|
-
* satisfied). Catch it at load with a clear error rather than shipping a dead SKU.
|
|
480
|
-
*
|
|
481
|
-
* - Every id in a bundle's `requires` MUST name an active bundle in the catalog.
|
|
482
|
-
* - The `requires` graph MUST be acyclic (a → b → a can never be satisfied).
|
|
483
|
-
* - Every `requiresFeatures` entry MUST be a real feature flag, attainable on
|
|
484
|
-
* EVERY tier the bundle is sold to — either tier-included (`TIER_FEATURES`) or
|
|
485
|
-
* granted by an active bundle offered on that same tier.
|
|
486
|
-
*/
|
|
487
|
-
export function assertBundleRequiresValid(bundles) {
|
|
488
|
-
const active = new Map(bundles.filter((b) => b.isActive).map((b) => [b.id, b]));
|
|
489
|
-
// 1. Validity: every requires id resolves to an active bundle.
|
|
490
|
-
for (const bundle of bundles) {
|
|
491
|
-
for (const reqId of bundle.requires ?? []) {
|
|
492
|
-
if (!active.has(reqId)) {
|
|
493
|
-
throw new Error(`[billing-config] Bundle "${bundle.id}" requires "${reqId}", which is not an active bundle in the catalog — it would be permanently unpurchasable.`);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
// 1b. Feature prerequisites: a real flag, attainable on every sold-to tier.
|
|
498
|
-
for (const bundle of bundles) {
|
|
499
|
-
for (const flag of bundle.requiresFeatures ?? []) {
|
|
500
|
-
if (!isValidFeatureFlag(flag)) {
|
|
501
|
-
throw new Error(`[billing-config] Bundle "${bundle.id}" requiresFeatures "${flag}", which is not a feature flag.`);
|
|
502
|
-
}
|
|
503
|
-
for (const tier of bundle.availableForTiers) {
|
|
504
|
-
const tierIncludes = (TIER_FEATURES[tier] ?? []).includes(flag);
|
|
505
|
-
const buyable = [...active.values()].some((o) => o.availableForTiers.includes(tier) && (o.features ?? []).includes(flag));
|
|
506
|
-
if (!tierIncludes && !buyable) {
|
|
507
|
-
throw new Error(`[billing-config] Bundle "${bundle.id}" requires feature "${flag}", which the ${tier} tier neither includes nor can buy — it would be permanently unpurchasable there.`);
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
// 2. Acyclicity: DFS over the requires edges, tracking the current path.
|
|
513
|
-
const VISITING = 1;
|
|
514
|
-
const DONE = 2;
|
|
515
|
-
const state = new Map();
|
|
516
|
-
const visit = (id, path) => {
|
|
517
|
-
const s = state.get(id);
|
|
518
|
-
if (s === DONE)
|
|
519
|
-
return;
|
|
520
|
-
if (s === VISITING) {
|
|
521
|
-
const cycle = [...path.slice(path.indexOf(id)), id].join(' -> ');
|
|
522
|
-
throw new Error(`[billing-config] Bundle "requires" cycle detected: ${cycle}.`);
|
|
523
|
-
}
|
|
524
|
-
state.set(id, VISITING);
|
|
525
|
-
for (const reqId of active.get(id)?.requires ?? []) {
|
|
526
|
-
visit(reqId, [...path, id]);
|
|
527
|
-
}
|
|
528
|
-
state.set(id, DONE);
|
|
529
|
-
};
|
|
530
|
-
for (const bundle of active.keys()) {
|
|
531
|
-
visit(bundle, []);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmlsbGluZy1jb25maWcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uZmlnL2JpbGxpbmctY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsT0FBTyxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsZ0JBQWdCLEVBQUUsV0FBVyxFQUFFLGNBQWMsRUFBRSxrQkFBa0IsRUFBRSxXQUFXLEVBQXdDLE1BQU0sNEJBQTRCLENBQUM7QUFPOUwsZ0ZBQWdGO0FBQ2hGLDhFQUE4RTtBQUM5RSxrREFBa0Q7QUFDbEQsa0ZBQWtGO0FBQ2xGLGlEQUFpRDtBQUNqRCx3RUFBd0U7QUFDeEUsMkVBQTJFO0FBQzNFLDZFQUE2RTtBQUM3RSwrRUFBK0U7QUFDL0UsZ0VBQWdFO0FBQ2hFLDZFQUE2RTtBQUM3RSwrRUFBK0U7QUFDL0UsMkVBQTJFO0FBQzNFLDhEQUE4RDtBQUU5RCx3RkFBd0Y7QUFDeEYsU0FBUyxTQUFTLENBQUMsS0FBYSxFQUFFLFFBQWdCLEVBQUUsTUFBYztJQUNoRSxJQUFJLEtBQUssS0FBSyxDQUFDLENBQUM7UUFBRSxPQUFPLGFBQWEsTUFBTSxFQUFFLENBQUM7SUFDL0MsT0FBTyxTQUFTLEtBQUssQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLElBQUksS0FBSyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztBQUNyRixDQUFDO0FBRUQsU0FBUyxlQUFlLENBQUMsSUFBZSxFQUFFLEtBQWU7SUFDdkQsTUFBTSxDQUFDLEdBQUcsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNuQyxPQUFPO1FBQ0wsU0FBUyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQztRQUNuQyxTQUFTLENBQUMsQ0FBQyxDQUFDLE9BQU8s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SSxFQUFFLEVBQUUsQ0FBQztZQUNuRCxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUMsR0FBRyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUM5QixDQUFDO1FBQ0QsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDdEIsQ0FBQyxDQUFDO0lBRUYsS0FBSyxNQUFNLE1BQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQztRQUNuQyxLQUFLLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3BCLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogTG9hZCBiaWxsaW5nIHBsYW4gY29uZmlndXJhdGlvbiBmcm9tIGVudmlyb25tZW50IHZhcmlhYmxlcy5cbiAqXG4gKiBQZXItcGxhbiBwcmljZXMgYXJlIHRoZSBtb3N0IGxpa2VseSB0byB2YXJ5IGJldHdlZW4gZW52aXJvbm1lbnRzOlxuICogICBCSUxMSU5HX1BMQU5fe1RJRVJ9X01PTlRITFkgLyBCSUxMSU5HX1BMQU5fe1RJRVJ9X0FOTlVBTCAgKGluIGNlbnRzKVxuICpcbiAqIE9wdGlvbmFsIG92ZXJyaWRlcyBmb3IgZGVzY3JpcHRpb25zIGFuZCBmZWF0dXJlczpcbiAqICAgQklMTElOR19QTEFOX3tUSUVSfV9OQU1FICAgICAgICAgIChwbGFpbiBzdHJpbmcsIGRpc3BsYXkgbmFtZSlcbiAqICAgQklMTElOR19QTEFOX3tUSUVSfV9ERVNDUklQVElPTiAgIChwbGFpbiBzdHJpbmcpXG4gKiAgIEJJTExJTkdfUExBTl97VElFUn1fRkVBVFVSRVMgICAgICAoSlNPTiBzdHJpbmcgYXJyYXkpXG4gKlxuICogQWxsIGRlZmF1bHRzIG1hdGNoIHRoZSBvcmlnaW5hbCBoYXJkY29kZWQgc2VlZCBkYXRhLlxuICovXG5pbXBvcnQgeyBRVU9UQV9USUVSUywgVElFUl9GRUFUVVJFUywgRkVBVFVSRV9NRVRBREFUQSwgVkFMSURfVElFUlMsIFNUQU5EQVJEX1RJRVJTLCBpc1ZhbGlkRmVhdHVyZUZsYWcsIGlzVmFsaWRUaWVyLCB0eXBlIFF1b3RhVGllciwgdHlwZSBRdW90YVRpZXJMaW1pdHMgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgdHlwZSB7IEJpbGxpbmdDb25maWcsIEJpbGxpbmdQbGFuQ29uZmlnLCBCdW5kbGVDb25maWcsIENvbWJvRGlzY291bnRDb25maWcgfSBmcm9tICcuL2NvbmZpZy10eXBlcy5qcyc7XG5cbi8qKiBQZXItdW5pdCBxdW90YSBkZWx0YXMgZm9yIGEgYnVuZGxlIOKAlCBrZXlzIGNvbnN0cmFpbmVkIHRvIHJlYWwgcXVvdGEgZmllbGRzXG4gKiAgKG1hdGNoZXMgYEJ1bmRsZUNvbmZpZy5ncmFudHNgKSwgc28gYSB0eXBvJ2QgZGltZW5zaW9uIGZhaWxzIHRvIGNvbXBpbGUuICovXG50eXBlIEdyYW50TWFwID0gUGFydGlhbDxSZWNvcmQ8a2V5b2YgUXVvdGFUaWVyTGltaXRzLCBudW1iZXI+PjtcblxuLy8gLS0gRGVmYXVsdCBmZWF0dXJlcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFRoZSBtYXJrZXRlZCBmZWF0dXJlIGxpc3QgaXMgYnVpbHQgZnJvbSB0d28gZGVyaXZlZCBzb3VyY2VzIHNvIGl0IGNhbiBuZXZlclxuLy8gZHJpZnQgZnJvbSB3aGF0IHRoZSBwbGF0Zm9ybSBhY3R1YWxseSBlbmZvcmNlczpcbi8vICAgMS4gTElNSVQgbGluZXMgZGVyaXZlZCBmcm9tIGVhY2ggdGllcidzIEVGRkVDVElWRSBxdW90YSBsaW1pdHMgKFFVT1RBX1RJRVJTKSxcbi8vICAgICAgc28gdGhleSB0cmFjayBRVU9UQV9USUVSXyogZW52IG92ZXJyaWRlcy5cbi8vICAgMi4gSU5DTFVERUQtRkVBVFVSRSBsaW5lcyBkZXJpdmVkIGZyb20gdGhlIGVuZm9yY2VkIGVudGl0bGVtZW50IHNldFxuLy8gICAgICAoVElFUl9GRUFUVVJFUykgdmlhIEZFQVRVUkVfTUVUQURBVEEgbGFiZWxzIOKAlCBzbyBhbiBhZHZlcnRpc2VkIGJhc2Vcbi8vICAgICAgZmVhdHVyZSBpcyBhbHdheXMgb25lIGByZXF1aXJlRmVhdHVyZWAgYWN0dWFsbHkgZ3JhbnRzIGZvciB0aGF0IHRpZXIuXG4vLyBPbmx5IGdlbnVpbmVseSBub24tZ2F0ZWQgbWFya2V0aW5nIGNvcHkgKHN1cHBvcnQgbGV2ZWwsIGRhc2hib2FyZHMsIFJCQUMpIGlzXG4vLyBoYW5kLWF1dGhvcmVkLCBwYXNzZWQgYXMgYHBlcmtzYC4gUHVyY2hhc2FibGUgZmVhdHVyZSBhZGQtb25zXG4vLyAoYWR2YW5jZWRfcmVwb3J0aW5nLCB0ZWFtX3VzYWdlX2FuYWx5dGljcywgY29tcGxpYW5jZV8qKSBhcmUgTk9UIGxpc3RlZCBhc1xuLy8gYmFzZSBwZXJrcyBoZXJlIOKAlCB0aGV5IGFyZSBzb2xkIGFzIGJ1bmRsZXMgKHNlZSBsb2FkQnVuZGxlcygpKS4gYHNzb2AgaXMgdGhlXG4vLyBvdGhlciB3YXkgcm91bmQ6IGEgVElFUiBmZWF0dXJlIG9ubHkgKFRlYW0rKSwgbmV2ZXIgYSBidW5kbGUsIHNvIGl0IERPRVNcbi8vIGFwcGVhciBhcyBhIGRlcml2ZWQgYmFzZSBwZXJrIG9uIHRoZSB0aWVycyB0aGF0IGluY2x1ZGUgaXQuXG5cbi8qKiBcIlVwIHRvIE4gcGx1Z2luc1wiIC8gXCJVbmxpbWl0ZWQgcGx1Z2luc1wiIGZyb20gYW4gZWZmZWN0aXZlIGxpbWl0ICgtMSA9IHVubGltaXRlZCkuICovXG5mdW5jdGlvbiBsaW1pdExpbmUobGltaXQ6IG51bWJlciwgc2luZ3VsYXI6IHN0cmluZywgcGx1cmFsOiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAobGltaXQgPT09IC0xKSByZXR1cm4gYFVubGltaXRlZCAke3BsdXJhbH1gO1xuICByZXR1cm4gYFVwIHRvICR7bGltaXQudG9Mb2NhbGVTdHJpbmcoJ2VuLVVTJyl9ICR7bGltaXQgPT09IDEgPyBzaW5ndWxhciA6IHBsdXJhbH1gO1xufVxuXG5mdW5jdGlvbiBkZWZhdWx0RmVhdHVyZXModGllcjogUXVvdGFUaWVyLCBwZXJrczogc3RyaW5nW10pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IGwgPSBRVU9UQV9USUVSU1t0aWVyXS5saW1pdHM7XG4gIHJldHVybiBbXG4gICAgbGltaXRMaW5lKGwuc2VhdHMsICdzZWF0JywgJ3NlYXRzJyksXG4gICAgbGltaXRMaW5lKGwucGx1Z2lucywgJ3BsdWdpbicsICdwbHVnaW5zJyksXG4gICAgbGltaXRMaW5lKGwucGlwZWxpbmVzLCAncGlwZWxpbmUnLCAncGlwZWxpbmVzJyksXG4gICAgbGltaXRMaW5lKGwuYXBpQ2FsbHMsICdBUEkgY2FsbCcsICdBUEkgY2FsbHMnKSxcbiAgICBsaW1pdExpbmUobC5haUNhbGxzLCAnQUkgY2FsbCcsICdBSSBjYWxscycpLFxuICAgIC8vIEVuZm9yY2VkIGVudGl0bGVtZW50cyDihpIgY3VzdG9tZXItZmFjaW5nIGxhYmVscyAoc2luZ2xlIHNvdXJjZSBvZiB0cnV0aCkuXG4gICAgLi4uVElFUl9GRUFUVVJFU1t0aWVyXS5tYXAoKGYpID0+IEZFQVRVUkVfTUVUQURBVEFbZl0ubGFiZWwpLFxuICAgIC4uLnBlcmtzLFxuICBdO1xufVxuXG4vLyBOb3RlOiBgcGVya3NgIGFyZSBub24tZ2F0ZWQgbWFya2V0aW5nIGxpbmVzIG9ubHkuIEVuZm9yY2VkIGZlYXR1cmVzIChpbmNsLlxuLy8gUHJpb3JpdHkgU3VwcG9ydCBmb3IgcHJvL3RlYW0vZW50ZXJwcmlzZSkgY29tZSBmcm9tIFRJRVJfRkVBVFVSRVMgYWJvdmUuXG4vLyBUaGUgcmVwb3J0aW5nIGRhc2hib2FyZCBpcyBvcGVuIHRvIGV2ZXJ5IHRpZXIgKG9ubHkgdGhlIERPUkEvc2NvcmVjYXJkIHZpZXdzXG4vLyBhcmUgZW50aXRsZW1lbnQtZ2F0ZWQpLCBzbyBpdCdzIGxpc3RlZCBvbiBlYWNoIHBsYW4gcmF0aGVyIHRoYW4gaW1wbHlpbmcgYVxuLy8gbG93ZXIgdGllciBsYWNrcyBpdC5cbmNvbnN0IERFRkFVTFRfREVWRUxPUEVSX0ZFQVRVUkVTID0gZGVmYXVsdEZlYXR1cmVzKCdkZXZlbG9wZXInLCBbJ0NvbW11bml0eSBzdXBwb3J0JywgJ1JlcG9ydGluZyBkYXNoYm9hcmQnXSk7XG5jb25zdCBERUZBVUxUX1BST19GRUFUVVJFUyA9IGRlZmF1bHRGZWF0dXJlcygncHJvJywgWydSZXBvcnRpbmcgZGFzaGJvYXJkJ10pO1xuY29uc3QgREVGQVVMVF9URUFNX0ZFQVRVUkVTID0gZGVmYXVsdEZlYXR1cmVzKCd0ZWFtJywgWydSQkFDICYgdGVhbSByb2xlcycsICdSZXBvcnRpbmcgZGFzaGJvYXJkJ10pO1xuY29uc3QgREVGQVVMVF9FTlRFUlBSSVNFX0ZFQVRVUkVTID0gZGVmYXVsdEZlYXR1cmVzKCdlbnRlcnByaXNlJywgW1xuICAnUkJBQyAmIHRlYW0gcm9sZXMnLCAnUmVwb3J0aW5nIGRhc2hib2FyZCcsXG5dKTtcbi8vIFVubGltaXRlZCBpbmNsdWRlcyBldmVyeSBmZWF0dXJlIChUSUVSX0ZFQVRVUkVTLnVubGltaXRlZCA9IGFsbCkuXG5jb25zdCBERUZBVUxUX1VOTElNSVRFRF9GRUFUVVJFUyA9IGRlZmF1bHRGZWF0dXJlcygndW5saW1pdGVkJywgW1xuICAnVW5saW1pdGVkIGV2ZXJ5dGhpbmcnLCAnUkJBQyAmIHRlYW0gcm9sZXMnLCAnUmVwb3J0aW5nIGRhc2hib2FyZCcsXG5dKTtcblxuLyoqXG4gKiBQYXJzZSBhIHByaWNlIChpbiBjZW50cykgZnJvbSBhbiBlbnYgdmFyLCBmYWxsaW5nIGJhY2sgdG8gdGhlIGRlZmF1bHQgd2hlblxuICogdW5zZXQgT1IgbWFsZm9ybWVkLiBBIE5hTiAoZS5nLiBgQklMTElOR19QTEFOX1BST19NT05USExZPWFiY2ApIG11c3QgbmV2ZXJcbiAqIGZsb3cgaW50byB0aGUgcmV0dXJuZWQgY29uZmlnIGFzIGEgcHJpY2UuXG4gKi9cbmZ1bmN0aW9uIGVudkNlbnRzKGVudlZhcjogc3RyaW5nIHwgdW5kZWZpbmVkLCBmYWxsYmFjazogbnVtYmVyKTogbnVtYmVyIHtcbiAgaWYgKGVudlZhciA9PT0gdW5kZWZpbmVkIHx8IGVudlZhciA9PT0gJycpIHJldHVybiBmYWxsYmFjaztcbiAgLy8gYHBhcnNlSW50YCBpcyB0b28gbGVuaWVudCBoZXJlOiAnNDkuOTkn4oaSNDksICc0OWFiYyfihpI0OSwgJy0xMDAn4oaSLTEwMCB3b3VsZCBhbGxcbiAgLy8gZmxvdyB0aHJvdWdoIGFzIGEgXCJwcmljZVwiLiBSZXF1aXJlIGEgY2xlYW4sIG5vbi1uZWdhdGl2ZSBpbnRlZ2VyIChjZW50cyksXG4gIC8vIG1hdGNoaW5nIGBhcHBseUdyYW50T3ZlcnJpZGVgJ3Mgcmlnb3Ig4oCUIGFueXRoaW5nIGVsc2UgZmFsbHMgYmFjay5cbiAgY29uc3QgbiA9IE51bWJlcihlbnZWYXIpO1xuICByZXR1cm4gTnVtYmVyLmlzSW50ZWdlcihuKSAmJiBuID49IDAgPyBuIDogZmFsbGJhY2s7XG59XG5cbi8qKlxuICogUGFyc2UgYSBKU09OIGFycmF5IGZyb20gYW4gZW52IHZhciwgZmFsbGluZyBiYWNrIHRvIGRlZmF1bHQuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlRmVhdHVyZXMoZW52VmFyOiBzdHJpbmcgfCB1bmRlZmluZWQsIGZhbGxiYWNrOiBzdHJpbmdbXSk6IHN0cmluZ1tdIHtcbiAgaWYgKCFlbnZWYXIpIHJldHVybiBmYWxsYmFjaztcbiAgdHJ5IHtcbiAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKGVudlZhcik7XG4gICAgLy8gQXJyYXktb2Ytc3RyaW5ncyBvbmx5IOKAlCBhIEpTT04gYXJyYXkgb2Ygbm9uLXN0cmluZ3MgKGUuZy4gYFsxLDJdYCkgbXVzdCBub3RcbiAgICAvLyBzaGlwIG51bWJlcnMgYXMgZmVhdHVyZSBsYWJlbHMuIEZpbHRlciB0byBzdHJpbmdzIChtaXJyb3JzIGFwcGx5VGllcnNPdmVycmlkZSkuXG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHBhcnNlZCkpIHJldHVybiBmYWxsYmFjaztcbiAgICBjb25zdCBzdHJpbmdzID0gcGFyc2VkLmZpbHRlcigoeCk6IHggaXMgc3RyaW5nID0+IHR5cGVvZiB4ID09PSAnc3RyaW5nJyk7XG4gICAgcmV0dXJuIHN0cmluZ3MubGVuZ3RoID09PSBwYXJzZWQubGVuZ3RoID8gc3RyaW5ncyA6IGZhbGxiYWNrO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsbGJhY2s7XG4gIH1cbn1cblxuLyoqXG4gKiBMb2FkIGJpbGxpbmcgcGxhbiBjb25maWd1cmF0aW9uIGZyb20gZW52aXJvbm1lbnQgdmFyaWFibGVzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbG9hZEJpbGxpbmdDb25maWcoKTogQmlsbGluZ0NvbmZpZyB7XG4gIC8vIEtleWVkIGJ5IFF1b3RhVGllciBzbyB0aGUgY29tcGlsZXIgZm9yY2VzIGEgcGxhbiBmb3IgRVZFUlkgdGllciDigJQgYWRkaW5nIGFcbiAgLy8gNXRoIFF1b3RhVGllciB3aXRob3V0IGEgcGxhbiBoZXJlIGlzIG5vdyBhIGNvbXBpbGUgZXJyb3IgKHdhcyBhIGhhbmQta2VwdFxuICAvLyA0LWVsZW1lbnQgYXJyYXkgdGhhdCBzaWxlbnRseSBzaGlwcGVkIG5vIHBsYW4vcHJpY2UgZm9yIGEgbmV3IHRpZXIpLiBUaGVcbiAgLy8gcHVibGljIGBjb25maWcucGxhbnNgIHNoYXBlIHN0YXlzIGFuIGFycmF5LCBkZXJpdmVkIGJlbG93IGluIFZBTElEX1RJRVJTXG4gIC8vIG9yZGVyIChkZXZlbG9wZXIsIHBybywgdGVhbSwgZW50ZXJwcmlzZSwgdW5saW1pdGVkKSB0byBwcmVzZXJ2ZSBjb25zdW1lciBvcmRlcmluZy5cbiAgY29uc3QgcGxhbkJ5VGllcjogUmVjb3JkPFF1b3RhVGllciwgQmlsbGluZ1BsYW5Db25maWc+ID0ge1xuICAgIGRldmVsb3Blcjoge1xuICAgICAgaWQ6ICdkZXZlbG9wZXInLFxuICAgICAgbmFtZTogcHJvY2Vzcy5lbnYuQklMTElOR19QTEFOX0RFVkVMT1BFUl9OQU1FIHx8ICdEZXZlbG9wZXInLFxuICAgICAgZGVzY3JpcHRpb246IHByb2Nlc3MuZW52LkJJTExJTkdfUExBTl9ERVZFTE9QRVJfREVTQ1JJUFRJT05cbiAgICAgICAgfHwgJ0ZyZWUgc3RhcnRlciB0aWVyIGZvciBpbmRpdmlkdWFsIGRldmVsb3BlcnMnLFxuICAgICAgdGllcjogJ2RldmVsb3BlcicsXG4gICAgICBwcmljZXM6IHtcbiAgICAgICAgbW9udGhseTogZW52Q2VudHMocHJvY2Vzcy5lbnYuQklMTElOR19QTEFOX0RFVkVMT1BFUl9NT05USExZLCAwKSxcbiAgICAgICAgYW5udWFsOiBlbnZDZW50cyhwcm9jZXNzLmVudi5CSUxMSU5HX1BMQU5fREVWRUxPUEVSX0FOTlVBTCwgMCksXG4gICAgICB9LFxuICAgICAgZmVhdHVyZXM6IHBhcnNlRmVhdHVyZXMoXG4gICAgICAgIHByb2Nlc3MuZW52LkJJTExJTkdfUExBTl9ERVZFTE9QRVJfRkVBVFVSRVMsXG4gICAgICAgIERFRkFVTFRfREVWRUxPUEVSX0ZFQVRVUkVTLFxuICAgICAgKSxcbiAgICAgIGlzQWN0aXZlOiB0cnVlLFxuICAgICAgaXNEZWZhdWx0OiB0cnVlLFxuICAgICAgc29ydE9yZGVyOiAwLFxuICAgIH0sXG4gICAgcHJvOiB7XG4gICAgICBpZDogJ3BybycsXG4gICAgICBuYW1lOiBwcm9jZXNzLmVudi5CSUxMSU5HX1BMQU5fUFJPX05BTUUgfHwgJ1BybycsXG4gICAgICBkZXNjcmlwdGlvbjogcHJvY2Vzcy5lbnYuQklMTElOR19QTEFOX1BST19ERVNDUklQVElPTlxuICAgICAgICB8fCAnRm9yIGluZGl2aWR1YWwgcG93ZXIgdXNlcnMgYW5kIHByb2R1Y3Rpb24gd29ya2xvYWRzJyxcbiAgICAgIHRpZXI6ICdwcm8nLFxuICAgICAgcHJpY2VzOiB7XG4gICAgICAgIG1vbnRobHk6IGVudkNlbnRzKHByb2Nlc3MuZW52LkJJTExJTkdfUExBTl9QUk9fTU9OVEhMWSwgMzkwMCksXG4gICAgICAgIGFubnVhbDogZW52Q2VudHMocHJvY2Vzcy5lbnYuQklMTElOR19QTEFOX1BST19BTk5VQUwsIDM5MDAwKSxcbiAgICAgIH0sXG4gICAgICBmZWF0dXJlczogcGFyc2VGZWF0dXJlcyhcbiAgICAgICAgcHJvY2Vzcy5lbnYuQklMTElOR19QTEFOX1BST19GRUFUVVJFUyxcbiAgICAgICAgREVGQVVMVF9QUk9fRkVBVFVSRVMsXG4gICAgICApLFxuICAgICAgaXNBY3RpdmU6IHRydWUsXG4gICAgICBpc0RlZmF1bHQ6IGZhbHNlLFxuICAgICAgc29ydE9yZGVyOiAxLFxuICAgIH0sXG4gICAgdGVhbToge1xuICAgICAgaWQ6ICd0ZWFtJyxcbiAgICAgIG5hbWU6IHByb2Nlc3MuZW52LkJJTExJTkdfUExBTl9URUFNX05BTUUgfHwgJ1RlYW0nLFxuICAgICAgZGVzY3JpcHRpb246IHByb2Nlc3MuZW52LkJJTExJTkdfUExBTl9URUFNX0RFU0NSSVBUSU9OXG4gICAgICAgIHx8ICdGb3IgdGVhbXMgY29sbGFib3JhdGluZyBvbiBzaGFyZWQgcGlwZWxpbmVzJyxcbiAgICAgIHRpZXI6ICd0ZWFtJyxcbiAgICAgIHByaWNlczoge1xuICAgICAgICBtb250aGx5OiBlbnZDZW50cyhwcm9jZXNzLmVudi5CSUxMSU5HX1BMQU5fVEVBTV9NT05USExZLCA3OTAwKSxcbiAgICAgICAgYW5udWFsOiBlbnZDZW50cyhwcm9jZXNzLmVudi5CSUxMSU5HX1BMQU5fVEVBTV9BTk5VQUwsIDc5MDAwKSxcbiAgICAgIH0sXG4gICAgICBmZWF0dXJlczogcGFyc2VGZWF0dXJlcyhcbiAgICAgICAgcHJvY2Vzcy5lbnYuQklMTElOR19QTEFOX1RFQU1fRkVBVFVSRVMsXG4gICAgICAgIERFRkFVTFRfVEVBTV9GRUFUVVJFUyxcbiAgICAgICksXG4gICAgICBpc0FjdGl2ZTogdHJ1ZSxcbiAgICAgIGlzRGVmYXVsdDogZmFsc2UsXG4gICAgICBzb3J0T3JkZXI6IDIsXG4gICAgfSxcbiAgICBlbnRlcnByaXNlOiB7XG4gICAgICBpZDogJ2VudGVycHJpc2UnLFxuICAgICAgbmFtZTogcHJvY2Vzcy5lbnYuQklMTElOR19QTEFOX0VOVEVSUFJJU0VfTkFNRSB8fCAnRW50ZXJwcmlzZScsXG4gICAgICBkZXNjcmlwdGlvbjogcHJvY2Vzcy5lbnYuQklMTElOR19QTEFOX0VOVEVSUFJJU0VfREVTQ1JJUFRJT05cbiAgICAgICAgfHwgJ09yZy13aWRlIHNjYWxlIHdpdGggYSBoaWdoIHNlYXQgYmFzZWxpbmUgKGV4cGFuZGFibGUgdmlhIE1lbWJlciBTZWF0IGFkZC1vbnMpIGFuZCBwcmlvcml0eSBzdXBwb3J0JyxcbiAgICAgIHRpZXI6ICdlbnRlcnByaXNlJyxcbiAgICAgIHByaWNlczoge1xuICAgICAgICBtb250aGx5OiBlbnZDZW50cyhwcm9jZXNzLmVudi5CSUxMSU5HX1BMQU5fRU5URVJQUklTRV9NT05USExZLCA1OTkwMCksXG4gICAgICAgIGFubnVhbDogZW52Q2VudHMocHJvY2Vzcy5lbnYuQklMTElOR19QTEFOX0VOVEVSUFJJU0VfQU5OVUFMLCA1OTkwMDApLFxuICAgICAgfSxcbiAgICAgIGZlYXR1cmVzOiBwYXJzZUZlYXR1cmVzKFxuICAgICAgICBwcm9jZXNzLmVudi5CSUxMSU5HX1BMQU5fRU5URVJQUklTRV9GRUFUVVJFUyxcbiAgICAgICAgREVGQVVMVF9FTlRFUlBSSVNFX0ZFQVRVUkVTLFxuICAgICAgKSxcbiAgICAgIGlzQWN0aXZlOiB0cnVlLFxuICAgICAgaXNEZWZhdWx0OiBmYWxzZSxcbiAgICAgIHNvcnRPcmRlcjogMyxcbiAgICB9LFxuICAgIC8vIFRoZSBiaWxsaW5nLURJU0FCTEVEIGRlZmF1bHQgcGxhbjogZXZlcnl0aGluZyB1bmNhcHBlZCwgYWxsIGZlYXR1cmVzLCBmcmVlLlxuICAgIC8vIFNlZWRlZCBzbyB0aGUgdGllcuKGknBsYW4gbWFwcGluZyByZXNvbHZlcywgYnV0IG5ldmVyIG9mZmVyZWQgZm9yIHNhbGUg4oCUIHRoZVxuICAgIC8vIHJlYWQtcGxhbnMgcm91dGUgZmlsdGVycyBpdCBvdXQgKHNlZSBjcmVhdGVSZWFkUGxhblJvdXRlcyksIHNvIGl0J3MgaGlkZGVuXG4gICAgLy8gd2hlbmV2ZXIgYmlsbGluZyBpcyBlbmFibGVkICh0aGUgb25seSB0aW1lIC9wbGFucyBpcyBzZXJ2ZWQpLlxuICAgIHVubGltaXRlZDoge1xuICAgICAgaWQ6ICd1bmxpbWl0ZWQnLFxuICAgICAgbmFtZTogcHJvY2Vzcy5lbnYuQklMTElOR19QTEFOX1VOTElNSVRFRF9OQU1FIHx8ICdVbmxpbWl0ZWQnLFxuICAgICAgZGVzY3JpcHRpb246IHByb2Nlc3MuZW52LkJJTExJTkdfUExBTl9VTkxJTUlURURfREVTQ1JJUFRJT05cbiAgICAgICAgfHwgJ0V2ZXJ5dGhpbmcgdW5jYXBwZWQg4oCUIHRoZSBkZWZhdWx0IHdoZW4gYmlsbGluZyBpcyBkaXNhYmxlZCcsXG4gICAgICB0aWVyOiAndW5saW1pdGVkJyxcbiAgICAgIHByaWNlczoge1xuICAgICAgICBtb250aGx5OiBlbnZDZW50cyhwcm9jZXNzLmVudi5CSUxMSU5HX1BMQU5fVU5MSU1JVEVEX01PTlRITFksIDApLFxuICAgICAgICBhbm51YWw6IGVudkNlbnRzKHByb2Nlc3MuZW52LkJJTExJTkdfUExBTl9VTkxJTUlURURfQU5OVUFMLCAwKSxcbiAgICAgIH0sXG4gICAgICBmZWF0dXJlczogcGFyc2VGZWF0dXJlcyhcbiAgICAgICAgcHJvY2Vzcy5lbnYuQklMTElOR19QTEFOX1VOTElNSVRFRF9GRUFUVVJFUyxcbiAgICAgICAgREVGQVVMVF9VTkxJTUlURURfRkVBVFVSRVMsXG4gICAgICApLFxuICAgICAgaXNBY3RpdmU6IHRydWUsXG4gICAgICBpc0RlZmF1bHQ6IGZhbHNlLFxuICAgICAgc29ydE9yZGVyOiA0LFxuICAgIH0sXG4gIH07XG5cbiAgLy8gRGVyaXZlIHRoZSBhcnJheSBjb25zdW1lcnMgcmVhZCAoYGNvbmZpZy5wbGFuc2ApIGluIGNhbm9uaWNhbCB0aWVyIG9yZGVyLlxuICBjb25zdCBwbGFuczogQmlsbGluZ1BsYW5Db25maWdbXSA9IFZBTElEX1RJRVJTLm1hcCgodGllcikgPT4gcGxhbkJ5VGllclt0aWVyXSk7XG5cbiAgLy8gQnVpbGQgYnVuZGxlcyBPTkNFIGFuZCB0aHJlYWQgdGhlbSBpbnRvIHRoZSBjb21ibyBsb2FkZXIgKHdoaWNoIG5lZWRzIHRoZWlyXG4gIC8vIGVudi1lZmZlY3RpdmUgcHJpY2VzKSDigJQgYXZvaWRzIHBhcnNpbmcgdGhlIHdob2xlIGJ1bmRsZSBjYXRhbG9nIHR3aWNlIHBlciBsb2FkLlxuICBjb25zdCBidW5kbGVzID0gbG9hZEJ1bmRsZXMoKTtcbiAgcmV0dXJuIHsgcGxhbnMsIGJ1bmRsZXMsIGNvbWJvRGlzY291bnRzOiBsb2FkQ29tYm9EaXNjb3VudHMoYnVuZGxlcykgfTtcbn1cblxuLyoqXG4gKiBDb21ibyBkaXNjb3VudHMgKGRvY3MvYmlsbGluZy1idW5kbGVzLm1kIMKnQ29tYm8gcHJpY2luZykuIFdoZW4gYW4gYWNjb3VudCBvd25zXG4gKiBldmVyeSBtZW1iZXIgYnVuZGxlIChlYWNoIGF0IOKJpSBpdHMgbWluaW11bSBxdWFudGl0eSksIHRoZSBzZXQgaXMgYmlsbGVkIGF0IHRoZVxuICogY29tYmluZWQgcHJpY2UgaW5zdGVhZCBvZiB0aGUgc3VtIG9mIHRoZSBtZW1iZXJzIOKAlCByZWFsaXplZCBhcyBhIHJlY3VycmluZyB1c2FnZVxuICogY3JlZGl0IGZvciB0aGUgZGlmZmVyZW5jZS4gT3ZlcmxhcHBpbmcgY29tYm9zIGFyZSByZXNvbHZlZCBieSBtYXgtd2VpZ2h0IHBhY2tpbmdcbiAqIChhIHNoYXJlZCBhZGQtb24gaXMgbmV2ZXIgZGlzY291bnRlZCB0d2ljZSk7IGBzb3J0T3JkZXJgIGJyZWFrcyBlcXVhbC10b3RhbCB0aWVzLlxuICpcbiAqIERlZmF1bHRzOlxuICogIC0gXCJBbmFseXRpY3MgU3VpdGVcIiDigJQgQWR2YW5jZWQgUmVwb3J0aW5nIChET1JBKSArIFRlYW0gVXNhZ2UgQW5hbHl0aWNzLCBlYWNoXG4gKiAgICAkMzAvbW8sIHRvZ2V0aGVyICQ0Mi9tbyAoJDQyMC95cikg4oaSIGEgJDE4L21vIGNyZWRpdCAofjMwJSBvZmYpLlxuICogIC0gXCJUZWFtIEdyb3d0aCBCdW5kbGVcIiDigJQg4omlNSBTZWF0cyAoJDE5Ljk5IGVhKSArIFRlYW0gVXNhZ2UgQW5hbHl0aWNzICgkMzApLFxuICogICAgYmFza2V0ICQxMjkuOTUvbW8g4oaSIHRvZ2V0aGVyICQ5MC45OS9tbyAoJDkwOS45MC95cikg4oaSIGEgfiQzOC45Ni9tbyBjcmVkaXQgKH4zMCUgb2ZmKS5cbiAqICAtIFwiU2NhbGUgQnVuZGxlXCIg4oCUIEFQSSBQYWNrICgkMTkuOTkpICsgU3RvcmFnZSBQYWNrICgkMTkuOTkpLCBiYXNrZXQgJDM5Ljk4L21vXG4gKiAgICDihpIgdG9nZXRoZXIgJDI3Ljk5L21vICgkMjc5LjkwL3lyKSDihpIgYSB+JDExLjk5L21vIGNyZWRpdCAofjMwJSBvZmYpLlxuICogUHJpY2VzIGVudi1vdmVycmlkYWJsZSB2aWEgYEJJTExJTkdfQ09NQk9fPElEPl9NT05USExZYCAvIGBfQU5OVUFMYC5cbiAqL1xuZnVuY3Rpb24gbG9hZENvbWJvRGlzY291bnRzKGJ1bmRsZXM6IEJ1bmRsZUNvbmZpZ1tdKTogQ29tYm9EaXNjb3VudENvbmZpZ1tdIHtcbiAgY29uc3QgYyA9IChcbiAgICBpZDogc3RyaW5nLFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICBidW5kbGVJZHM6IHN0cmluZ1tdLFxuICAgIG1vbnRobHk6IG51bWJlcixcbiAgICBhbm51YWw6IG51bWJlcixcbiAgICBzb3J0T3JkZXI6IG51bWJlcixcbiAgICBtaW5RdWFudGl0aWVzPzogUmVjb3JkPHN0cmluZywgbnVtYmVyPixcbiAgKTogQ29tYm9EaXNjb3VudENvbmZpZyA9PiAoe1xuICAgIGlkLFxuICAgIG5hbWUsXG4gICAgYnVuZGxlSWRzLFxuICAgIC4uLihtaW5RdWFudGl0aWVzID8geyBtaW5RdWFudGl0aWVzIH0gOiB7fSksXG4gICAgcHJpY2VzOiB7XG4gICAgICBtb250aGx5OiBlbnZDZW50cyhwcm9jZXNzLmVudltgQklMTElOR19DT01CT18ke2lkLnRvVXBwZXJDYXNlKCl9X01PTlRITFlgXSwgbW9udGhseSksXG4gICAgICBhbm51YWw6IGVudkNlbnRzKHByb2Nlc3MuZW52W2BCSUxMSU5HX0NPTUJPXyR7aWQudG9VcHBlckNhc2UoKX1fQU5OVUFMYF0sIGFubnVhbCksXG4gICAgfSxcbiAgICBzb3J0T3JkZXIsXG4gICAgaXNBY3RpdmU6IHRydWUsXG4gIH0pO1xuXG4gIGNvbnN0IGNvbWJvcyA9IFtcbiAgICBjKCdhbmFseXRpY3Nfc3VpdGUnLCAnQW5hbHl0aWNzIFN1aXRlJywgWydhZHZhbmNlZF9yZXBvcnRpbmcnLCAndGVhbV91c2FnZV9hbmFseXRpY3MnXSwgNDIwMCwgNDIwMDAsIDApLFxuICAgIC8vIFRlYW0gR3Jvd3RoIOKAlCDiiaU1IFNlYXRzICgkMTkuOTkgZWEpICsgVGVhbSBVc2FnZSBBbmFseXRpY3MgKCQzMCkuIEJhc2tldFxuICAgIC8vIDXDlyQxOS45OSArICQzMCA9ICQxMjkuOTUvbW8g4oaSIGJ1bmRsZWQgJDkwLjk5L21vICh+MzAlIG9mZiwgfiQzOC45NiBjcmVkaXQpLlxuICAgIGMoJ3RlYW1fZ3Jvd3RoJywgJ1RlYW0gR3Jvd3RoIEJ1bmRsZScsIFsnc2VhdCcsICd0ZWFtX3VzYWdlX2FuYWx5dGljcyddLCA5MDk5LCA5MDk5MCwgMSwgeyBzZWF0OiA1IH0pLFxuICAgIC8vIENvbXBsaWFuY2UgU3VpdGUg4oCUIFN0YW5kYXJkICsgQWR2YW5jZWQgYXQgMzAlIG9mZiAoJDkwOC42MC95ciB2cyAkMSwyOTggbGlzdCkuXG4gICAgYygnY29tcGxpYW5jZV9zdWl0ZScsICdDb21wbGlhbmNlIFN1aXRlJywgWydjb21wbGlhbmNlX3N0YW5kYXJkJywgJ2NvbXBsaWFuY2VfYWR2YW5jZWQnXSwgOTA4NiwgOTA4NjAsIDIpLFxuICAgIC8vIFNjYWxlIEJ1bmRsZSDigJQgQVBJIFBhY2sgKCQxOS45OSkgKyBTdG9yYWdlIFBhY2sgKCQxOS45OSkuIEJhc2tldCAkMzkuOTgvbW8g4oaSXG4gICAgLy8gYnVuZGxlZCAkMjcuOTkvbW8gKH4zMCUgb2ZmLCB+JDExLjk5IGNyZWRpdCkuIEJvdGggbWVtYmVycyBhbGwtdGllci5cbiAgICBjKCdzY2FsZV9idW5kbGUnLCAnU2NhbGUgQnVuZGxlJywgWydhcGlfcGFjaycsICdzdG9yYWdlX3BhY2snXSwgMjc5OSwgMjc5OTAsIDMpLFxuICBdO1xuICBhc3NlcnRDb21ib3NWYWxpZChjb21ib3MsIGJ1bmRsZXMpO1xuICB3YXJuT25Ob25EaXNjb3VudENvbWJvcyhjb21ib3MsIGJ1bmRsZXMpO1xuICByZXR1cm4gY29tYm9zO1xufVxuXG4vKipcbiAqIENvbmZpZy1sb2FkIGd1YXJkcmFpbCBmb3IgY29tYm9zOiBldmVyeSBgYnVuZGxlSWRgIG11c3QgcmVzb2x2ZSB0byBhbiBBQ1RJVkVcbiAqIGJ1bmRsZSBhbmQgZXZlcnkgYG1pblF1YW50aXRpZXNgIGtleSBtdXN0IGJlIG9uZSBvZiB0aGUgY29tYm8ncyBgYnVuZGxlSWRzYC5cbiAqIEEgdHlwbydkIG1lbWJlciBvciBzdHJheSBtaW5RdWFudGl0eSBrZXkgb3RoZXJ3aXNlIHNoaXBzIGEgcGVybWFuZW50bHktaW5lcnRcbiAqIGNvbWJvIChtaXNzaW5nIGJ1bmRsZSB0cmVhdGVkIGFzIHVuaXQgcHJpY2UgMCwgb3IgYSBtaW4gbmV2ZXIgc2F0aXNmaWFibGUpLFxuICogc2lsZW50bHkgbmV2ZXIgYXBwbHlpbmcuIFRocm93cyBzbyBtaXNjb25maWcgZmFpbHMgZmFzdCBhdCBib290LlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0Q29tYm9zVmFsaWQoY29tYm9zOiBDb21ib0Rpc2NvdW50Q29uZmlnW10sIGJ1bmRsZXM6IEJ1bmRsZUNvbmZpZ1tdKTogdm9pZCB7XG4gIGNvbnN0IGFjdGl2ZUlkcyA9IG5ldyBTZXQoYnVuZGxlcy5maWx0ZXIoKGIpID0+IGIuaXNBY3RpdmUpLm1hcCgoYikgPT4gYi5pZCkpO1xuICBmb3IgKGNvbnN0IGNvbWJvIG9mIGNvbWJvcykge1xuICAgIGZvciAoY29uc3QgaWQgb2YgY29tYm8uYnVuZGxlSWRzKSB7XG4gICAgICBpZiAoIWFjdGl2ZUlkcy5oYXMoaWQpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ29tYm8gXCIke2NvbWJvLmlkfVwiIHJlZmVyZW5jZXMgYnVuZGxlIFwiJHtpZH1cIiwgd2hpY2ggaXMgbm90IGFuIGFjdGl2ZSBidW5kbGUuYCk7XG4gICAgICB9XG4gICAgfVxuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKGNvbWJvLm1pblF1YW50aXRpZXMgPz8ge30pKSB7XG4gICAgICBpZiAoIWNvbWJvLmJ1bmRsZUlkcy5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ29tYm8gXCIke2NvbWJvLmlkfVwiIG1pblF1YW50aXRpZXMga2V5IFwiJHtrZXl9XCIgaXMgbm90IG9uZSBvZiBpdHMgYnVuZGxlSWRzLmApO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG4vKiogVGhlIHZvbHVtZS1kaXNjb3VudCBwZXJjZW50IGFwcGx5aW5nIHRvIGBxdWFudGl0eWAgdW5pdHMgb2YgYSBidW5kbGUg4oCUIHRoZVxuICogIGhpZ2hlc3QgYHZvbHVtZVRpZXJzYCBlbnRyeSB3aG9zZSBgbWluUXVhbnRpdHkg4omkIHF1YW50aXR5YCwgZWxzZSAwLiBNaXJyb3JzXG4gKiAgYHZvbHVtZURpc2NvdW50UGN0YCBpbiBhcGkvYmlsbGluZydzIGNvbWJvLXByaWNpbmcgKHdoaWNoIGNhbid0IGJlIGltcG9ydGVkIHRoZVxuICogIG90aGVyIHdheSk7IHRoZSBjb21ibyBjcmVkaXQgbWF0aCBhbmQgdGhpcyBndWFyZHJhaWwgTVVTVCB1c2UgdGhlIHNhbWUgYmFzaXMuICovXG5mdW5jdGlvbiB2b2x1bWVEaXNjb3VudFBjdEF0KGJ1bmRsZTogQnVuZGxlQ29uZmlnIHwgdW5kZWZpbmVkLCBxdWFudGl0eTogbnVtYmVyKTogbnVtYmVyIHtcbiAgbGV0IHBjdCA9IDA7XG4gIGZvciAoY29uc3QgdCBvZiBidW5kbGU/LnZvbHVtZVRpZXJzID8/IFtdKSBpZiAocXVhbnRpdHkgPj0gdC5taW5RdWFudGl0eSkgcGN0ID0gdC5kaXNjb3VudFBlcmNlbnQ7XG4gIHJldHVybiBwY3Q7XG59XG5cbi8qKlxuICogR3VhcmRyYWlsOiBhIGNvbWJvIHdob3NlIGNvbWJpbmVkIHByaWNlIGlzIOKJpSBpdHMgbWluaW11bS1jb21wb3NpdGlvbiBiYXNrZXQgZ3JhbnRzXG4gKiBubyBjcmVkaXQgKHRoZSBjcmVkaXQgY2xhbXBzIHRvICQwKSBhbmQgaXMgc2lsZW50bHkgaW5lcnQuIFdhcm4gbG91ZGx5IGluc3RlYWQgc28gYVxuICogbWlzY29uZmlndXJlZCBgQklMTElOR19DT01CT18qYCBvdmVycmlkZSBpcyBjYXVnaHQuIE5vbi1mYXRhbC5cbiAqL1xuZnVuY3Rpb24gd2Fybk9uTm9uRGlzY291bnRDb21ib3MoY29tYm9zOiBDb21ib0Rpc2NvdW50Q29uZmlnW10sIGJ1bmRsZXM6IEJ1bmRsZUNvbmZpZ1tdKTogdm9pZCB7XG4gIC8vIENvbWJvIG1lbWJlcnMgYXJlIGFsd2F5cyBidW5kbGVzOyByZXNvbHZlIHRoZWlyIChlbnYtZWZmZWN0aXZlKSB1bml0IHByaWNlcyBvbmNlLlxuICBjb25zdCBieUlkID0gbmV3IE1hcChidW5kbGVzLm1hcCgoYikgPT4gW2IuaWQsIGJdKSk7XG4gIGZvciAoY29uc3QgY29tYm8gb2YgY29tYm9zKSB7XG4gICAgZm9yIChjb25zdCBpbnRlcnZhbCBvZiBbJ21vbnRobHknLCAnYW5udWFsJ10gYXMgY29uc3QpIHtcbiAgICAgIC8vIFBvc3Qtdm9sdW1lIGJhc2lzIChtaXJyb3JzIGBjb21ib0Jhc2lzQ2VudHNgKTogYSBtZW1iZXIgd2l0aCB2b2x1bWUgdGllcnMgaXNcbiAgICAgIC8vIGJhc2lzZWQgb24gaXRzIERJU0NPVU5URUQgdW5pdCBhdCB0aGUgY29tYm8ncyBtaW5RdHksIHNvIHRoaXMgZ3VhcmRyYWlsIGNhbid0XG4gICAgICAvLyBzaWxlbnRseSBtaXNzIGEgY29tYm8gdGhhdCBncmFudHMgbm8gcmVhbCBjcmVkaXQgb25jZSB2b2x1bWUgaXMgYXBwbGllZC5cbiAgICAgIGNvbnN0IGJhc2tldCA9IGNvbWJvLmJ1bmRsZUlkcy5yZWR1Y2UoKHMsIGlkKSA9PiB7XG4gICAgICAgIGNvbnN0IGIgPSBieUlkLmdldChpZCk7XG4gICAgICAgIGNvbnN0IHF0eSA9IGNvbWJvLm1pblF1YW50aXRpZXM/LltpZF0gPz8gMTtcbiAgICAgICAgY29uc3QgcmF3VW5pdCA9IGI/LnByaWNlc1tpbnRlcnZhbF0gPz8gMDtcbiAgICAgICAgY29uc3QgdW5pdCA9IE1hdGgucm91bmQoKHJhd1VuaXQgKiAoMTAwIC0gdm9sdW1lRGlzY291bnRQY3RBdChiLCBxdHkpKSkgLyAxMDApO1xuICAgICAgICByZXR1cm4gcyArIHVuaXQgKiBxdHk7XG4gICAgICB9LCAwKTtcbiAgICAgIGlmIChjb21iby5wcmljZXNbaW50ZXJ2YWxdID49IGJhc2tldCkge1xuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZVxuICAgICAgICBjb25zb2xlLndhcm4oYFtiaWxsaW5nLWNvbmZpZ10gQ29tYm8gXCIke2NvbWJvLmlkfVwiICR7aW50ZXJ2YWx9IHByaWNlICR7Y29tYm8ucHJpY2VzW2ludGVydmFsXX0g4omlIG1lbWJlciBiYXNrZXQgJHtiYXNrZXR9OyBpdCBncmFudHMgbm8gZGlzY291bnQuYCk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbmNvbnN0IEJVTkRMRV9HQiA9IDEwMjQgKiAxMDI0ICogMTAyNDtcblxuLyoqXG4gKiBBcHBseSBhIHBlci1idW5kbGUgZ3JhbnQgb3ZlcnJpZGUuIEVhY2ggc3RhY2thYmxlIHBhY2sgZ3JhbnRzIGV4YWN0bHkgb25lXG4gKiBxdW90YSBkaW1lbnNpb24sIHNvIGBCSUxMSU5HX0JVTkRMRV88SUQ+X0dSQU5UYCByZXR1bmVzIHRoYXQgYW1vdW50IChlLmcuIG1ha2VcbiAqIHRoZSBQbHVnaW4gUGFjayBncmFudCArNTAgaW5zdGVhZCBvZiArMjUpIOKAlCBwYXJhbGxlbCB0byB0aGUgcHJpY2Ugb3ZlcnJpZGVzLlxuICogSWdub3JlZCBmb3IgbXVsdGktZGltZW5zaW9uIG9yIGZlYXR1cmUtb25seSAoZW1wdHktZ3JhbnQpIGJ1bmRsZXMsIGFuZCBmb3IgYVxuICogbWFsZm9ybWVkL25lZ2F0aXZlIHZhbHVlLlxuICovXG5mdW5jdGlvbiBhcHBseUdyYW50T3ZlcnJpZGUoaWQ6IHN0cmluZywgZ3JhbnRzOiBHcmFudE1hcCk6IEdyYW50TWFwIHtcbiAgY29uc3QgcmF3ID0gcHJvY2Vzcy5lbnZbYEJJTExJTkdfQlVORExFXyR7aWQudG9VcHBlckNhc2UoKX1fR1JBTlRgXTtcbiAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKGdyYW50cyk7XG4gIGlmIChyYXcgPT09IHVuZGVmaW5lZCB8fCByYXcgPT09ICcnIHx8IGtleXMubGVuZ3RoICE9PSAxKSByZXR1cm4gZ3JhbnRzO1xuICBjb25zdCBuID0gcGFyc2VJbnQocmF3LCAxMCk7XG4gIGlmIChOdW1iZXIuaXNOYU4obikgfHwgbiA8IDApIHJldHVybiBncmFudHM7XG4gIC8vIGBrZXlzYCBjYW1lIGZyb20gYSBHcmFudE1hcCwgc28gaXRzIHNvbGUga2V5IGlzIGEgUXVvdGFUaWVyTGltaXRzIGZpZWxkLlxuICByZXR1cm4geyBba2V5c1swXSBhcyBrZXlvZiBRdW90YVRpZXJMaW1pdHNdOiBuIH07XG59XG5cbi8qKlxuICogQXBwbHkgYSBwZXItYnVuZGxlIHRpZXItYXZhaWxhYmlsaXR5IG92ZXJyaWRlLiBgQklMTElOR19CVU5ETEVfPElEPl9USUVSU2AgaXMgYVxuICogSlNPTiBhcnJheSBvZiB0aWVyIElEcyB0aGF0IG1heSBwdXJjaGFzZSB0aGUgYnVuZGxlIChlLmcuIGBbXCJkZXZlbG9wZXJcIixcInByb1wiXWApXG4gKiDigJQgcGFyYWxsZWwgdG8gdGhlIHByaWNlL2dyYW50IG92ZXJyaWRlcy4gRmFsbHMgYmFjayB0byBgZGVmYXVsdFRpZXJzYCB3aGVuXG4gKiB1bnNldCwgbWFsZm9ybWVkLCBlbXB0eSwgb3IgY29udGFpbmluZyBhbiB1bmtub3duIHRpZXIuXG4gKi9cbmZ1bmN0aW9uIGFwcGx5VGllcnNPdmVycmlkZShpZDogc3RyaW5nLCBkZWZhdWx0VGllcnM6IFF1b3RhVGllcltdKTogUXVvdGFUaWVyW10ge1xuICBjb25zdCByYXcgPSBwcm9jZXNzLmVudltgQklMTElOR19CVU5ETEVfJHtpZC50b1VwcGVyQ2FzZSgpfV9USUVSU2BdO1xuICBpZiAoIXJhdykgcmV0dXJuIGRlZmF1bHRUaWVycztcbiAgdHJ5IHtcbiAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKHJhdyk7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHBhcnNlZCkgfHwgcGFyc2VkLmxlbmd0aCA9PT0gMCkgcmV0dXJuIGRlZmF1bHRUaWVycztcbiAgICBjb25zdCB2YWxpZCA9IHBhcnNlZC5maWx0ZXIoKHQpOiB0IGlzIFF1b3RhVGllciA9PiB0eXBlb2YgdCA9PT0gJ3N0cmluZycgJiYgaXNWYWxpZFRpZXIodCkpO1xuICAgIHJldHVybiB2YWxpZC5sZW5ndGggPT09IHBhcnNlZC5sZW5ndGggPyB2YWxpZCA6IGRlZmF1bHRUaWVycztcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGRlZmF1bHRUaWVycztcbiAgfVxufVxuXG50eXBlIFZvbHVtZVRpZXIgPSB7IG1pblF1YW50aXR5OiBudW1iZXI7IGRpc2NvdW50UGVyY2VudDogbnVtYmVyIH07XG5cbi8qKlxuICogQXBwbHkgYSBwZXItYnVuZGxlIHZvbHVtZS10aWVyIG92ZXJyaWRlLiBgQklMTElOR19CVU5ETEVfPElEPl9WT0xVTUVfVElFUlNgIGlzIGFcbiAqIEpTT04gYXJyYXkgb2YgYHsgbWluUXVhbnRpdHksIGRpc2NvdW50UGVyY2VudCB9YCAoZS5nLlxuICogYFt7XCJtaW5RdWFudGl0eVwiOjUsXCJkaXNjb3VudFBlcmNlbnRcIjoxMH1dYCkg4oCUIHBhcmFsbGVsIHRvIHRoZSBwcmljZS9ncmFudC90aWVyXG4gKiBvdmVycmlkZXMuIEZhbGxzIGJhY2sgdG8gYGRlZmF1bHRUaWVyc2Agd2hlbiB1bnNldCwgbWFsZm9ybWVkLCBvciBjb250YWluaW5nIGFuXG4gKiBpbnZhbGlkIGVudHJ5IChtaW5RdWFudGl0eSDiiaUgMSwgMCA8IGRpc2NvdW50UGVyY2VudCDiiaQgMTAwKS4gU29ydGVkIGFzY2VuZGluZyBieVxuICogbWluUXVhbnRpdHkgc28gdGhlIFwiaGlnaGVzdCBtYXRjaGluZyB0aWVyIHdpbnNcIiBsb29rdXAgaXMgZGV0ZXJtaW5pc3RpYy5cbiAqL1xuZnVuY3Rpb24gYXBwbHlWb2x1bWVUaWVyc092ZXJyaWRlKGlkOiBzdHJpbmcsIGRlZmF1bHRUaWVycz86IFZvbHVtZVRpZXJbXSk6IFZvbHVtZVRpZXJbXSB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHJhdyA9IHByb2Nlc3MuZW52W2BCSUxMSU5HX0JVTkRMRV8ke2lkLnRvVXBwZXJDYXNlKCl9X1ZPTFVNRV9USUVSU2BdO1xuICBjb25zdCBzb3J0QXNjID0gKHQ6IFZvbHVtZVRpZXJbXSkgPT4gWy4uLnRdLnNvcnQoKGEsIGIpID0+IGEubWluUXVhbnRpdHkgLSBiLm1pblF1YW50aXR5KTtcbiAgY29uc3QgZmFsbGJhY2sgPSAoKSA9PiAoZGVmYXVsdFRpZXJzID8gc29ydEFzYyhkZWZhdWx0VGllcnMpIDogdW5kZWZpbmVkKTtcbiAgaWYgKCFyYXcpIHJldHVybiBmYWxsYmFjaygpO1xuICB0cnkge1xuICAgIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UocmF3KTtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkocGFyc2VkKSB8fCBwYXJzZWQubGVuZ3RoID09PSAwKSByZXR1cm4gZmFsbGJhY2soKTtcbiAgICAvLyBFYWNoIGVudHJ5OiBpbnRlZ2VyIG1pblF1YW50aXR5IOKJpSAxLCAwIDwgZGlzY291bnRQZXJjZW50IOKJpCAxMDAuXG4gICAgY29uc3QgdmFsaWQgPSBwYXJzZWQuZmlsdGVyKCh0KTogdCBpcyBWb2x1bWVUaWVyID0+XG4gICAgICB0ICYmIHR5cGVvZiB0Lm1pblF1YW50aXR5ID09PSAnbnVtYmVyJyAmJiBOdW1iZXIuaXNJbnRlZ2VyKHQubWluUXVhbnRpdHkpICYmIHQubWluUXVhbnRpdHkgPj0gMVxuICAgICAgJiYgdHlwZW9mIHQuZGlzY291bnRQZXJjZW50ID09PSAnbnVtYmVyJyAmJiB0LmRpc2NvdW50UGVyY2VudCA+IDAgJiYgdC5kaXNjb3VudFBlcmNlbnQgPD0gMTAwKTtcbiAgICBpZiAodmFsaWQubGVuZ3RoICE9PSBwYXJzZWQubGVuZ3RoKSByZXR1cm4gZmFsbGJhY2soKTtcbiAgICBjb25zdCBzb3J0ZWQgPSBzb3J0QXNjKHZhbGlkKTtcbiAgICAvLyBSZWplY3QgYSBub24tbW9ub3RvbmljIGN1cnZlOiBidXlpbmcgTU9SRSBtdXN0IG5ldmVyIGVhcm4gYSBTTUFMTEVSIGRpc2NvdW50LFxuICAgIC8vIGFuZCBkdXBsaWNhdGUgdGhyZXNob2xkcyBhcmUgYW1iaWd1b3VzLiAoYHZvbHVtZURpc2NvdW50UGN0YCBwaWNrcyB0aGUgbGFzdFxuICAgIC8vIHF1YWxpZnlpbmcgdGllciwgc28gYSBkZXNjZW5kaW5nIHBlcmNlbnQgd291bGQgcGVuYWxpemUgaGlnaGVyIHF1YW50aXRpZXMuKVxuICAgIGZvciAobGV0IGkgPSAxOyBpIDwgc29ydGVkLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoc29ydGVkW2ldLm1pblF1YW50aXR5ID09PSBzb3J0ZWRbaSAtIDFdLm1pblF1YW50aXR5KSByZXR1cm4gZmFsbGJhY2soKTtcbiAgICAgIGlmIChzb3J0ZWRbaV0uZGlzY291bnRQZXJjZW50IDw9IHNvcnRlZFtpIC0gMV0uZGlzY291bnRQZXJjZW50KSByZXR1cm4gZmFsbGJhY2soKTtcbiAgICB9XG4gICAgcmV0dXJuIHNvcnRlZDtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbGxiYWNrKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBQdXJjaGFzYWJsZSBhZGQtb24gYnVuZGxlcyAoZG9jcy9iaWxsaW5nLWJ1bmRsZXMubWQgwqczKS4gR3JhbnRzIGFyZSBwZXItdW5pdFxuICogZGVsdGFzIG9uIFF1b3RhVGllckxpbWl0czsgcHJpY2VzIChjZW50cywgYEJJTExJTkdfQlVORExFXzxJRD5fTU9OVEhMWWAgL1xuICogYF9BTk5VQUxgKSwgdGhlIHNpbmdsZS1kaW1lbnNpb24gZ3JhbnQgYW1vdW50IChgQklMTElOR19CVU5ETEVfPElEPl9HUkFOVGApLFxuICogYW5kIHRoZSBwdXJjaGFzYWJsZS10aWVyIGxpc3QgKGBCSUxMSU5HX0JVTkRMRV88SUQ+X1RJRVJTYCkgYXJlIGFsbFxuICogZW52LW92ZXJyaWRhYmxlLiBBbm51YWwg4omIIDEww5cgbW9udGhseS5cbiAqL1xuZnVuY3Rpb24gbG9hZEJ1bmRsZXMoKTogQnVuZGxlQ29uZmlnW10ge1xuICBjb25zdCBiID0gKFxuICAgIGlkOiBzdHJpbmcsXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIGRlc2NyaXB0aW9uOiBzdHJpbmcsXG4gICAgZ3JhbnRzOiBHcmFudE1hcCxcbiAgICBtb250aGx5OiBudW1iZXIsXG4gICAgYXZhaWxhYmxlRm9yVGllcnM6IFF1b3RhVGllcltdLFxuICAgIHNvcnRPcmRlcjogbnVtYmVyLFxuICAgIGV4dHJhOiB7IGZlYXR1cmVzPzogc3RyaW5nW107IHN0YWNrYWJsZT86IGJvb2xlYW47IG1heFF1YW50aXR5PzogbnVtYmVyOyByZXF1aXJlcz86IHN0cmluZ1tdOyByZXF1aXJlc0ZlYXR1cmVzPzogc3RyaW5nW107IHZvbHVtZVRpZXJzPzogVm9sdW1lVGllcltdIH0gPSB7fSxcbiAgKTogQnVuZGxlQ29uZmlnID0+IHtcbiAgICAvLyBSZXNvbHZlIG1vbnRobHkgZmlyc3Qgc28gdGhlIGFubnVhbCBmYWxsYmFjayB0cmFja3MgYSBgX01PTlRITFlgIG92ZXJyaWRlXG4gICAgLy8gKGFubnVhbCDiiYggMTDDlyB0aGUgKmVmZmVjdGl2ZSogbW9udGhseSwgbm90IHRoZSBoYXJkY29kZWQgZGVmYXVsdCkuXG4gICAgY29uc3QgcmVzb2x2ZWRNb250aGx5ID0gZW52Q2VudHMocHJvY2Vzcy5lbnZbYEJJTExJTkdfQlVORExFXyR7aWQudG9VcHBlckNhc2UoKX1fTU9OVEhMWWBdLCBtb250aGx5KTtcbiAgICBjb25zdCB2b2x1bWVUaWVycyA9IGFwcGx5Vm9sdW1lVGllcnNPdmVycmlkZShpZCwgZXh0cmEudm9sdW1lVGllcnMpO1xuICAgIHJldHVybiB7XG4gICAgICBpZCxcbiAgICAgIG5hbWUsXG4gICAgICBkZXNjcmlwdGlvbixcbiAgICAgIGdyYW50czogYXBwbHlHcmFudE92ZXJyaWRlKGlkLCBncmFudHMpLFxuICAgICAgLi4uKGV4dHJhLmZlYXR1cmVzID8geyBmZWF0dXJlczogZXh0cmEuZmVhdHVyZXMgfSA6IHt9KSxcbiAgICAgIC4uLihleHRyYS5tYXhRdWFudGl0eSAhPT0gdW5kZWZpbmVkID8geyBtYXhRdWFudGl0eTogZXh0cmEubWF4UXVhbnRpdHkgfSA6IHt9KSxcbiAgICAgIC4uLihleHRyYS5yZXF1aXJlcyA/IHsgcmVxdWlyZXM6IGV4dHJhLnJlcXVpcmVzIH0gOiB7fSksXG4gICAgICAuLi4oZXh0cmEucmVxdWlyZXNGZWF0dXJlcyA/IHsgcmVxdWlyZXNGZWF0dXJlczogZXh0cmEucmVxdWlyZXNGZWF0dXJlcyB9IDoge30pLFxuICAgICAgLi4uKHZvbHVtZVRpZXJzID8geyB2b2x1bWVUaWVycyB9IDoge30pLFxuICAgICAgcHJpY2VzOiB7XG4gICAgICAgIG1vbnRobHk6IHJlc29sdmVkTW9udGhseSxcbiAgICAgICAgYW5udWFsOiBlbnZDZW50cyhwcm9jZXNzLmVudltgQklMTElOR19CVU5ETEVfJHtpZC50b1VwcGVyQ2FzZSgpfV9BTk5VQUxgXSwgcmVzb2x2ZWRNb250aGx5ICogMTApLFxuICAgICAgfSxcbiAgICAgIHN0YWNrYWJsZTogZXh0cmEuc3RhY2thYmxlID8/IHRydWUsXG4gICAgICBhdmFpbGFibGVGb3JUaWVyczogYXBwbHlUaWVyc092ZXJyaWRlKGlkLCBhdmFpbGFibGVGb3JUaWVycyksXG4gICAgICBpc0FjdGl2ZTogdHJ1ZSxcbiAgICAgIHNvcnRPcmRlcixcbiAgICB9O1xuICB9O1xuXG4gIC8vIEJ1bmRsZXMgYXJlIHB1cmNoYXNhYmxlIG9uIGV2ZXJ5IFNFTEVDVEFCTEUgdGllciAoZXhjbHVkZXMgYHVubGltaXRlZGAsIHdoaWNoXG4gIC8vIGlzIHRoZSBiaWxsaW5nLW9mZiB0aWVyIGFuZCBidXlzIG5vdGhpbmcpIOKAlCBzbyB0aGlzIGlzIGV4YWN0bHkgU1RBTkRBUkRfVElFUlMuXG4gIGNvbnN0IEFMTDogUXVvdGFUaWVyW10gPSBbLi4uU1RBTkRBUkRfVElFUlNdO1xuICBjb25zdCBidW5kbGVzOiBCdW5kbGVDb25maWdbXSA9IFtcbiAgICAvLyBgc2VhdGAgYW5kIGBwaXBlbGluZV9wYWNrYCBhcmUgdGhlIHRpZXIgZGlmZmVyZW50aWF0b3JzLCBzbyBib3RoIGFyZSBUZWFtK1xuICAgIC8vIE9OTFkg4oCUIGEgc2luZ2xlLXNlYXQgRGV2ZWxvcGVyL1BybyBjYW4ndCBjaGVhcGx5IHN0YWNrIHNlYXRzL3BpcGVsaW5lcyB0b1xuICAgIC8vIHVuZGVyY3V0IFRlYW0gKDMgc2VhdHMgLyA2IHBpcGVsaW5lcyk7IHRoZXkgbXVzdCB1cGdyYWRlLiBgc2VhdGAgaXMgZ3JhbnVsYXJcbiAgICAvLyAocGVyLXNlYXQpIHdpdGggdm9sdW1lIHRpZXJzICg1LzE1LzQwIOKGkiAxMC8yMC8zMCUpLiBUaGUgb3RoZXIgY2FwYWNpdHkgcGFja3NcbiAgICAvLyAocGx1Z2luL2FwaS9haS9zdG9yYWdlKSBhcmUgTk9UIGRpZmZlcmVudGlhdG9ycywgc28gdGhleSBzdGF5IGFsbC10aWVyLlxuICAgIGIoJ3NlYXQnLCAnTWVtYmVyIFNlYXQnLCAnMSBhZGRpdGlvbmFsIG1lbWJlciBzZWF0JywgeyBzZWF0czogMSB9LCAxOTk5LCBbJ3RlYW0nLCAnZW50ZXJwcmlzZSddLCAwLFxuICAgICAgeyB2b2x1bWVUaWVyczogW3sgbWluUXVhbnRpdHk6IDUsIGRpc2NvdW50UGVyY2VudDogMTAgfSwgeyBtaW5RdWFudGl0eTogMTUsIGRpc2NvdW50UGVyY2VudDogMjAgfSwgeyBtaW5RdWFudGl0eTogNDAsIGRpc2NvdW50UGVyY2VudDogMzAgfV0gfSksXG4gICAgYigncGlwZWxpbmVfcGFjaycsICdQaXBlbGluZSBQYWNrICgrNSknLCAnNSBhZGRpdGlvbmFsIHBpcGVsaW5lcycsIHsgcGlwZWxpbmVzOiA1IH0sIDE1MDAsIFsndGVhbScsICdlbnRlcnByaXNlJ10sIDEpLFxuICAgIGIoJ3BsdWdpbl9wYWNrJywgJ1BsdWdpbiBQYWNrICgrMjUpJywgJzI1IGFkZGl0aW9uYWwgcGx1Z2lucycsIHsgcGx1Z2luczogMjUgfSwgMTAwMCwgQUxMLCAyKSxcbiAgICBiKCdhcGlfcGFjaycsICdBUEkgUGFjayAoKzEwMGspJywgJzEwMCwwMDAgYWRkaXRpb25hbCBBUEkgY2FsbHMgLyBwZXJpb2QnLCB7IGFwaUNhbGxzOiAxMDBfMDAwIH0sIDE5OTksIEFMTCwgMyksXG4gICAgYignYWlfcGFjaycsICdBSSBQYWNrICgrMi41ayknLCAnMiw1MDAgYWRkaXRpb25hbCBBSSBjYWxscyAvIHBlcmlvZCcsIHsgYWlDYWxsczogMjUwMCB9LCAxOTk5LCBBTEwsIDQpLFxuICAgIGIoJ3N0b3JhZ2VfcGFjaycsICdTdG9yYWdlIFBhY2sgKCsxMCBHQiknLCAnMTAgR0IgYWRkaXRpb25hbCByZWdpc3RyeSBzdG9yYWdlJywgeyBzdG9yYWdlQnl0ZXM6IDEwICogQlVORExFX0dCIH0sIDE5OTksIEFMTCwgNSksXG4gICAgLy8gTk9URTogYHNzb2AgaXMgTk9UIHNvbGQgYXMgYW4gYWRkLW9uLiBJdCBpcyBhIFRJRVIgZmVhdHVyZSBmcm9tIFRlYW0gdXBcbiAgICAvLyAoVElFUl9GRUFUVVJFUy50ZWFtKSBhbmQgbm90aGluZyBiZWxvdyBUZWFtIGNhbiBidXkgaXQuIFRoZSBidW5kbGUgdGhhdFxuICAgIC8vIHVzZWQgdG8gZXhpc3QgaGVyZSB3YXMgJDQwL21vIG9uIFBybyBvbmx5IOKAlCBQcm8gKCQzOSkgKyB0aGUgYWRkLW9uIGNhbWUgdG9cbiAgICAvLyBleGFjdGx5IFRlYW0gKCQ3OSksIHdoaWNoIGFscmVhZHkgaW5jbHVkZXMgU1NPICphbmQqIHRlYW1zICphbmQqIGRvbWFpblxuICAgIC8vIHJlZ2lzdHJhdGlvbiwgc28gaXQgd2FzIHN0cmljdGx5IGRvbWluYXRlZC4gSXQgd2FzIGFsc28gZnVuY3Rpb25hbGx5XG4gICAgLy8gYnJva2VuIGJlbG93IFRlYW06IFNTTyByZWZ1c2VzIGFuIGlkZW50aXR5IHdob3NlIGVtYWlsIGRvbWFpbiB0aGUgb3JnIGhhc1xuICAgIC8vIG5vdCBETlMtdmVyaWZpZWQgKGBhc3NlcnRTc29JZGVudGl0eVRydXN0ZWRgLCB3aGljaCBleGVtcHRzIG9ubHlcbiAgICAvLyBHb29nbGUtaXNzdWVkIGlkZW50aXRpZXMpLCBhbmQgcmVnaXN0ZXJpbmcgYSBkb21haW4gdG8gdmVyaWZ5IGlzIElUU0VMRiBhXG4gICAgLy8gaGFyZCBUZWFtL0VudGVycHJpc2UgdGllciBjaGVjayAocGxhdGZvcm0gYG9yZy1kb21haW4tc2VydmljZWApLiBTbyBhIFByb1xuICAgIC8vIGJ1eWVyJ3MgT2t0YSAvIEVudHJhIC8gZ2VuZXJpYy1PSURDIC8gU0FNTCBjb25uZWN0aW9uIGZhaWxlZCBhdCBjYWxsYmFja1xuICAgIC8vIHdpdGggT0lEQ19FTUFJTF9ET01BSU5fTk9UX1ZFUklGSUVELCB3aXRoIG5vIHdheSB0byBmaXggaXQgb24gUHJvLiBTZWxsaW5nXG4gICAgLy8gU1NPIGJlbG93IFRlYW0gd291bGQgbWVhbiBnaXZpbmcgYXdheSBkb21haW4gcmVnaXN0cmF0aW9uIHRvbywgYW5kIHRoYXQgaXNcbiAgICAvLyB0aGUgVGVhbSBkaWZmZXJlbnRpYXRvci5cblxuICAgIC8vIERPUkEgLyBhZHZhbmNlZCBkZWxpdmVyeSBhbmFseXRpY3MuIElOQ0xVREVEIGluIEVudGVycHJpc2UgKFRJRVJfRkVBVFVSRVMpLFxuICAgIC8vIHNvIHRoZSBhZGQtb24gaXMgb2ZmZXJlZCB0byBldmVyeSBvdGhlciB0aWVyIChkZXZlbG9wZXIvcHJvL3RlYW0pLiBQcmljZWRcbiAgICAvLyBhcyBhbiBhbmFseXRpY3Mgc3VyZmFjZSwgbm90IGFuIGVudGVycHJpc2UgaWRlbnRpdHkgZ2F0ZS5cbiAgICAvLyBMZWFkIHRpbWUgaXMgTUVBU1VSRUQgY29tbWl0IOKGkiBkZXBsb3kgKHJlcG9ydGluZydzIGRlcGxveSBldmVudHMpLCBub3QgYSBwcm94eS5cbiAgICBiKCdhZHZhbmNlZF9yZXBvcnRpbmcnLCAnQWR2YW5jZWQgUmVwb3J0aW5nIChET1JBKScsICdET1JBIGRlbGl2ZXJ5IG1ldHJpY3Mg4oCUIGRlcGxveW1lbnQgZnJlcXVlbmN5LCBsZWFkIHRpbWUgKGNvbW1pdCDihpIgZGVwbG95KSwgY2hhbmdlIGZhaWx1cmUgcmF0ZSwgTVRUUiwgcGVyZm9ybWFuY2UgYmFuZHMgKyB0cmVuZCcsIHt9LCAzMDAwLCBbJ2RldmVsb3BlcicsICdwcm8nLCAndGVhbSddLCA4LCB7IGZlYXR1cmVzOiBbJ2FkdmFuY2VkX3JlcG9ydGluZyddLCBzdGFja2FibGU6IGZhbHNlIH0pLFxuICAgIC8vIFBlci10ZWFtIHVzYWdlIGJyZWFrZG93biBhY3Jvc3MgdGhlIG9yZyDihpIgdGVhbSBzdWJ0cmVlLiBJTkNMVURFRCBpblxuICAgIC8vIEVudGVycHJpc2UgKFRJRVJfRkVBVFVSRVMpOyB0aGUgYWRkLW9uIGlzIG9mZmVyZWQgdG8gVGVhbSBvbmx5IOKAlCBEZXZlbG9wZXJcbiAgICAvLyBhbmQgUHJvIGNhbid0IG5lc3QgdGVhbXMgKFRFQU1fQ0FQQUJMRV9USUVSUyksIHNvIHRoZXJlJ2QgYmUgbm90aGluZyB0b1xuICAgIC8vIGJyZWFrIGRvd24uIFByaWNlZCBhdCAkMzAvbW8gKCQzMDAveXIpIOKAlCBwYXJpdHkgd2l0aCBET1JBLCBpdHMgYW5hbHl0aWNzXG4gICAgLy8gc2libGluZy4gT3ZlcnJpZGFibGUgdmlhIEJJTExJTkdfQlVORExFX1RFQU1fVVNBR0VfQU5BTFlUSUNTX01PTlRITFkvX0FOTlVBTC5cbiAgICBiKCd0ZWFtX3VzYWdlX2FuYWx5dGljcycsICdUZWFtIFVzYWdlIEFuYWx5dGljcycsICdQZXItdGVhbSB1c2FnZSBicmVha2Rvd24gYWNyb3NzIHRoZSBvcmcg4oaSIHRlYW0gc3VidHJlZSAoYWxsIHF1b3RhIGRpbWVuc2lvbnMpJywge30sIDMwMDAsIFsndGVhbSddLCA5LCB7IGZlYXR1cmVzOiBbJ3RlYW1fdXNhZ2VfYW5hbHl0aWNzJ10sIHN0YWNrYWJsZTogZmFsc2UgfSksXG4gICAgLy8gUmV0ZW50aW9uIHBhY2tzIChkb2NzL2JpbGxpbmctYnVuZGxlcy5tZCkuIFN0YWNrYWJsZSBjYXBhY2l0eSBwYWNrcyB0aGF0XG4gICAgLy8gcmFpc2UgdGhlIHJlcG9ydGluZyByZXRlbnRpb24gZW50aXRsZW1lbnQgYmlsbGluZyBzeW5jcyB0byByZXBvcnRpbmcnc1xuICAgIC8vIGBkb3JhX3NldHRpbmdzYC4gTk9UIHF1b3RhLW1ldGVyZWQgZmxvdyDigJQgYGV2ZW50UmV0ZW50aW9uRGF5c2AvYGRvcmFSZXRlbnRpb25EYXlzYFxuICAgIC8vIGFyZSBhYnNlbnQgZnJvbSBWQUxJRF9RVU9UQV9UWVBFUywgc28gdGhleSBuZXZlciByaWRlIHRoZSBxdW90YS1zZXJ2aWNlIGxlZy5cbiAgICAvLyBTdGFuZGFyZCBSZXRlbnRpb24gUGFjazogKzkwZCBzdGFuZGFyZC1ldmVudCByZXRlbnRpb24gKGJhc2UgMzAg4oaSIDEyMCDihpIgMjEw4oCmKS5cbiAgICAvLyBDYXBwZWQgYXQgNyAoMzAgKyA3w5c5MCA9IDY2MCDiiaQgdGhlIDczMC1kYXkgcmV0ZW50aW9uIGNlaWxpbmcpLlxuICAgIGIoJ3JldGVudGlvbl9wYWNrJywgJ1N0YW5kYXJkIFJldGVudGlvbiBQYWNrICgrOTBkKScsICc5MCBhZGRpdGlvbmFsIGRheXMgb2Ygc3RhbmRhcmQgcGlwZWxpbmUtZXZlbnQgcmV0ZW50aW9uJywgeyBldmVudFJldGVudGlvbkRheXM6IDkwIH0sIDE1MDAsIEFMTCwgMTAsIHsgbWF4UXVhbnRpdHk6IDcgfSksXG4gICAgLy8gRE9SQSBIaXN0b3J5IFBhY2s6ICszNjVkIERPUkEgcmV0ZW50aW9uIEFORCBwZXItb3JnIHJlcG9ydC1xdWVyeSB3aW5kb3cgKHRoZVxuICAgIC8vIHdpbmRvdyBjYXAgdHJhY2tzIGRvcmFSZXRlbnRpb25EYXlzKS4gT25seSBtZWFuaW5nZnVsIHdpdGggQWR2YW5jZWQgUmVwb3J0aW5nXG4gICAgLy8g4oCUIElOQ0xVREVEIGluIEVudGVycHJpc2UsIGFuIGFkZC1vbiBvbiBkZXZlbG9wZXIvcHJvL3RlYW0g4oCUIHNvIGl0XG4gICAgLy8gYHJlcXVpcmVzRmVhdHVyZXNgIGl0ICh0aGUgdGllciBPUiBhIGhlbGQgYnVuZGxlIHNhdGlzZmllcyBpdCkuIENhcHBlZCBhdCAxXG4gICAgLy8gKDE4MCArIDM2NSA9IDU0NSDiiaQgdGhlIDczMC1kYXkgcmV0ZW50aW9uIGNlaWxpbmcpLlxuICAgIGIoJ2RvcmFfaGlzdG9yeV9wYWNrJywgJ0RPUkEgSGlzdG9yeSBQYWNrICgrMzY1ZCknLCAnMzY1IGFkZGl0aW9uYWwgZGF5cyBvZiBET1JBIGhpc3RvcnkgKyByZXBvcnQtcXVlcnkgd2luZG93IChyZXF1aXJlcyBBZHZhbmNlZCBSZXBvcnRpbmcpJywgeyBkb3JhUmV0ZW50aW9uRGF5czogMzY1IH0sIDMwMDAsIEFMTCwgMTEsIHsgbWF4UXVhbnRpdHk6IDEsIHJlcXVpcmVzRmVhdHVyZXM6IFsnYWR2YW5jZWRfcmVwb3J0aW5nJ10gfSksXG4gICAgLy8gQ29tcGxpYW5jZSBjb250ZW50IGFkZC1vbnMgKGRvY3MvcGxhbnMvY29tcGxpYW5jZS1hZGRvbnMubWQpLiBGZWF0dXJlIGJ1bmRsZXNcbiAgICAvLyBnYXRpbmcgYWNjZXNzIHRvIGN1cmF0ZWQgc3lzdGVtLW9yZyBwdWJsaXNoZWQgcnVsZSBzZXRzLiBJTkNMVURFRCBpblxuICAgIC8vIEVudGVycHJpc2UvVW5saW1pdGVkICh2aWEgQUxMX0ZFQVRVUkVfRkxBR1MpOyBzb2xkIHRvIERldmVsb3Blci9Qcm8vVGVhbS5cbiAgICAvLyBTdGFuZGFyZCA9IH4yMCBDSS9DRCBiZXN0LXByYWN0aWNlIHJ1bGVzLiBBZHZhbmNlZCA9IFNPQzIvUENJL0NJUyBmcmFtZXdvcmtcbiAgICAvLyBsaWJyYXJpZXM7IFJFUVVJUkVTIFN0YW5kYXJkIChvciBidXkgdGhlIFN1aXRlIGNvbWJvIGZvciBib3RoIGF0IDMwJSBvZmYpLlxuICAgIGIoJ2NvbXBsaWFuY2Vfc3RhbmRhcmQnLCAnU3RhbmRhcmQgQ29tcGxpYW5jZScsICdDdXJhdGVkIENJL0NEIGJlc3QtcHJhY3RpY2UgY29tcGxpYW5jZSBydWxlcycsIHt9LCAyOTkwLCBbJ2RldmVsb3BlcicsICdwcm8nLCAndGVhbSddLCAxMiwgeyBmZWF0dXJlczogWydjb21wbGlhbmNlX3N0YW5kYXJkJ10sIHN0YWNrYWJsZTogZmFsc2UgfSksXG4gICAgYignY29tcGxpYW5jZV9hZHZhbmNlZCcsICdBZHZhbmNlZCBDb21wbGlhbmNlJywgJ0N1cmF0ZWQgZnJhbWV3b3JrIGNvbXBsaWFuY2UgbGlicmFyaWVzIChTT0MyIC8gUENJLURTUyAvIENJUyknLCB7fSwgOTk5MCwgWydkZXZlbG9wZXInLCAncHJvJywgJ3RlYW0nXSwgMTMsIHsgZmVhdHVyZXM6IFsnY29tcGxpYW5jZV9hZHZhbmNlZCddLCBzdGFja2FibGU6IGZhbHNlLCByZXF1aXJlczogWydjb21wbGlhbmNlX3N0YW5kYXJkJ10gfSksXG4gIF07XG4gIGFzc2VydEJ1bmRsZVJlcXVpcmVzVmFsaWQoYnVuZGxlcyk7XG4gIHJldHVybiBidW5kbGVzO1xufVxuXG4vKipcbiAqIENvbmZpZy1sb2FkIGd1YXJkcmFpbCBmb3IgdGhlIGByZXF1aXJlc2AgLyBgcmVxdWlyZXNGZWF0dXJlc2AgcHJlcmVxdWlzaXRlcy4gQVxuICogYHJlcXVpcmVzYCBlbnRyeSB0aGF0IGRvZXNuJ3QgcmVzb2x2ZSB0byBhbiBBQ1RJVkUgYnVuZGxlIOKAlCBvciB0aGF0IHBhcnRpY2lwYXRlc1xuICogaW4gYSBjeWNsZSDigJQgc2lsZW50bHkgbWFrZXMgdGhlIHJlZmVyZW5jaW5nIGJ1bmRsZSB1bnB1cmNoYXNhYmxlICh0aGUgYWRkb25cbiAqIHJvdXRlIHJlamVjdHMgd2l0aCA0MDAgZm9yZXZlciBiZWNhdXNlIHRoZSBwcmVyZXF1aXNpdGUgY2FuIG5ldmVyIGJlXG4gKiBzYXRpc2ZpZWQpLiBDYXRjaCBpdCBhdCBsb2FkIHdpdGggYSBjbGVhciBlcnJvciByYXRoZXIgdGhhbiBzaGlwcGluZyBhIGRlYWQgU0tVLlxuICpcbiAqICAtIEV2ZXJ5IGlkIGluIGEgYnVuZGxlJ3MgYHJlcXVpcmVzYCBNVVNUIG5hbWUgYW4gYWN0aXZlIGJ1bmRsZSBpbiB0aGUgY2F0YWxvZy5cbiAqICAtIFRoZSBgcmVxdWlyZXNgIGdyYXBoIE1VU1QgYmUgYWN5Y2xpYyAoYSDihpIgYiDihpIgYSBjYW4gbmV2ZXIgYmUgc2F0aXNmaWVkKS5cbiAqICAtIEV2ZXJ5IGByZXF1aXJlc0ZlYXR1cmVzYCBlbnRyeSBNVVNUIGJlIGEgcmVhbCBmZWF0dXJlIGZsYWcsIGF0dGFpbmFibGUgb25cbiAqICAgIEVWRVJZIHRpZXIgdGhlIGJ1bmRsZSBpcyBzb2xkIHRvIOKAlCBlaXRoZXIgdGllci1pbmNsdWRlZCAoYFRJRVJfRkVBVFVSRVNgKSBvclxuICogICAgZ3JhbnRlZCBieSBhbiBhY3RpdmUgYnVuZGxlIG9mZmVyZWQgb24gdGhhdCBzYW1lIHRpZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhc3NlcnRCdW5kbGVSZXF1aXJlc1ZhbGlkKGJ1bmRsZXM6IEJ1bmRsZUNvbmZpZ1tdKTogdm9pZCB7XG4gIGNvbnN0IGFjdGl2ZSA9IG5ldyBNYXAoYnVuZGxlcy5maWx0ZXIoKGIpID0+IGIuaXNBY3RpdmUpLm1hcCgoYikgPT4gW2IuaWQsIGJdKSk7XG5cbiAgLy8gMS4gVmFsaWRpdHk6IGV2ZXJ5IHJlcXVpcmVzIGlkIHJlc29sdmVzIHRvIGFuIGFjdGl2ZSBidW5kbGUuXG4gIGZvciAoY29uc3QgYnVuZGxlIG9mIGJ1bmRsZXMpIHtcbiAgICBmb3IgKGNvbnN0IHJlcUlkIG9mIGJ1bmRsZS5yZXF1aXJlcyA/PyBbXSkge1xuICAgICAgaWYgKCFhY3RpdmUuaGFzKHJlcUlkKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYFtiaWxsaW5nLWNvbmZpZ10gQnVuZGxlIFwiJHtidW5kbGUuaWR9XCIgcmVxdWlyZXMgXCIke3JlcUlkfVwiLCB3aGljaCBpcyBub3QgYW4gYWN0aXZlIGJ1bmRsZSBpbiB0aGUgY2F0YWxvZyDigJQgaXQgd291bGQgYmUgcGVybWFuZW50bHkgdW5wdXJjaGFzYWJsZS5gLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIDFiLiBGZWF0dXJlIHByZXJlcXVpc2l0ZXM6IGEgcmVhbCBmbGFnLCBhdHRhaW5hYmxlIG9uIGV2ZXJ5IHNvbGQtdG8gdGllci5cbiAgZm9yIChjb25zdCBidW5kbGUgb2YgYnVuZGxlcykge1xuICAgIGZvciAoY29uc3QgZmxhZyBvZiBidW5kbGUucmVxdWlyZXNGZWF0dXJlcyA/PyBbXSkge1xuICAgICAgaWYgKCFpc1ZhbGlkRmVhdHVyZUZsYWcoZmxhZykpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbYmlsbGluZy1jb25maWddIEJ1bmRsZSBcIiR7YnVuZGxlLmlkfVwiIHJlcXVpcmVzRmVhdHVyZXMgXCIke2ZsYWd9XCIsIHdoaWNoIGlzIG5vdCBhIGZlYXR1cmUgZmxhZy5gKTtcbiAgICAgIH1cbiAgICAgIGZvciAoY29uc3QgdGllciBvZiBidW5kbGUuYXZhaWxhYmxlRm9yVGllcnMpIHtcbiAgICAgICAgY29uc3QgdGllckluY2x1ZGVzID0gKFRJRVJfRkVBVFVSRVNbdGllcl0gPz8gW10pLmluY2x1ZGVzKGZsYWcpO1xuICAgICAgICBjb25zdCBidXlhYmxlID0gWy4uLmFjdGl2ZS52YWx1ZXMoKV0uc29tZSgobykgPT4gby5hdmFpbGFibGVGb3JUaWVycy5pbmNsdWRlcyh0aWVyKSAmJiAoby5mZWF0dXJlcyA/PyBbXSkuaW5jbHVkZXMoZmxhZykpO1xuICAgICAgICBpZiAoIXRpZXJJbmNsdWRlcyAmJiAhYnV5YWJsZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBbYmlsbGluZy1jb25maWddIEJ1bmRsZSBcIiR7YnVuZGxlLmlkfVwiIHJlcXVpcmVzIGZlYXR1cmUgXCIke2ZsYWd9XCIsIHdoaWNoIHRoZSAke3RpZXJ9IHRpZXIgbmVpdGhlciBpbmNsdWRlcyBub3IgY2FuIGJ1eSDigJQgaXQgd291bGQgYmUgcGVybWFuZW50bHkgdW5wdXJjaGFzYWJsZSB0aGVyZS5gLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyAyLiBBY3ljbGljaXR5OiBERlMgb3ZlciB0aGUgcmVxdWlyZXMgZWRnZXMsIHRyYWNraW5nIHRoZSBjdXJyZW50IHBhdGguXG4gIGNvbnN0IFZJU0lUSU5HID0gMTtcbiAgY29uc3QgRE9ORSA9IDI7XG4gIGNvbnN0IHN0YXRlID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcblxuICBjb25zdCB2aXNpdCA9IChpZDogc3RyaW5nLCBwYXRoOiBzdHJpbmdbXSk6IHZvaWQgPT4ge1xuICAgIGNvbnN0IHMgPSBzdGF0ZS5nZXQoaWQpO1xuICAgIGlmIChzID09PSBET05FKSByZXR1cm47XG4gICAgaWYgKHMgPT09IFZJU0lUSU5HKSB7XG4gICAgICBjb25zdCBjeWNsZSA9IFsuLi5wYXRoLnNsaWNlKHBhdGguaW5kZXhPZihpZCkpLCBpZF0uam9pbignIC0+ICcpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBbYmlsbGluZy1jb25maWddIEJ1bmRsZSBcInJlcXVpcmVzXCIgY3ljbGUgZGV0ZWN0ZWQ6ICR7Y3ljbGV9LmApO1xuICAgIH1cbiAgICBzdGF0ZS5zZXQoaWQsIFZJU0lUSU5HKTtcbiAgICBmb3IgKGNvbnN0IHJlcUlkIG9mIGFjdGl2ZS5nZXQoaWQpPy5yZXF1aXJlcyA/PyBbXSkge1xuICAgICAgdmlzaXQocmVxSWQsIFsuLi5wYXRoLCBpZF0pO1xuICAgIH1cbiAgICBzdGF0ZS5zZXQoaWQsIERPTkUpO1xuICB9O1xuXG4gIGZvciAoY29uc3QgYnVuZGxlIG9mIGFjdGl2ZS5rZXlzKCkpIHtcbiAgICB2aXNpdChidW5kbGUsIFtdKTtcbiAgfVxufVxuIl19
|