From 29b17c8028a55d3a0e854d6efb945f9cbdbedfcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Wed, 22 Jul 2026 17:42:19 +0800 Subject: [PATCH] fix(models): expose current Claude official lineup --- adapters/telegram/__tests__/commands.test.ts | 4 +- adapters/telegram/commands.ts | 2 +- .../src/__tests__/generalSettings.test.tsx | 14 ++ .../controls/ModelSelector.test.tsx | 38 ++++ .../src/components/controls/ModelSelector.tsx | 14 +- desktop/src/constants/modelCatalog.ts | 28 ++- .../__tests__/providerSettingsJson.test.ts | 2 + desktop/src/lib/providerSettingsJson.ts | 4 + desktop/src/mocks/data.ts | 5 +- desktop/src/pages/SessionControls.tsx | 2 +- desktop/src/pages/Settings.tsx | 21 ++- desktop/src/types/provider.ts | 1 + desktop/src/types/providerPreset.ts | 1 + src/commands/effort/effort.tsx | 4 +- src/commands/model/model.tsx | 20 ++- src/commands/ultraplan.tsx | 4 +- src/constants/prompts.ts | 19 +- .../__tests__/e2e/business-flow.test.ts | 17 +- src/server/__tests__/e2e/full-flow.test.ts | 4 +- .../__tests__/provider-runtime-env.test.ts | 4 + src/server/__tests__/settings.test.ts | 151 +++++++++++++++- src/server/api/models.ts | 28 ++- src/server/config/providerPresets.ts | 1 + src/server/services/conversationService.ts | 8 + .../services/persistentStorageMigrations.ts | 2 + src/server/services/providerRuntimeEnv.ts | 13 ++ src/server/services/sessionService.ts | 2 + src/server/types/provider.ts | 1 + src/skills/bundled/claudeApiContent.ts | 8 +- .../providerManagedEnvCompat.test.ts | 3 + src/utils/__tests__/thinking.test.ts | 65 +++++++ src/utils/attribution.ts | 4 +- src/utils/auth.ts | 29 ++- src/utils/betas.ts | 34 +++- src/utils/commitAttribution.ts | 3 + src/utils/context.ts | 11 +- src/utils/effort.ts | 34 +++- src/utils/fastMode.ts | 2 +- src/utils/managedEnvConstants.ts | 8 + src/utils/model/configs.ts | 20 ++- src/utils/model/fable.test.ts | 81 ++++++++- src/utils/model/model.ts | 67 +++++-- src/utils/model/modelContextWindows.ts | 4 + src/utils/model/modelOptions.ts | 167 ++++++++++++------ src/utils/model/providers.ts | 4 + src/utils/modelCost.ts | 18 ++ src/utils/providerManagedEnvCompat.ts | 2 + src/utils/swarm/teammateModel.ts | 11 +- src/utils/thinking.ts | 10 +- 49 files changed, 845 insertions(+), 154 deletions(-) diff --git a/adapters/telegram/__tests__/commands.test.ts b/adapters/telegram/__tests__/commands.test.ts index 30875e79..ca653b1e 100644 --- a/adapters/telegram/__tests__/commands.test.ts +++ b/adapters/telegram/__tests__/commands.test.ts @@ -271,8 +271,8 @@ describe('Telegram command controller helpers', () => { await controller.handleProviderCommand(allowed.ctx) expect(deps.httpClient.activateOfficialProvider).toHaveBeenCalled() - expect(deps.httpClient.setCurrentModel).toHaveBeenCalledWith('claude-opus-4-7') - expect(runtimeModels).toEqual(['claude-opus-4-7']) + expect(deps.httpClient.setCurrentModel).toHaveBeenCalledWith('claude-opus-4-8') + expect(runtimeModels).toEqual(['claude-opus-4-8']) expect(allowed.replies[0]).toContain('Claude 官方') const denied = createCommandContext({ userId: 999 }) diff --git a/adapters/telegram/commands.ts b/adapters/telegram/commands.ts index b5f389b9..efcee045 100644 --- a/adapters/telegram/commands.ts +++ b/adapters/telegram/commands.ts @@ -16,7 +16,7 @@ import { export const TELEGRAM_SELECTION_TTL_MS = 15 * 60 * 1000 export const OFFICIAL_PROVIDER_VALUE = 'official' export const OPENAI_OFFICIAL_PROVIDER_ID = 'openai-official' -export const OFFICIAL_DEFAULT_MODEL_ID = 'claude-opus-4-7' +export const OFFICIAL_DEFAULT_MODEL_ID = 'claude-opus-4-8' export const OPENAI_OFFICIAL_DEFAULT_MODEL_ID = 'gpt-5.3-codex' type TelegramSendApi = { diff --git a/desktop/src/__tests__/generalSettings.test.tsx b/desktop/src/__tests__/generalSettings.test.tsx index 96446312..b9ed6c06 100644 --- a/desktop/src/__tests__/generalSettings.test.tsx +++ b/desktop/src/__tests__/generalSettings.test.tsx @@ -1906,6 +1906,20 @@ describe('Settings > Providers tab', () => { expect(providerStoreState.testConfig).not.toHaveBeenCalledWith(expect.objectContaining({ modelId: 'deepseek-v4-pro', })) + + fireEvent.click(within(dialog).getByRole('button', { name: /Save|Add|保存|添加/i })) + + await waitFor(() => { + expect(providerStoreState.createProvider).toHaveBeenCalledWith(expect.objectContaining({ + models: expect.objectContaining({ + fable: 'Qwen3Coder', + main: 'claude-sonnet-4-6', + haiku: 'claude-haiku-4-5', + sonnet: 'claude-sonnet-4-6', + opus: 'claude-opus-4-8', + }), + })) + }) }) it('keeps the provider form locked while save is in flight', async () => { diff --git a/desktop/src/components/controls/ModelSelector.test.tsx b/desktop/src/components/controls/ModelSelector.test.tsx index d9a6f969..51021400 100644 --- a/desktop/src/components/controls/ModelSelector.test.tsx +++ b/desktop/src/components/controls/ModelSelector.test.tsx @@ -43,6 +43,44 @@ beforeEach(() => { }) describe('ModelSelector', () => { + it('keeps the current Claude Official catalog visible when the API returns legacy settings models', async () => { + const legacyModels: ModelInfo[] = [ + { id: 'claude-opus-4-7', name: 'Opus 4.7', description: 'Legacy Opus', context: '1m' }, + { id: 'claude-sonnet-4-6', name: 'Sonnet 4.6', description: 'Legacy Sonnet', context: '200k' }, + { id: 'claude-haiku-4-5', name: 'Haiku 4.5', description: 'Legacy Haiku', context: '200k' }, + ] + useHahaOAuthStore.setState({ + status: { + loggedIn: true, + expiresAt: null, + scopes: [], + subscriptionType: 'pro', + }, + fetchStatus: async () => {}, + }) + useSettingsStore.setState({ + locale: 'en', + availableModels: legacyModels, + currentModel: legacyModels[0], + activeProviderName: 'Claude Official', + }) + useProviderStore.setState({ + providers: [], + activeId: null, + hasLoadedProviders: true, + isLoading: false, + }) + + render() + + await clickByRole(/Opus 4\.7/i) + + expect(screen.getByRole('button', { name: /Fable 5/ })).toBeInTheDocument() + expect(screen.getByRole('button', { name: /Opus 4\.8/ })).toBeInTheDocument() + expect(screen.getByRole('button', { name: /Sonnet 5/ })).toBeInTheDocument() + expect(screen.getAllByRole('button', { name: /Opus 4\.7/ }).length).toBeGreaterThan(0) + }) + it('does not query official OAuth status when mounted', () => { const fetchClaudeStatus = vi.fn(async () => {}) const fetchOpenAIStatus = vi.fn(async () => {}) diff --git a/desktop/src/components/controls/ModelSelector.tsx b/desktop/src/components/controls/ModelSelector.tsx index c95547be..4d5598bf 100644 --- a/desktop/src/components/controls/ModelSelector.tsx +++ b/desktop/src/components/controls/ModelSelector.tsx @@ -76,6 +76,18 @@ function officialChoices( } } +function mergeOfficialModels(availableModels: ModelInfo[]): ModelInfo[] { + const merged = [...OFFICIAL_MODELS] + const knownIds = new Set(merged.map(model => model.id)) + for (const model of availableModels) { + if (!knownIds.has(model.id)) { + knownIds.add(model.id) + merged.push(model) + } + } + return merged +} + function buildProviderModels( provider: SavedProvider, labels: Record<'main' | 'haiku' | 'sonnet' | 'opus', string>, @@ -121,7 +133,7 @@ function buildProviderChoices( grokOfficialLoggedIn: boolean, ): ProviderChoice[] { const claudeOfficialModels = activeId === null && availableModels.length > 0 - ? availableModels + ? mergeOfficialModels(availableModels) : OFFICIAL_MODELS const openAIOfficialModels = activeId === OPENAI_OFFICIAL_PROVIDER_ID && availableModels.length > 0 ? availableModels diff --git a/desktop/src/constants/modelCatalog.ts b/desktop/src/constants/modelCatalog.ts index fbd8dbb7..f97aca24 100644 --- a/desktop/src/constants/modelCatalog.ts +++ b/desktop/src/constants/modelCatalog.ts @@ -1,24 +1,34 @@ import type { ModelInfo } from '../types/settings' -export const OFFICIAL_DEFAULT_MODEL_ID = 'claude-opus-4-7' +export const OFFICIAL_DEFAULT_MODEL_ID = 'claude-opus-4-8' export const OFFICIAL_MODELS: ModelInfo[] = [ { - id: 'claude-opus-4-7', - name: 'Opus 4.7', - description: 'Most capable for ambitious work', + id: 'claude-fable-5', + name: 'Fable 5', + description: 'Highest capability for long-running tasks', context: '1m', }, { - id: 'claude-sonnet-4-6', - name: 'Sonnet 4.6', - description: 'Most efficient for everyday tasks', - context: '200k', + id: 'claude-opus-4-8', + name: 'Opus 4.8', + description: 'Best for complex agentic coding and enterprise work', + context: '1m', + defaultReasoningEffort: 'high', + supportedReasoningEfforts: ['low', 'medium', 'high', 'xhigh', 'max'], + }, + { + id: 'claude-sonnet-5', + name: 'Sonnet 5', + description: 'Best combination of speed and intelligence', + context: '1m', + defaultReasoningEffort: 'high', + supportedReasoningEfforts: ['low', 'medium', 'high', 'xhigh', 'max'], }, { id: 'claude-haiku-4-5', name: 'Haiku 4.5', - description: 'Fastest for quick answers', + description: 'Fastest with near-frontier intelligence', context: '200k', }, ] diff --git a/desktop/src/lib/__tests__/providerSettingsJson.test.ts b/desktop/src/lib/__tests__/providerSettingsJson.test.ts index f1741b08..d4432bec 100644 --- a/desktop/src/lib/__tests__/providerSettingsJson.test.ts +++ b/desktop/src/lib/__tests__/providerSettingsJson.test.ts @@ -67,6 +67,8 @@ describe('provider settings JSON helpers', () => { ANTHROPIC_AUTH_TOKEN: 'old-auth-token', ANTHROPIC_BASE_URL: 'https://old.example.com', ANTHROPIC_MODEL: 'old-model', + ANTHROPIC_DEFAULT_FABLE_MODEL: 'old-fable', + ANTHROPIC_DEFAULT_FABLE_MODEL_NAME: 'Old Fable', CLAUDE_CODE_MODEL_CONTEXT_WINDOWS: '{"old":100000}', CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: '1', CC_HAHA_OPENAI_OAUTH_PROVIDER: '1', diff --git a/desktop/src/lib/providerSettingsJson.ts b/desktop/src/lib/providerSettingsJson.ts index 954834da..8353d805 100644 --- a/desktop/src/lib/providerSettingsJson.ts +++ b/desktop/src/lib/providerSettingsJson.ts @@ -8,6 +8,10 @@ const PROVIDER_SETTINGS_JSON_ENV_KEYS = new Set([ 'ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_NAME', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_HAIKU_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION', 'ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME', diff --git a/desktop/src/mocks/data.ts b/desktop/src/mocks/data.ts index 28295704..c2da335f 100644 --- a/desktop/src/mocks/data.ts +++ b/desktop/src/mocks/data.ts @@ -146,8 +146,9 @@ export const mockPermissionModes = [ ] export const mockModels = [ - { id: 'opus', name: 'Opus 4.7', active: false }, - { id: 'sonnet', name: 'Sonnet 4.6', active: true }, + { id: 'fable', name: 'Fable 5', active: false }, + { id: 'opus', name: 'Opus 4.8', active: true }, + { id: 'sonnet', name: 'Sonnet 5', active: false }, { id: 'haiku', name: 'Haiku 4.5', active: false }, ] diff --git a/desktop/src/pages/SessionControls.tsx b/desktop/src/pages/SessionControls.tsx index 9ae10031..122cfff7 100644 --- a/desktop/src/pages/SessionControls.tsx +++ b/desktop/src/pages/SessionControls.tsx @@ -408,7 +408,7 @@ export default function SessionControls() { {modelIcons[selectedModel] || 'smart_toy'} - {activeModel?.name || 'Sonnet 4.6'} + {activeModel?.name || 'Opus 4.8'} {/* Attach file button */} diff --git a/desktop/src/pages/Settings.tsx b/desktop/src/pages/Settings.tsx index 2b2309b9..85ffca4e 100644 --- a/desktop/src/pages/Settings.tsx +++ b/desktop/src/pages/Settings.tsx @@ -900,6 +900,7 @@ function stripModel1mMarker(model: string): string { function stripModel1mMarkers(models: ModelMapping): ModelMapping { return { main: stripModel1mMarker(models.main), + ...(models.fable ? { fable: stripModel1mMarker(models.fable) } : {}), haiku: stripModel1mMarker(models.haiku), sonnet: stripModel1mMarker(models.sonnet), opus: stripModel1mMarker(models.opus), @@ -929,6 +930,7 @@ function applyModel1mSupportMapping( ): ModelMapping { return { main: applyModel1mSupport(models.main, model1mSupport.main), + ...(models.fable ? { fable: stripModel1mMarker(models.fable) } : {}), haiku: applyModel1mSupport(models.haiku, model1mSupport.haiku), sonnet: applyModel1mSupport(models.sonnet, model1mSupport.sonnet), opus: applyModel1mSupport(models.opus, model1mSupport.opus), @@ -968,6 +970,7 @@ function normalizeModelMapping(models: ModelMapping): ModelMapping { const main = models.main.trim() return { main, + ...(models.fable?.trim() ? { fable: models.fable.trim() } : {}), haiku: models.haiku.trim() || main, sonnet: models.sonnet.trim() || main, opus: models.opus.trim() || main, @@ -982,6 +985,14 @@ function readSettingsEnvString(env: Record, key: string): strin } function readModelMappingFromSettingsEnv(env: Record): Partial { + const hasModelEnv = [ + 'ANTHROPIC_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL', + 'ANTHROPIC_DEFAULT_HAIKU_MODEL', + 'ANTHROPIC_DEFAULT_SONNET_MODEL', + 'ANTHROPIC_DEFAULT_OPUS_MODEL', + ].some((key) => Object.prototype.hasOwnProperty.call(env, key)) + const fable = readSettingsEnvString(env, 'ANTHROPIC_DEFAULT_FABLE_MODEL') const haiku = readSettingsEnvString(env, 'ANTHROPIC_DEFAULT_HAIKU_MODEL') const sonnet = readSettingsEnvString(env, 'ANTHROPIC_DEFAULT_SONNET_MODEL') const opus = readSettingsEnvString(env, 'ANTHROPIC_DEFAULT_OPUS_MODEL') @@ -989,6 +1000,7 @@ function readModelMappingFromSettingsEnv(env: Record): Partial< return { ...(main ? { main } : {}), + ...(hasModelEnv ? { fable } : {}), ...(haiku ? { haiku } : {}), ...(sonnet ? { sonnet } : {}), ...(opus ? { opus } : {}), @@ -1133,9 +1145,15 @@ function updateSettingsJsonModels( ? parsed.env : {} const runtimeModels = applyModel1mSupportMapping(models, model1mSupport) + const env = { ...existingEnv } + delete env.ANTHROPIC_DEFAULT_FABLE_MODEL + delete env.ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION + delete env.ANTHROPIC_DEFAULT_FABLE_MODEL_NAME + delete env.ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES parsed.env = { - ...existingEnv, + ...env, ANTHROPIC_MODEL: runtimeModels.main, + ...(runtimeModels.fable ? { ANTHROPIC_DEFAULT_FABLE_MODEL: runtimeModels.fable } : {}), ANTHROPIC_DEFAULT_HAIKU_MODEL: runtimeModels.haiku, ANTHROPIC_DEFAULT_SONNET_MODEL: runtimeModels.sonnet, ANTHROPIC_DEFAULT_OPUS_MODEL: runtimeModels.opus, @@ -1282,6 +1300,7 @@ function ProviderFormModal({ open, onClose, mode, provider, presets }: ProviderF ANTHROPIC_BASE_URL: needsProxy ? providerProxyBaseUrl : baseUrl, ...buildSettingsJsonAuthEnv(apiFormat, authStrategy, apiKey, selectedPreset), ANTHROPIC_MODEL: runtimeModels.main, + ...(runtimeModels.fable ? { ANTHROPIC_DEFAULT_FABLE_MODEL: runtimeModels.fable } : {}), ANTHROPIC_DEFAULT_HAIKU_MODEL: runtimeModels.haiku, ANTHROPIC_DEFAULT_SONNET_MODEL: runtimeModels.sonnet, ANTHROPIC_DEFAULT_OPUS_MODEL: runtimeModels.opus, diff --git a/desktop/src/types/provider.ts b/desktop/src/types/provider.ts index 8036ec9a..1c14ac5f 100644 --- a/desktop/src/types/provider.ts +++ b/desktop/src/types/provider.ts @@ -13,6 +13,7 @@ export type ProviderRuntimeKind = 'anthropic_compatible' | 'openai_oauth' | 'gro export type ModelMapping = { main: string + fable?: string haiku: string sonnet: string opus: string diff --git a/desktop/src/types/providerPreset.ts b/desktop/src/types/providerPreset.ts index cc06f8f8..9b0f8727 100644 --- a/desktop/src/types/providerPreset.ts +++ b/desktop/src/types/providerPreset.ts @@ -2,6 +2,7 @@ import type { ApiFormat, ProviderAuthStrategy } from './provider' export type ModelMapping = { main: string + fable?: string haiku: string sonnet: string opus: string diff --git a/src/commands/effort/effort.tsx b/src/commands/effort/effort.tsx index cf4bd2de..35acf91f 100644 --- a/src/commands/effort/effort.tsx +++ b/src/commands/effort/effort.tsx @@ -171,7 +171,7 @@ function ApplyEffortAndClose(t0) { export async function call(onDone: LocalJSXCommandOnDone, _context: unknown, args?: string): Promise { args = args?.trim() || ''; if (COMMON_HELP_ARGS.includes(args)) { - onDone('Usage: /effort [low|medium|high|max|auto]\n\nEffort levels:\n- low: Quick, straightforward implementation\n- medium: Balanced approach with standard testing\n- high: Comprehensive implementation with extensive testing\n- max: Maximum capability with deepest reasoning (Opus 4.7 only)\n- auto: Use the default effort level for your model'); + onDone('Usage: /effort [low|medium|high|max|auto]\n\nEffort levels:\n- low: Quick, straightforward implementation\n- medium: Balanced approach with standard testing\n- high: Comprehensive implementation with extensive testing\n- max: Maximum capability with deepest reasoning\n- auto: Use the default effort level for your model'); return; } if (!args || args === 'current' || args === 'status') { @@ -180,4 +180,4 @@ export async function call(onDone: LocalJSXCommandOnDone, _context: unknown, arg const result = executeEffort(args); return ; } -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInVzZU1haW5Mb29wTW9kZWwiLCJBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTIiwibG9nRXZlbnQiLCJ1c2VBcHBTdGF0ZSIsInVzZVNldEFwcFN0YXRlIiwiTG9jYWxKU1hDb21tYW5kT25Eb25lIiwiRWZmb3J0VmFsdWUiLCJnZXREaXNwbGF5ZWRFZmZvcnRMZXZlbCIsImdldEVmZm9ydEVudk92ZXJyaWRlIiwiZ2V0RWZmb3J0VmFsdWVEZXNjcmlwdGlvbiIsImlzRWZmb3J0TGV2ZWwiLCJ0b1BlcnNpc3RhYmxlRWZmb3J0IiwidXBkYXRlU2V0dGluZ3NGb3JTb3VyY2UiLCJDT01NT05fSEVMUF9BUkdTIiwiRWZmb3J0Q29tbWFuZFJlc3VsdCIsIm1lc3NhZ2UiLCJlZmZvcnRVcGRhdGUiLCJ2YWx1ZSIsInNldEVmZm9ydFZhbHVlIiwiZWZmb3J0VmFsdWUiLCJwZXJzaXN0YWJsZSIsInVuZGVmaW5lZCIsInJlc3VsdCIsImVmZm9ydExldmVsIiwiZXJyb3IiLCJlZmZvcnQiLCJlbnZPdmVycmlkZSIsImVudlJhdyIsInByb2Nlc3MiLCJlbnYiLCJDTEFVREVfQ09ERV9FRkZPUlRfTEVWRUwiLCJkZXNjcmlwdGlvbiIsInN1ZmZpeCIsInNob3dDdXJyZW50RWZmb3J0IiwiYXBwU3RhdGVFZmZvcnQiLCJtb2RlbCIsImVmZmVjdGl2ZVZhbHVlIiwibGV2ZWwiLCJ1bnNldEVmZm9ydExldmVsIiwiZXhlY3V0ZUVmZm9ydCIsImFyZ3MiLCJub3JtYWxpemVkIiwidG9Mb3dlckNhc2UiLCJTaG93Q3VycmVudEVmZm9ydCIsInQwIiwib25Eb25lIiwiX3RlbXAiLCJzIiwiQXBwbHlFZmZvcnRBbmRDbG9zZSIsIiQiLCJfYyIsInNldEFwcFN0YXRlIiwidDEiLCJ0MiIsInByZXYiLCJ1c2VFZmZlY3QiLCJjYWxsIiwiX2NvbnRleHQiLCJQcm9taXNlIiwiUmVhY3ROb2RlIiwidHJpbSIsImluY2x1ZGVzIl0sInNvdXJjZXMiOlsiZWZmb3J0LnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IHVzZU1haW5Mb29wTW9kZWwgfSBmcm9tICcuLi8uLi9ob29rcy91c2VNYWluTG9vcE1vZGVsLmpzJ1xuaW1wb3J0IHtcbiAgdHlwZSBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICBsb2dFdmVudCxcbn0gZnJvbSAnLi4vLi4vc2VydmljZXMvYW5hbHl0aWNzL2luZGV4LmpzJ1xuaW1wb3J0IHsgdXNlQXBwU3RhdGUsIHVzZVNldEFwcFN0YXRlIH0gZnJvbSAnLi4vLi4vc3RhdGUvQXBwU3RhdGUuanMnXG5pbXBvcnQgdHlwZSB7IExvY2FsSlNYQ29tbWFuZE9uRG9uZSB9IGZyb20gJy4uLy4uL3R5cGVzL2NvbW1hbmQuanMnXG5pbXBvcnQge1xuICB0eXBlIEVmZm9ydFZhbHVlLFxuICBnZXREaXNwbGF5ZWRFZmZvcnRMZXZlbCxcbiAgZ2V0RWZmb3J0RW52T3ZlcnJpZGUsXG4gIGdldEVmZm9ydFZhbHVlRGVzY3JpcHRpb24sXG4gIGlzRWZmb3J0TGV2ZWwsXG4gIHRvUGVyc2lzdGFibGVFZmZvcnQsXG59IGZyb20gJy4uLy4uL3V0aWxzL2VmZm9ydC5qcydcbmltcG9ydCB7IHVwZGF0ZVNldHRpbmdzRm9yU291cmNlIH0gZnJvbSAnLi4vLi4vdXRpbHMvc2V0dGluZ3Mvc2V0dGluZ3MuanMnXG5cbmNvbnN0IENPTU1PTl9IRUxQX0FSR1MgPSBbJ2hlbHAnLCAnLWgnLCAnLS1oZWxwJ11cblxudHlwZSBFZmZvcnRDb21tYW5kUmVzdWx0ID0ge1xuICBtZXNzYWdlOiBzdHJpbmdcbiAgZWZmb3J0VXBkYXRlPzogeyB2YWx1ZTogRWZmb3J0VmFsdWUgfCB1bmRlZmluZWQgfVxufVxuXG5mdW5jdGlvbiBzZXRFZmZvcnRWYWx1ZShlZmZvcnRWYWx1ZTogRWZmb3J0VmFsdWUpOiBFZmZvcnRDb21tYW5kUmVzdWx0IHtcbiAgY29uc3QgcGVyc2lzdGFibGUgPSB0b1BlcnNpc3RhYmxlRWZmb3J0KGVmZm9ydFZhbHVlKVxuICBpZiAocGVyc2lzdGFibGUgIT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IHJlc3VsdCA9IHVwZGF0ZVNldHRpbmdzRm9yU291cmNlKCd1c2VyU2V0dGluZ3MnLCB7XG4gICAgICBlZmZvcnRMZXZlbDogcGVyc2lzdGFibGUsXG4gICAgfSlcbiAgICBpZiAocmVzdWx0LmVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBtZXNzYWdlOiBgRmFpbGVkIHRvIHNldCBlZmZvcnQgbGV2ZWw6ICR7cmVzdWx0LmVycm9yLm1lc3NhZ2V9YCxcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgbG9nRXZlbnQoJ3Rlbmd1X2VmZm9ydF9jb21tYW5kJywge1xuICAgIGVmZm9ydDpcbiAgICAgIGVmZm9ydFZhbHVlIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gIH0pXG5cbiAgLy8gRW52IHZhciB3aW5zIGF0IHJlc29sdmVBcHBsaWVkRWZmb3J0IHRpbWUuIE9ubHkgZmxhZyBpdCB3aGVuIGl0IGFjdHVhbGx5XG4gIC8vIGNvbmZsaWN0cyDigJQgaWYgZW52IG1hdGNoZXMgd2hhdCB0aGUgdXNlciBqdXN0IGFza2VkIGZvciwgdGhlIG91dGNvbWUgaXNcbiAgLy8gdGhlIHNhbWUsIHNvIFwiU2V0IGVmZm9ydCB0byBYXCIgaXMgdHJ1ZSBhbmQgdGhlIG5vdGUgaXMgbm9pc2UuXG4gIGNvbnN0IGVudk92ZXJyaWRlID0gZ2V0RWZmb3J0RW52T3ZlcnJpZGUoKVxuICBpZiAoZW52T3ZlcnJpZGUgIT09IHVuZGVmaW5lZCAmJiBlbnZPdmVycmlkZSAhPT0gZWZmb3J0VmFsdWUpIHtcbiAgICBjb25zdCBlbnZSYXcgPSBwcm9jZXNzLmVudi5DTEFVREVfQ09ERV9FRkZPUlRfTEVWRUxcbiAgICBpZiAocGVyc2lzdGFibGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbWVzc2FnZTogYE5vdCBhcHBsaWVkOiBDTEFVREVfQ09ERV9FRkZPUlRfTEVWRUw9JHtlbnZSYXd9IG92ZXJyaWRlcyBlZmZvcnQgdGhpcyBzZXNzaW9uLCBhbmQgJHtlZmZvcnRWYWx1ZX0gaXMgc2Vzc2lvbi1vbmx5IChub3RoaW5nIHNhdmVkKWAsXG4gICAgICAgIGVmZm9ydFVwZGF0ZTogeyB2YWx1ZTogZWZmb3J0VmFsdWUgfSxcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIG1lc3NhZ2U6IGBDTEFVREVfQ09ERV9FRkZPUlRfTEVWRUw9JHtlbnZSYXd9IG92ZXJyaWRlcyB0aGlzIHNlc3Npb24g4oCUIGNsZWFyIGl0IGFuZCAke2VmZm9ydFZhbHVlfSB0YWtlcyBvdmVyYCxcbiAgICAgIGVmZm9ydFVwZGF0ZTogeyB2YWx1ZTogZWZmb3J0VmFsdWUgfSxcbiAgICB9XG4gIH1cblxuICBjb25zdCBkZXNjcmlwdGlvbiA9IGdldEVmZm9ydFZhbHVlRGVzY3JpcHRpb24oZWZmb3J0VmFsdWUpXG4gIGNvbnN0IHN1ZmZpeCA9IHBlcnNpc3RhYmxlICE9PSB1bmRlZmluZWQgPyAnJyA6ICcgKHRoaXMgc2Vzc2lvbiBvbmx5KSdcbiAgcmV0dXJuIHtcbiAgICBtZXNzYWdlOiBgU2V0IGVmZm9ydCBsZXZlbCB0byAke2VmZm9ydFZhbHVlfSR7c3VmZml4fTogJHtkZXNjcmlwdGlvbn1gLFxuICAgIGVmZm9ydFVwZGF0ZTogeyB2YWx1ZTogZWZmb3J0VmFsdWUgfSxcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gc2hvd0N1cnJlbnRFZmZvcnQoXG4gIGFwcFN0YXRlRWZmb3J0OiBFZmZvcnRWYWx1ZSB8IHVuZGVmaW5lZCxcbiAgbW9kZWw6IHN0cmluZyxcbik6IEVmZm9ydENvbW1hbmRSZXN1bHQge1xuICBjb25zdCBlbnZPdmVycmlkZSA9IGdldEVmZm9ydEVudk92ZXJyaWRlKClcbiAgY29uc3QgZWZmZWN0aXZlVmFsdWUgPVxuICAgIGVudk92ZXJyaWRlID09PSBudWxsID8gdW5kZWZpbmVkIDogKGVudk92ZXJyaWRlID8/IGFwcFN0YXRlRWZmb3J0KVxuICBpZiAoZWZmZWN0aXZlVmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IGxldmVsID0gZ2V0RGlzcGxheWVkRWZmb3J0TGV2ZWwobW9kZWwsIGFwcFN0YXRlRWZmb3J0KVxuICAgIHJldHVybiB7IG1lc3NhZ2U6IGBFZmZvcnQgbGV2ZWw6IGF1dG8gKGN1cnJlbnRseSAke2xldmVsfSlgIH1cbiAgfVxuICBjb25zdCBkZXNjcmlwdGlvbiA9IGdldEVmZm9ydFZhbHVlRGVzY3JpcHRpb24oZWZmZWN0aXZlVmFsdWUpXG4gIHJldHVybiB7XG4gICAgbWVzc2FnZTogYEN1cnJlbnQgZWZmb3J0IGxldmVsOiAke2VmZmVjdGl2ZVZhbHVlfSAoJHtkZXNjcmlwdGlvbn0pYCxcbiAgfVxufVxuXG5mdW5jdGlvbiB1bnNldEVmZm9ydExldmVsKCk6IEVmZm9ydENvbW1hbmRSZXN1bHQge1xuICBjb25zdCByZXN1bHQgPSB1cGRhdGVTZXR0aW5nc0ZvclNvdXJjZSgndXNlclNldHRpbmdzJywge1xuICAgIGVmZm9ydExldmVsOiB1bmRlZmluZWQsXG4gIH0pXG4gIGlmIChyZXN1bHQuZXJyb3IpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbWVzc2FnZTogYEZhaWxlZCB0byBzZXQgZWZmb3J0IGxldmVsOiAke3Jlc3VsdC5lcnJvci5tZXNzYWdlfWAsXG4gICAgfVxuICB9XG4gIGxvZ0V2ZW50KCd0ZW5ndV9lZmZvcnRfY29tbWFuZCcsIHtcbiAgICBlZmZvcnQ6XG4gICAgICAnYXV0bycgYXMgQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyxcbiAgfSlcbiAgLy8gZW52PWF1dG8vdW5zZXQgKG51bGwpIG1hdGNoZXMgd2hhdCAvZWZmb3J0IGF1dG8gYXNrcyBmb3IsIHNvIG9ubHkgd2FyblxuICAvLyB3aGVuIGVudiBpcyBwaW5uaW5nIGEgc3BlY2lmaWMgbGV2ZWwgdGhhdCB3aWxsIGtlZXAgb3ZlcnJpZGluZy5cbiAgY29uc3QgZW52T3ZlcnJpZGUgPSBnZXRFZmZvcnRFbnZPdmVycmlkZSgpXG4gIGlmIChlbnZPdmVycmlkZSAhPT0gdW5kZWZpbmVkICYmIGVudk92ZXJyaWRlICE9PSBudWxsKSB7XG4gICAgY29uc3QgZW52UmF3ID0gcHJvY2Vzcy5lbnYuQ0xBVURFX0NPREVfRUZGT1JUX0xFVkVMXG4gICAgcmV0dXJuIHtcbiAgICAgIG1lc3NhZ2U6IGBDbGVhcmVkIGVmZm9ydCBmcm9tIHNldHRpbmdzLCBidXQgQ0xBVURFX0NPREVfRUZGT1JUX0xFVkVMPSR7ZW52UmF3fSBzdGlsbCBjb250cm9scyB0aGlzIHNlc3Npb25gLFxuICAgICAgZWZmb3J0VXBkYXRlOiB7IHZhbHVlOiB1bmRlZmluZWQgfSxcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHtcbiAgICBtZXNzYWdlOiAnRWZmb3J0IGxldmVsIHNldCB0byBhdXRvJyxcbiAgICBlZmZvcnRVcGRhdGU6IHsgdmFsdWU6IHVuZGVmaW5lZCB9LFxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBleGVjdXRlRWZmb3J0KGFyZ3M6IHN0cmluZyk6IEVmZm9ydENvbW1hbmRSZXN1bHQge1xuICBjb25zdCBub3JtYWxpemVkID0gYXJncy50b0xvd2VyQ2FzZSgpXG4gIGlmIChub3JtYWxpemVkID09PSAnYXV0bycgfHwgbm9ybWFsaXplZCA9PT0gJ3Vuc2V0Jykge1xuICAgIHJldHVybiB1bnNldEVmZm9ydExldmVsKClcbiAgfVxuXG4gIGlmICghaXNFZmZvcnRMZXZlbChub3JtYWxpemVkKSkge1xuICAgIHJldHVybiB7XG4gICAgICBtZXNzYWdlOiBgSW52YWxpZCBhcmd1bWVudDogJHthcmdzfS4gVmFsaWQgb3B0aW9ucyBhcmU6IGxvdywgbWVkaXVtLCBoaWdoLCBtYXgsIGF1dG9gLFxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBzZXRFZmZvcnRWYWx1ZShub3JtYWxpemVkKVxufVxuXG5mdW5jdGlvbiBTaG93Q3VycmVudEVmZm9ydCh7XG4gIG9uRG9uZSxcbn06IHtcbiAgb25Eb25lOiAocmVzdWx0OiBzdHJpbmcpID0+IHZvaWRcbn0pOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBlZmZvcnRWYWx1ZSA9IHVzZUFwcFN0YXRlKHMgPT4gcy5lZmZvcnRWYWx1ZSlcbiAgY29uc3QgbW9kZWwgPSB1c2VNYWluTG9vcE1vZGVsKClcbiAgY29uc3QgeyBtZXNzYWdlIH0gPSBzaG93Q3VycmVudEVmZm9ydChlZmZvcnRWYWx1ZSwgbW9kZWwpXG4gIG9uRG9uZShtZXNzYWdlKVxuICByZXR1cm4gbnVsbFxufVxuXG5mdW5jdGlvbiBBcHBseUVmZm9ydEFuZENsb3NlKHtcbiAgcmVzdWx0LFxuICBvbkRvbmUsXG59OiB7XG4gIHJlc3VsdDogRWZmb3J0Q29tbWFuZFJlc3VsdFxuICBvbkRvbmU6IChyZXN1bHQ6IHN0cmluZykgPT4gdm9pZFxufSk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IHNldEFwcFN0YXRlID0gdXNlU2V0QXBwU3RhdGUoKVxuICBjb25zdCB7IGVmZm9ydFVwZGF0ZSwgbWVzc2FnZSB9ID0gcmVzdWx0XG4gIFJlYWN0LnVzZUVmZmVjdCgoKSA9PiB7XG4gICAgaWYgKGVmZm9ydFVwZGF0ZSkge1xuICAgICAgc2V0QXBwU3RhdGUocHJldiA9PiAoe1xuICAgICAgICAuLi5wcmV2LFxuICAgICAgICBlZmZvcnRWYWx1ZTogZWZmb3J0VXBkYXRlLnZhbHVlLFxuICAgICAgfSkpXG4gICAgfVxuICAgIG9uRG9uZShtZXNzYWdlKVxuICB9LCBbc2V0QXBwU3RhdGUsIGVmZm9ydFVwZGF0ZSwgbWVzc2FnZSwgb25Eb25lXSlcbiAgcmV0dXJuIG51bGxcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNhbGwoXG4gIG9uRG9uZTogTG9jYWxKU1hDb21tYW5kT25Eb25lLFxuICBfY29udGV4dDogdW5rbm93bixcbiAgYXJncz86IHN0cmluZyxcbik6IFByb21pc2U8UmVhY3QuUmVhY3ROb2RlPiB7XG4gIGFyZ3MgPSBhcmdzPy50cmltKCkgfHwgJydcblxuICBpZiAoQ09NTU9OX0hFTFBfQVJHUy5pbmNsdWRlcyhhcmdzKSkge1xuICAgIG9uRG9uZShcbiAgICAgICdVc2FnZTogL2VmZm9ydCBbbG93fG1lZGl1bXxoaWdofG1heHxhdXRvXVxcblxcbkVmZm9ydCBsZXZlbHM6XFxuLSBsb3c6IFF1aWNrLCBzdHJhaWdodGZvcndhcmQgaW1wbGVtZW50YXRpb25cXG4tIG1lZGl1bTogQmFsYW5jZWQgYXBwcm9hY2ggd2l0aCBzdGFuZGFyZCB0ZXN0aW5nXFxuLSBoaWdoOiBDb21wcmVoZW5zaXZlIGltcGxlbWVudGF0aW9uIHdpdGggZXh0ZW5zaXZlIHRlc3RpbmdcXG4tIG1heDogTWF4aW11bSBjYXBhYmlsaXR5IHdpdGggZGVlcGVzdCByZWFzb25pbmcgKE9wdXMgNC42IG9ubHkpXFxuLSBhdXRvOiBVc2UgdGhlIGRlZmF1bHQgZWZmb3J0IGxldmVsIGZvciB5b3VyIG1vZGVsJyxcbiAgICApXG4gICAgcmV0dXJuXG4gIH1cblxuICBpZiAoIWFyZ3MgfHwgYXJncyA9PT0gJ2N1cnJlbnQnIHx8IGFyZ3MgPT09ICdzdGF0dXMnKSB7XG4gICAgcmV0dXJuIDxTaG93Q3VycmVudEVmZm9ydCBvbkRvbmU9e29uRG9uZX0gLz5cbiAgfVxuXG4gIGNvbnN0IHJlc3VsdCA9IGV4ZWN1dGVFZmZvcnQoYXJncylcbiAgcmV0dXJuIDxBcHBseUVmZm9ydEFuZENsb3NlIHJlc3VsdD17cmVzdWx0fSBvbkRvbmU9e29uRG9uZX0gLz5cbn1cbiJdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sS0FBS0EsS0FBSyxNQUFNLE9BQU87QUFDOUIsU0FBU0MsZ0JBQWdCLFFBQVEsaUNBQWlDO0FBQ2xFLFNBQ0UsS0FBS0MsMERBQTBELEVBQy9EQyxRQUFRLFFBQ0gsbUNBQW1DO0FBQzFDLFNBQVNDLFdBQVcs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 \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInVzZU1haW5Mb29wTW9kZWwiLCJBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTIiwibG9nRXZlbnQiLCJ1c2VBcHBTdGF0ZSIsInVzZVNldEFwcFN0YXRlIiwiTG9jYWxKU1hDb21tYW5kT25Eb25lIiwiRWZmb3J0VmFsdWUiLCJnZXREaXNwbGF5ZWRFZmZvcnRMZXZlbCIsImdldEVmZm9ydEVudk92ZXJyaWRlIiwiZ2V0RWZmb3J0VmFsdWVEZXNjcmlwdGlvbiIsImlzRWZmb3J0TGV2ZWwiLCJ0b1BlcnNpc3RhYmxlRWZmb3J0IiwidXBkYXRlU2V0dGluZ3NGb3JTb3VyY2UiLCJDT01NT05fSEVMUF9BUkdTIiwiRWZmb3J0Q29tbWFuZFJlc3VsdCIsIm1lc3NhZ2UiLCJlZmZvcnRVcGRhdGUiLCJ2YWx1ZSIsInNldEVmZm9ydFZhbHVlIiwiZWZmb3J0VmFsdWUiLCJwZXJzaXN0YWJsZSIsInVuZGVmaW5lZCIsInJlc3VsdCIsImVmZm9ydExldmVsIiwiZXJyb3IiLCJlZmZvcnQiLCJlbnZPdmVycmlkZSIsImVudlJhdyIsInByb2Nlc3MiLCJlbnYiLCJDTEFVREVfQ09ERV9FRkZPUlRfTEVWRUwiLCJkZXNjcmlwdGlvbiIsInN1ZmZpeCIsInNob3dDdXJyZW50RWZmb3J0IiwiYXBwU3RhdGVFZmZvcnQiLCJtb2RlbCIsImVmZmVjdGl2ZVZhbHVlIiwibGV2ZWwiLCJ1bnNldEVmZm9ydExldmVsIiwiZXhlY3V0ZUVmZm9ydCIsImFyZ3MiLCJub3JtYWxpemVkIiwidG9Mb3dlckNhc2UiLCJTaG93Q3VycmVudEVmZm9ydCIsInQwIiwib25Eb25lIiwiX3RlbXAiLCJzIiwiQXBwbHlFZmZvcnRBbmRDbG9zZSIsIiQiLCJfYyIsInNldEFwcFN0YXRlIiwidDEiLCJ0MiIsInByZXYiLCJ1c2VFZmZlY3QiLCJjYWxsIiwiX2NvbnRleHQiLCJQcm9taXNlIiwiUmVhY3ROb2RlIiwidHJpbSIsImluY2x1ZGVzIl0sInNvdXJjZXMiOlsiZWZmb3J0LnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IHVzZU1haW5Mb29wTW9kZWwgfSBmcm9tICcuLi8uLi9ob29rcy91c2VNYWluTG9vcE1vZGVsLmpzJ1xuaW1wb3J0IHtcbiAgdHlwZSBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICBsb2dFdmVudCxcbn0gZnJvbSAnLi4vLi4vc2VydmljZXMvYW5hbHl0aWNzL2luZGV4LmpzJ1xuaW1wb3J0IHsgdXNlQXBwU3RhdGUsIHVzZVNldEFwcFN0YXRlIH0gZnJvbSAnLi4vLi4vc3RhdGUvQXBwU3RhdGUuanMnXG5pbXBvcnQgdHlwZSB7IExvY2FsSlNYQ29tbWFuZE9uRG9uZSB9IGZyb20gJy4uLy4uL3R5cGVzL2NvbW1hbmQuanMnXG5pbXBvcnQge1xuICB0eXBlIEVmZm9ydFZhbHVlLFxuICBnZXREaXNwbGF5ZWRFZmZvcnRMZXZlbCxcbiAgZ2V0RWZmb3J0RW52T3ZlcnJpZGUsXG4gIGdldEVmZm9ydFZhbHVlRGVzY3JpcHRpb24sXG4gIGlzRWZmb3J0TGV2ZWwsXG4gIHRvUGVyc2lzdGFibGVFZmZvcnQsXG59IGZyb20gJy4uLy4uL3V0aWxzL2VmZm9ydC5qcydcbmltcG9ydCB7IHVwZGF0ZVNldHRpbmdzRm9yU291cmNlIH0gZnJvbSAnLi4vLi4vdXRpbHMvc2V0dGluZ3Mvc2V0dGluZ3MuanMnXG5cbmNvbnN0IENPTU1PTl9IRUxQX0FSR1MgPSBbJ2hlbHAnLCAnLWgnLCAnLS1oZWxwJ11cblxudHlwZSBFZmZvcnRDb21tYW5kUmVzdWx0ID0ge1xuICBtZXNzYWdlOiBzdHJpbmdcbiAgZWZmb3J0VXBkYXRlPzogeyB2YWx1ZTogRWZmb3J0VmFsdWUgfCB1bmRlZmluZWQgfVxufVxuXG5mdW5jdGlvbiBzZXRFZmZvcnRWYWx1ZShlZmZvcnRWYWx1ZTogRWZmb3J0VmFsdWUpOiBFZmZvcnRDb21tYW5kUmVzdWx0IHtcbiAgY29uc3QgcGVyc2lzdGFibGUgPSB0b1BlcnNpc3RhYmxlRWZmb3J0KGVmZm9ydFZhbHVlKVxuICBpZiAocGVyc2lzdGFibGUgIT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IHJlc3VsdCA9IHVwZGF0ZVNldHRpbmdzRm9yU291cmNlKCd1c2VyU2V0dGluZ3MnLCB7XG4gICAgICBlZmZvcnRMZXZlbDogcGVyc2lzdGFibGUsXG4gICAgfSlcbiAgICBpZiAocmVzdWx0LmVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBtZXNzYWdlOiBgRmFpbGVkIHRvIHNldCBlZmZvcnQgbGV2ZWw6ICR7cmVzdWx0LmVycm9yLm1lc3NhZ2V9YCxcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgbG9nRXZlbnQoJ3Rlbmd1X2VmZm9ydF9jb21tYW5kJywge1xuICAgIGVmZm9ydDpcbiAgICAgIGVmZm9ydFZhbHVlIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gIH0pXG5cbiAgLy8gRW52IHZhciB3aW5zIGF0IHJlc29sdmVBcHBsaWVkRWZmb3J0IHRpbWUuIE9ubHkgZmxhZyBpdCB3aGVuIGl0IGFjdHVhbGx5XG4gIC8vIGNvbmZsaWN0cyDigJQgaWYgZW52IG1hdGNoZXMgd2hhdCB0aGUgdXNlciBqdXN0IGFza2VkIGZvciwgdGhlIG91dGNvbWUgaXNcbiAgLy8gdGhlIHNhbWUsIHNvIFwiU2V0IGVmZm9ydCB0byBYXCIgaXMgdHJ1ZSBhbmQgdGhlIG5vdGUgaXMgbm9pc2UuXG4gIGNvbnN0IGVudk92ZXJyaWRlID0gZ2V0RWZmb3J0RW52T3ZlcnJpZGUoKVxuICBpZiAoZW52T3ZlcnJpZGUgIT09IHVuZGVmaW5lZCAmJiBlbnZPdmVycmlkZSAhPT0gZWZmb3J0VmFsdWUpIHtcbiAgICBjb25zdCBlbnZSYXcgPSBwcm9jZXNzLmVudi5DTEFVREVfQ09ERV9FRkZPUlRfTEVWRUxcbiAgICBpZiAocGVyc2lzdGFibGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbWVzc2FnZTogYE5vdCBhcHBsaWVkOiBDTEFVREVfQ09ERV9FRkZPUlRfTEVWRUw9JHtlbnZSYXd9IG92ZXJyaWRlcyBlZmZvcnQgdGhpcyBzZXNzaW9uLCBhbmQgJHtlZmZvcnRWYWx1ZX0gaXMgc2Vzc2lvbi1vbmx5IChub3RoaW5nIHNhdmVkKWAsXG4gICAgICAgIGVmZm9ydFVwZGF0ZTogeyB2YWx1ZTogZWZmb3J0VmFsdWUgfSxcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIG1lc3NhZ2U6IGBDTEFVREVfQ09ERV9FRkZPUlRfTEVWRUw9JHtlbnZSYXd9IG92ZXJyaWRlcyB0aGlzIHNlc3Npb24g4oCUIGNsZWFyIGl0IGFuZCAke2VmZm9ydFZhbHVlfSB0YWtlcyBvdmVyYCxcbiAgICAgIGVmZm9ydFVwZGF0ZTogeyB2YWx1ZTogZWZmb3J0VmFsdWUgfSxcbiAgICB9XG4gIH1cblxuICBjb25zdCBkZXNjcmlwdGlvbiA9IGdldEVmZm9ydFZhbHVlRGVzY3JpcHRpb24oZWZmb3J0VmFsdWUpXG4gIGNvbnN0IHN1ZmZpeCA9IHBlcnNpc3RhYmxlICE9PSB1bmRlZmluZWQgPyAnJyA6ICcgKHRoaXMgc2Vzc2lvbiBvbmx5KSdcbiAgcmV0dXJuIHtcbiAgICBtZXNzYWdlOiBgU2V0IGVmZm9ydCBsZXZlbCB0byAke2VmZm9ydFZhbHVlfSR7c3VmZml4fTogJHtkZXNjcmlwdGlvbn1gLFxuICAgIGVmZm9ydFVwZGF0ZTogeyB2YWx1ZTogZWZmb3J0VmFsdWUgfSxcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gc2hvd0N1cnJlbnRFZmZvcnQoXG4gIGFwcFN0YXRlRWZmb3J0OiBFZmZvcnRWYWx1ZSB8IHVuZGVmaW5lZCxcbiAgbW9kZWw6IHN0cmluZyxcbik6IEVmZm9ydENvbW1hbmRSZXN1bHQge1xuICBjb25zdCBlbnZPdmVycmlkZSA9IGdldEVmZm9ydEVudk92ZXJyaWRlKClcbiAgY29uc3QgZWZmZWN0aXZlVmFsdWUgPVxuICAgIGVudk92ZXJyaWRlID09PSBudWxsID8gdW5kZWZpbmVkIDogKGVudk92ZXJyaWRlID8/IGFwcFN0YXRlRWZmb3J0KVxuICBpZiAoZWZmZWN0aXZlVmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IGxldmVsID0gZ2V0RGlzcGxheWVkRWZmb3J0TGV2ZWwobW9kZWwsIGFwcFN0YXRlRWZmb3J0KVxuICAgIHJldHVybiB7IG1lc3NhZ2U6IGBFZmZvcnQgbGV2ZWw6IGF1dG8gKGN1cnJlbnRseSAke2xldmVsfSlgIH1cbiAgfVxuICBjb25zdCBkZXNjcmlwdGlvbiA9IGdldEVmZm9ydFZhbHVlRGVzY3JpcHRpb24oZWZmZWN0aXZlVmFsdWUpXG4gIHJldHVybiB7XG4gICAgbWVzc2FnZTogYEN1cnJlbnQgZWZmb3J0IGxldmVsOiAke2VmZmVjdGl2ZVZhbHVlfSAoJHtkZXNjcmlwdGlvbn0pYCxcbiAgfVxufVxuXG5mdW5jdGlvbiB1bnNldEVmZm9ydExldmVsKCk6IEVmZm9ydENvbW1hbmRSZXN1bHQge1xuICBjb25zdCByZXN1bHQgPSB1cGRhdGVTZXR0aW5nc0ZvclNvdXJjZSgndXNlclNldHRpbmdzJywge1xuICAgIGVmZm9ydExldmVsOiB1bmRlZmluZWQsXG4gIH0pXG4gIGlmIChyZXN1bHQuZXJyb3IpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbWVzc2FnZTogYEZhaWxlZCB0byBzZXQgZWZmb3J0IGxldmVsOiAke3Jlc3VsdC5lcnJvci5tZXNzYWdlfWAsXG4gICAgfVxuICB9XG4gIGxvZ0V2ZW50KCd0ZW5ndV9lZmZvcnRfY29tbWFuZCcsIHtcbiAgICBlZmZvcnQ6XG4gICAgICAnYXV0bycgYXMgQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyxcbiAgfSlcbiAgLy8gZW52PWF1dG8vdW5zZXQgKG51bGwpIG1hdGNoZXMgd2hhdCAvZWZmb3J0IGF1dG8gYXNrcyBmb3IsIHNvIG9ubHkgd2FyblxuICAvLyB3aGVuIGVudiBpcyBwaW5uaW5nIGEgc3BlY2lmaWMgbGV2ZWwgdGhhdCB3aWxsIGtlZXAgb3ZlcnJpZGluZy5cbiAgY29uc3QgZW52T3ZlcnJpZGUgPSBnZXRFZmZvcnRFbnZPdmVycmlkZSgpXG4gIGlmIChlbnZPdmVycmlkZSAhPT0gdW5kZWZpbmVkICYmIGVudk92ZXJyaWRlICE9PSBudWxsKSB7XG4gICAgY29uc3QgZW52UmF3ID0gcHJvY2Vzcy5lbnYuQ0xBVURFX0NPREVfRUZGT1JUX0xFVkVMXG4gICAgcmV0dXJuIHtcbiAgICAgIG1lc3NhZ2U6IGBDbGVhcmVkIGVmZm9ydCBmcm9tIHNldHRpbmdzLCBidXQgQ0xBVURFX0NPREVfRUZGT1JUX0xFVkVMPSR7ZW52UmF3fSBzdGlsbCBjb250cm9scyB0aGlzIHNlc3Npb25gLFxuICAgICAgZWZmb3J0VXBkYXRlOiB7IHZhbHVlOiB1bmRlZmluZWQgfSxcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHtcbiAgICBtZXNzYWdlOiAnRWZmb3J0IGxldmVsIHNldCB0byBhdXRvJyxcbiAgICBlZmZvcnRVcGRhdGU6IHsgdmFsdWU6IHVuZGVmaW5lZCB9LFxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBleGVjdXRlRWZmb3J0KGFyZ3M6IHN0cmluZyk6IEVmZm9ydENvbW1hbmRSZXN1bHQge1xuICBjb25zdCBub3JtYWxpemVkID0gYXJncy50b0xvd2VyQ2FzZSgpXG4gIGlmIChub3JtYWxpemVkID09PSAnYXV0bycgfHwgbm9ybWFsaXplZCA9PT0gJ3Vuc2V0Jykge1xuICAgIHJldHVybiB1bnNldEVmZm9ydExldmVsKClcbiAgfVxuXG4gIGlmICghaXNFZmZvcnRMZXZlbChub3JtYWxpemVkKSkge1xuICAgIHJldHVybiB7XG4gICAgICBtZXNzYWdlOiBgSW52YWxpZCBhcmd1bWVudDogJHthcmdzfS4gVmFsaWQgb3B0aW9ucyBhcmU6IGxvdywgbWVkaXVtLCBoaWdoLCBtYXgsIGF1dG9gLFxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBzZXRFZmZvcnRWYWx1ZShub3JtYWxpemVkKVxufVxuXG5mdW5jdGlvbiBTaG93Q3VycmVudEVmZm9ydCh7XG4gIG9uRG9uZSxcbn06IHtcbiAgb25Eb25lOiAocmVzdWx0OiBzdHJpbmcpID0+IHZvaWRcbn0pOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBlZmZvcnRWYWx1ZSA9IHVzZUFwcFN0YXRlKHMgPT4gcy5lZmZvcnRWYWx1ZSlcbiAgY29uc3QgbW9kZWwgPSB1c2VNYWluTG9vcE1vZGVsKClcbiAgY29uc3QgeyBtZXNzYWdlIH0gPSBzaG93Q3VycmVudEVmZm9ydChlZmZvcnRWYWx1ZSwgbW9kZWwpXG4gIG9uRG9uZShtZXNzYWdlKVxuICByZXR1cm4gbnVsbFxufVxuXG5mdW5jdGlvbiBBcHBseUVmZm9ydEFuZENsb3NlKHtcbiAgcmVzdWx0LFxuICBvbkRvbmUsXG59OiB7XG4gIHJlc3VsdDogRWZmb3J0Q29tbWFuZFJlc3VsdFxuICBvbkRvbmU6IChyZXN1bHQ6IHN0cmluZykgPT4gdm9pZFxufSk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IHNldEFwcFN0YXRlID0gdXNlU2V0QXBwU3RhdGUoKVxuICBjb25zdCB7IGVmZm9ydFVwZGF0ZSwgbWVzc2FnZSB9ID0gcmVzdWx0XG4gIFJlYWN0LnVzZUVmZmVjdCgoKSA9PiB7XG4gICAgaWYgKGVmZm9ydFVwZGF0ZSkge1xuICAgICAgc2V0QXBwU3RhdGUocHJldiA9PiAoe1xuICAgICAgICAuLi5wcmV2LFxuICAgICAgICBlZmZvcnRWYWx1ZTogZWZmb3J0VXBkYXRlLnZhbHVlLFxuICAgICAgfSkpXG4gICAgfVxuICAgIG9uRG9uZShtZXNzYWdlKVxuICB9LCBbc2V0QXBwU3RhdGUsIGVmZm9ydFVwZGF0ZSwgbWVzc2FnZSwgb25Eb25lXSlcbiAgcmV0dXJuIG51bGxcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNhbGwoXG4gIG9uRG9uZTogTG9jYWxKU1hDb21tYW5kT25Eb25lLFxuICBfY29udGV4dDogdW5rbm93bixcbiAgYXJncz86IHN0cmluZyxcbik6IFByb21pc2U8UmVhY3QuUmVhY3ROb2RlPiB7XG4gIGFyZ3MgPSBhcmdzPy50cmltKCkgfHwgJydcblxuICBpZiAoQ09NTU9OX0hFTFBfQVJHUy5pbmNsdWRlcyhhcmdzKSkge1xuICAgIG9uRG9uZShcbiAgICAgICdVc2FnZTogL2VmZm9ydCBbbG93fG1lZGl1bXxoaWdofG1heHxhdXRvXVxcblxcbkVmZm9ydCBsZXZlbHM6XFxuLSBsb3c6IFF1aWNrLCBzdHJhaWdodGZvcndhcmQgaW1wbGVtZW50YXRpb25cXG4tIG1lZGl1bTogQmFsYW5jZWQgYXBwcm9hY2ggd2l0aCBzdGFuZGFyZCB0ZXN0aW5nXFxuLSBoaWdoOiBDb21wcmVoZW5zaXZlIGltcGxlbWVudGF0aW9uIHdpdGggZXh0ZW5zaXZlIHRlc3RpbmdcXG4tIG1heDogTWF4aW11bSBjYXBhYmlsaXR5IHdpdGggZGVlcGVzdCByZWFzb25pbmcgKE9wdXMgNC42IG9ubHkpXFxuLSBhdXRvOiBVc2UgdGhlIGRlZmF1bHQgZWZmb3J0IGxldmVsIGZvciB5b3VyIG1vZGVsJyxcbiAgICApXG4gICAgcmV0dXJuXG4gIH1cblxuICBpZiAoIWFyZ3MgfHwgYXJncyA9PT0gJ2N1cnJlbnQnIHx8IGFyZ3MgPT09ICdzdGF0dXMnKSB7XG4gICAgcmV0dXJuIDxTaG93Q3VycmVudEVmZm9ydCBvbkRvbmU9e29uRG9uZX0gLz5cbiAgfVxuXG4gIGNvbnN0IHJlc3VsdCA9IGV4ZWN1dGVFZmZvcnQoYXJncylcbiAgcmV0dXJuIDxBcHBseUVmZm9ydEFuZENsb3NlIHJlc3VsdD17cmVzdWx0fSBvbkRvbmU9e29uRG9uZX0gLz5cbn1cbiJdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sS0FBS0EsS0FBSyxNQUFNLE9BQU87QUFDOUIsU0FBU0MsZ0JBQWdCLFFBQVEsaUNBQWlDO0FBQ2xFLFNBQ0UsS0FBS0MsMERBQTBELEVBQy9EQyxRQUFRLFFBQ0gsbUNBQW1DO0FBQzFDLFNBQVNDLFdBQVcs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 diff --git a/src/commands/model/model.tsx b/src/commands/model/model.tsx index 7f6e2127..08e0d6c6 100644 --- a/src/commands/model/model.tsx +++ b/src/commands/model/model.tsx @@ -12,7 +12,7 @@ import { isBilledAsExtraUsage } from '../../utils/extraUsage.js'; import { clearFastModeCooldown, isFastModeAvailable, isFastModeEnabled, isFastModeSupportedByModel } from '../../utils/fastMode.js'; import { MODEL_ALIASES } from '../../utils/model/aliases.js'; import { checkOpus1mAccess, checkSonnet1mAccess } from '../../utils/model/check1mAccess.js'; -import { getDefaultMainLoopModelSetting, isOpus1mMergeEnabled, renderDefaultModelSetting } from '../../utils/model/model.js'; +import { getDefaultMainLoopModelSetting, getDefaultSonnetModel, isOpus1mMergeEnabled, renderDefaultModelSetting } from '../../utils/model/model.js'; import { isModelAllowed } from '../../utils/model/modelAllowlist.js'; import { validateModel } from '../../utils/model/validateModel.js'; function ModelPickerWrapper(t0) { @@ -150,13 +150,13 @@ function SetModelAndClose({ // @[MODEL LAUNCH]: Update check for 1M access. if (model && isOpus1mUnavailable(model)) { - onDone(`Opus 4.7 with 1M context is not available for your account. Learn more: https://code.claude.com/docs/en/model-config#extended-context-with-1m`, { + onDone(`Opus with 1M context is not available for your account. Learn more: https://code.claude.com/docs/en/model-config#extended-context-with-1m`, { display: 'system' }); return; } if (model && isSonnet1mUnavailable(model)) { - onDone(`Sonnet 4.6 with 1M context is not available for your account. Learn more: https://code.claude.com/docs/en/model-config#extended-context-with-1m`, { + onDone(`Sonnet with 1M context is not available for your account. Learn more: https://code.claude.com/docs/en/model-config#extended-context-with-1m`, { display: 'system' }); return; @@ -239,8 +239,16 @@ function isOpus1mUnavailable(model: string): boolean { } function isSonnet1mUnavailable(model: string): boolean { const m = model.toLowerCase(); - // Warn about Sonnet and Sonnet 4.6, but not Sonnet 4.5 since that had - // a different access criteria. + if (m.includes('sonnet-5')) { + return false; + } + + // Sonnet 5 has a native 1M window, so sonnet[1m] is only gated when the + // alias resolves to an older Sonnet model. + if (m.includes('sonnet[1m]') && getDefaultSonnetModel().toLowerCase().includes('sonnet-5')) { + return false; + } + return !checkSonnet1mAccess() && (m.includes('sonnet[1m]') || m.includes('sonnet-4-6[1m]')); } function ShowModelAndClose(t0) { @@ -294,4 +302,4 @@ function renderModelLabel(model: string | null): string { const rendered = renderDefaultModelSetting(model ?? getDefaultMainLoopModelSetting()); return model === null ? `${rendered} (default)` : rendered; } -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjaGFsayIsIlJlYWN0IiwiQ29tbWFuZFJlc3VsdERpc3BsYXkiLCJNb2RlbFBpY2tlciIsIkNPTU1PTl9IRUxQX0FSR1MiLCJDT01NT05fSU5GT19BUkdTIiwiQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyIsImxvZ0V2ZW50IiwidXNlQXBwU3RhdGUiLCJ1c2VTZXRBcHBTdGF0ZSIsIkxvY2FsSlNYQ29tbWFuZENhbGwiLCJFZmZvcnRMZXZlbCIsImlzQmlsbGVkQXNFeHRyYVVzYWdlIiwiY2xlYXJGYXN0TW9kZUNvb2xkb3duIiwiaXNGYXN0TW9kZUF2YWlsYWJsZSIsImlzRmFzdE1vZGVFbmFibGVkIiwiaXNGYXN0TW9kZVN1cHBvcnRlZEJ5TW9kZWwiLCJNT0RFTF9BTElBU0VTIiwiY2hlY2tPcHVzMW1BY2Nlc3MiLCJjaGVja1Nvbm5ldDFtQWNjZXNzIiwiZ2V0RGVmYXVsdE1haW5Mb29wTW9kZWxTZXR0aW5nIiwiaXNPcHVzMW1NZXJnZUVuYWJsZWQiLCJyZW5kZXJEZWZhdWx0TW9kZWxTZXR0aW5nIiwiaXNNb2RlbEFsbG93ZWQiLCJ2YWxpZGF0ZU1vZGVsIiwiTW9kZWxQaWNrZXJXcmFwcGVyIiwidDAiLCIkIiwiX2MiLCJvbkRvbmUiLCJtYWluTG9vcE1vZGVsIiwiX3RlbXAiLCJtYWluTG9vcE1vZGVsRm9yU2Vzc2lvbiIsIl90ZW1wMiIsImlzRmFzdE1vZGUiLCJfdGVtcDMiLCJzZXRBcHBTdGF0ZSIsInQxIiwiaGFuZGxlQ2FuY2VsIiwiYWN0aW9uIiwiZGlzcGxheU1vZGVsIiwicmVuZGVyTW9kZWxMYWJlbCIsImJvbGQiLCJkaXNwbGF5IiwidDIiLCJoYW5kbGVTZWxlY3QiLCJtb2RlbCIsImVmZm9ydCIsImZyb21fbW9kZWwiLCJ0b19tb2RlbCIsInByZXYiLCJtZXNzYWdlIiwidW5kZWZpbmVkIiwid2FzRmFzdE1vZGVUb2dnbGVkT24iLCJfdGVtcDQiLCJ0MyIsInQ0IiwicHJldl8wIiwiZmFzdE1vZGUiLCJzXzEiLCJzIiwic18wIiwiU2V0TW9kZWxBbmRDbG9zZSIsImFyZ3MiLCJyZXN1bHQiLCJvcHRpb25zIiwiUmVhY3ROb2RlIiwidXNlRWZmZWN0IiwiaGFuZGxlTW9kZWxDaGFuZ2UiLCJQcm9taXNlIiwiaXNPcHVzMW1VbmF2YWlsYWJsZSIsImlzU29ubmV0MW1VbmF2YWlsYWJsZSIsInNldE1vZGVsIiwiaXNLbm93bkFsaWFzIiwidmFsaWQiLCJlcnJvciIsIkVycm9yIiwibW9kZWxWYWx1ZSIsImluY2x1ZGVzIiwidG9Mb3dlckNhc2UiLCJ0cmltIiwibSIsIlNob3dNb2RlbEFuZENsb3NlIiwiX3RlbXA3IiwiX3RlbXA4IiwiZWZmb3J0VmFsdWUiLCJfdGVtcDkiLCJlZmZvcnRJbmZvIiwiY2FsbCIsIl9jb250ZXh0IiwicmVuZGVyZWQiXSwic291cmNlcyI6WyJtb2RlbC50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNoYWxrIGZyb20gJ2NoYWxrJ1xuaW1wb3J0ICogYXMgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgdHlwZSB7IENvbW1hbmRSZXN1bHREaXNwbGF5IH0gZnJvbSAnLi4vLi4vY29tbWFuZHMuanMnXG5pbXBvcnQgeyBNb2RlbFBpY2tlciB9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvTW9kZWxQaWNrZXIuanMnXG5pbXBvcnQgeyBDT01NT05fSEVMUF9BUkdTLCBDT01NT05fSU5GT19BUkdTIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzL3htbC5qcydcbmltcG9ydCB7XG4gIHR5cGUgQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyxcbiAgbG9nRXZlbnQsXG59IGZyb20gJy4uLy4uL3NlcnZpY2VzL2FuYWx5dGljcy9pbmRleC5qcydcbmltcG9ydCB7IHVzZUFwcFN0YXRlLCB1c2VTZXRBcHBTdGF0ZSB9IGZyb20gJy4uLy4uL3N0YXRlL0FwcFN0YXRlLmpzJ1xuaW1wb3J0IHR5cGUgeyBMb2NhbEpTWENvbW1hbmRDYWxsIH0gZnJvbSAnLi4vLi4vdHlwZXMvY29tbWFuZC5qcydcbmltcG9ydCB0eXBlIHsgRWZmb3J0TGV2ZWwgfSBmcm9tICcuLi8uLi91dGlscy9lZmZvcnQuanMnXG5pbXBvcnQgeyBpc0JpbGxlZEFzRXh0cmFVc2FnZSB9IGZyb20gJy4uLy4uL3V0aWxzL2V4dHJhVXNhZ2UuanMnXG5pbXBvcnQge1xuICBjbGVhckZhc3RNb2RlQ29vbGRvd24sXG4gIGlzRmFzdE1vZGVBdmFpbGFibGUsXG4gIGlzRmFzdE1vZGVFbmFibGVkLFxuICBpc0Zhc3RNb2RlU3VwcG9ydGVkQnlNb2RlbCxcbn0gZnJvbSAnLi4vLi4vdXRpbHMvZmFzdE1vZGUuanMnXG5pbXBvcnQgeyBNT0RFTF9BTElBU0VTIH0gZnJvbSAnLi4vLi4vdXRpbHMvbW9kZWwvYWxpYXNlcy5qcydcbmltcG9ydCB7XG4gIGNoZWNrT3B1czFtQWNjZXNzLFxuICBjaGVja1Nvbm5ldDFtQWNjZXNzLFxufSBmcm9tICcuLi8uLi91dGlscy9tb2RlbC9jaGVjazFtQWNjZXNzLmpzJ1xuaW1wb3J0IHtcbiAgZ2V0RGVmYXVsdE1haW5Mb29wTW9kZWxTZXR0aW5nLFxuICBpc09wdXMxbU1lcmdlRW5hYmxlZCxcbiAgcmVuZGVyRGVmYXVsdE1vZGVsU2V0dGluZyxcbn0gZnJvbSAnLi4vLi4vdXRpbHMvbW9kZWwvbW9kZWwuanMnXG5pbXBvcnQgeyBpc01vZGVsQWxsb3dlZCB9IGZyb20gJy4uLy4uL3V0aWxzL21vZGVsL21vZGVsQWxsb3dsaXN0LmpzJ1xuaW1wb3J0IHsgdmFsaWRhdGVNb2RlbCB9IGZyb20gJy4uLy4uL3V0aWxzL21vZGVsL3ZhbGlkYXRlTW9kZWwuanMnXG5cbmZ1bmN0aW9uIE1vZGVsUGlja2VyV3JhcHBlcih7XG4gIG9uRG9uZSxcbn06IHtcbiAgb25Eb25lOiAoXG4gICAgcmVzdWx0Pzogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7IGRpc3BsYXk/OiBDb21tYW5kUmVzdWx0RGlzcGxheSB9LFxuICApID0+IHZvaWRcbn0pOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBtYWluTG9vcE1vZGVsID0gdXNlQXBwU3RhdGUocyA9PiBzLm1haW5Mb29wTW9kZWwpXG4gIGNvbnN0IG1haW5Mb29wTW9kZWxGb3JTZXNzaW9uID0gdXNlQXBwU3RhdGUocyA9PiBzLm1haW5Mb29wTW9kZWxGb3JTZXNzaW9uKVxuICBjb25zdCBpc0Zhc3RNb2RlID0gdXNlQXBwU3RhdGUocyA9PiBzLmZhc3RNb2RlKVxuICBjb25zdCBzZXRBcHBTdGF0ZSA9IHVzZVNldEFwcFN0YXRlKClcblxuICBmdW5jdGlvbiBoYW5kbGVDYW5jZWwoKTogdm9pZCB7XG4gICAgbG9nRXZlbnQoJ3Rlbmd1X21vZGVsX2NvbW1hbmRfbWVudScsIHtcbiAgICAgIGFjdGlvbjpcbiAgICAgICAgJ2NhbmNlbCcgYXMgQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyxcbiAgICB9KVxuICAgIGNvbnN0IGRpc3BsYXlNb2RlbCA9IHJlbmRlck1vZGVsTGFiZWwobWFpbkxvb3BNb2RlbClcbiAgICBvbkRvbmUoYEtlcHQgbW9kZWwgYXMgJHtjaGFsay5ib2xkKGRpc3BsYXlNb2RlbCl9YCwge1xuICAgICAgZGlzcGxheTogJ3N5c3RlbScsXG4gICAgfSlcbiAgfVxuXG4gIGZ1bmN0aW9uIGhhbmRsZVNlbGVjdChcbiAgICBtb2RlbDogc3RyaW5nIHwgbnVsbCxcbiAgICBlZmZvcnQ6IEVmZm9ydExldmVsIHwgdW5kZWZpbmVkLFxuICApOiB2b2lkIHtcbiAgICBsb2dFdmVudCgndGVuZ3VfbW9kZWxfY29tbWFuZF9tZW51Jywge1xuICAgICAgYWN0aW9uOlxuICAgICAgICBtb2RlbCBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgICAgZnJvbV9tb2RlbDpcbiAgICAgICAgbWFpbkxvb3BNb2RlbCBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgICAgdG9fbW9kZWw6XG4gICAgICAgIG1vZGVsIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gICAgfSlcbiAgICBzZXRBcHBTdGF0ZShwcmV2ID0+ICh7XG4gICAgICAuLi5wcmV2LFxuICAgICAgbWFpbkxvb3BNb2RlbDogbW9kZWwsXG4gICAgICBtYWluTG9vcE1vZGVsRm9yU2Vzc2lvbjogbnVsbCxcbiAgICB9KSlcblxuICAgIGxldCBtZXNzYWdlID0gYFNldCBtb2RlbCB0byAke2NoYWxrLmJvbGQocmVuZGVyTW9kZWxMYWJlbChtb2RlbCkpfWBcbiAgICBpZiAoZWZmb3J0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIG1lc3NhZ2UgKz0gYCB3aXRoICR7Y2hhbGsuYm9sZChlZmZvcnQpfSBlZmZvcnRgXG4gICAgfVxuXG4gICAgLy8gVHVybiBvZmYgZmFzdCBtb2RlIGlmIHN3aXRjaGluZyB0byB1bnN1cHBvcnRlZCBtb2RlbFxuICAgIGxldCB3YXNGYXN0TW9kZVRvZ2dsZWRPbiA9IHVuZGVmaW5lZFxuICAgIGlmIChpc0Zhc3RNb2RlRW5hYmxlZCgpKSB7XG4gICAgICBjbGVhckZhc3RNb2RlQ29vbGRvd24oKVxuICAgICAgaWYgKCFpc0Zhc3RNb2RlU3VwcG9ydGVkQnlNb2RlbChtb2RlbCkgJiYgaXNGYXN0TW9kZSkge1xuICAgICAgICBzZXRBcHBTdGF0ZShwcmV2ID0+ICh7XG4gICAgICAgICAgLi4ucHJldixcbiAgICAgICAgICBmYXN0TW9kZTogZmFsc2UsXG4gICAgICAgIH0pKVxuICAgICAgICB3YXNGYXN0TW9kZVRvZ2dsZWRPbiA9IGZhbHNlXG4gICAgICAgIC8vIERvIG5vdCB1cGRhdGUgZmFzdCBtb2RlIGluIHNldHRpbmdzIHNpbmNlIHRoaXMgaXMgYW4gYXV0b21hdGljIGRvd25ncmFkZVxuICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgaXNGYXN0TW9kZVN1cHBvcnRlZEJ5TW9kZWwobW9kZWwpICYmXG4gICAgICAgIGlzRmFzdE1vZGVBdmFpbGFibGUoKSAmJlxuICAgICAgICBpc0Zhc3RNb2RlXG4gICAgICApIHtcbiAgICAgICAgbWVzc2FnZSArPSBgIMK3IEZhc3QgbW9kZSBPTmBcbiAgICAgICAgd2FzRmFzdE1vZGVUb2dnbGVkT24gPSB0cnVlXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgaXNCaWxsZWRBc0V4dHJhVXNhZ2UoXG4gICAgICAgIG1vZGVsLFxuICAgICAgICB3YXNGYXN0TW9kZVRvZ2dsZWRPbiA9PT0gdHJ1ZSxcbiAgICAgICAgaXNPcHVzMW1NZXJnZUVuYWJsZWQoKSxcbiAgICAgIClcbiAgICApIHtcbiAgICAgIG1lc3NhZ2UgKz0gYCDCtyBCaWxsZWQgYXMgZXh0cmEgdXNhZ2VgXG4gICAgfVxuXG4gICAgaWYgKHdhc0Zhc3RNb2RlVG9nZ2xlZE9uID09PSBmYWxzZSkge1xuICAgICAgLy8gRmFzdCBtb2RlIHdhcyB0b2dnbGVkIG9mZiwgc2hvdyBzdWZmaXggYWZ0ZXIgZXh0cmEgdXNhZ2UgYmlsbGluZ1xuICAgICAgbWVzc2FnZSArPSBgIMK3IEZhc3QgbW9kZSBPRkZgXG4gICAgfVxuXG4gICAgb25Eb25lKG1lc3NhZ2UpXG4gIH1cblxuICByZXR1cm4gKFxuICAgIDxNb2RlbFBpY2tlclxuICAgICAgaW5pdGlhbD17bWFpbkxvb3BNb2RlbH1cbiAgICAgIHNlc3Npb25Nb2RlbD17bWFpbkxvb3BNb2RlbEZvclNlc3Npb259XG4gICAgICBvblNlbGVjdD17aGFuZGxlU2VsZWN0fVxuICAgICAgb25DYW5jZWw9e2hhbmRsZUNhbmNlbH1cbiAgICAgIGlzU3RhbmRhbG9uZUNvbW1hbmRcbiAgICAgIHNob3dGYXN0TW9kZU5vdGljZT17XG4gICAgICAgIGlzRmFzdE1vZGVFbmFibGVkKCkgJiZcbiAgICAgICAgaXNGYXN0TW9kZSAmJlxuICAgICAgICBpc0Zhc3RNb2RlU3VwcG9ydGVkQnlNb2RlbChtYWluTG9vcE1vZGVsKSAmJlxuICAgICAgICBpc0Zhc3RNb2RlQXZhaWxhYmxlKClcbiAgICAgIH1cbiAgICAvPlxuICApXG59XG5cbmZ1bmN0aW9uIFNldE1vZGVsQW5kQ2xvc2Uoe1xuICBhcmdzLFxuICBvbkRvbmUsXG59OiB7XG4gIGFyZ3M6IHN0cmluZ1xuICBvbkRvbmU6IChcbiAgICByZXN1bHQ/OiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHsgZGlzcGxheT86IENvbW1hbmRSZXN1bHREaXNwbGF5IH0sXG4gICkgPT4gdm9pZFxufSk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IGlzRmFzdE1vZGUgPSB1c2VBcHBTdGF0ZShzID0+IHMuZmFzdE1vZGUpXG4gIGNvbnN0IHNldEFwcFN0YXRlID0gdXNlU2V0QXBwU3RhdGUoKVxuICBjb25zdCBtb2RlbCA9IGFyZ3MgPT09ICdkZWZhdWx0JyA/IG51bGwgOiBhcmdzXG5cbiAgUmVhY3QudXNlRWZmZWN0KCgpID0+IHtcbiAgICBhc3luYyBmdW5jdGlvbiBoYW5kbGVNb2RlbENoYW5nZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgIGlmIChtb2RlbCAmJiAhaXNNb2RlbEFsbG93ZWQobW9kZWwpKSB7XG4gICAgICAgIG9uRG9uZShcbiAgICAgICAgICBgTW9kZWwgJyR7bW9kZWx9JyBpcyBub3QgYXZhaWxhYmxlLiBZb3VyIG9yZ2FuaXphdGlvbiByZXN0cmljdHMgbW9kZWwgc2VsZWN0aW9uLmAsXG4gICAgICAgICAgeyBkaXNwbGF5OiAnc3lzdGVtJyB9LFxuICAgICAgICApXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICAvLyBAW01PREVMIExBVU5DSF06IFVwZGF0ZSBjaGVjayBmb3IgMU0gYWNjZXNzLlxuICAgICAgaWYgKG1vZGVsICYmIGlzT3B1czFtVW5hdmFpbGFibGUobW9kZWwpKSB7XG4gICAgICAgIG9uRG9uZShcbiAgICAgICAgICBgT3B1cyA0LjYgd2l0aCAxTSBjb250ZXh0IGlzIG5vdCBhdmFpbGFibGUgZm9yIHlvdXIgYWNjb3VudC4gTGVhcm4gbW9yZTogaHR0cHM6Ly9jb2RlLmNsYXVkZS5jb20vZG9jcy9lbi9tb2RlbC1jb25maWcjZXh0ZW5kZWQtY29udGV4dC13aXRoLTFtYCxcbiAgICAgICAgICB7IGRpc3BsYXk6ICdzeXN0ZW0nIH0sXG4gICAgICAgIClcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGlmIChtb2RlbCAmJiBpc1Nvbm5ldDFtVW5hdmFpbGFibGUobW9kZWwpKSB7XG4gICAgICAgIG9uRG9uZShcbiAgICAgICAgICBgU29ubmV0IDQuNiB3aXRoIDFNIGNvbnRleHQgaXMgbm90IGF2YWlsYWJsZSBmb3IgeW91ciBhY2NvdW50LiBMZWFybiBtb3JlOiBodHRwczovL2NvZGUuY2xhdWRlLmNvbS9kb2NzL2VuL21vZGVsLWNvbmZpZyNleHRlbmRlZC1jb250ZXh0LXdpdGgtMW1gLFxuICAgICAgICAgIHsgZGlzcGxheTogJ3N5c3RlbScgfSxcbiAgICAgICAgKVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgLy8gU2tpcCB2YWxpZGF0aW9uIGZvciBkZWZhdWx0IG1vZGVsXG4gICAgICBpZiAoIW1vZGVsKSB7XG4gICAgICAgIHNldE1vZGVsKG51bGwpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICAvLyBTa2lwIHZhbGlkYXRpb24gZm9yIGtub3duIGFsaWFzZXMgLSB0aGV5J3JlIHByZWRlZmluZWQgYW5kIHNob3VsZCB3b3JrXG4gICAgICBpZiAoaXNLbm93bkFsaWFzKG1vZGVsKSkge1xuICAgICAgICBzZXRNb2RlbChtb2RlbClcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIC8vIFZhbGlkYXRlIGFuZCBzZXQgY3VzdG9tIG1vZGVsXG4gICAgICB0cnkge1xuICAgICAgICAvLyBEb24ndCB1c2UgcGFyc2VVc2VyU3BlY2lmaWVkTW9kZWwgZm9yIG5vbi1hbGlhc2VzIHNpbmNlIGl0IGxvd2VyY2FzZXMgdGhlIGlucHV0XG4gICAgICAgIC8vIGFuZCBtb2RlbCBuYW1lcyBhcmUgY2FzZS1zZW5zaXRpdmVcbiAgICAgICAgY29uc3QgeyB2YWxpZCwgZXJyb3IgfSA9IGF3YWl0IHZhbGlkYXRlTW9kZWwobW9kZWwpXG5cbiAgICAgICAgaWYgKHZhbGlkKSB7XG4gICAgICAgICAgc2V0TW9kZWwobW9kZWwpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgb25Eb25lKGVycm9yIHx8IGBNb2RlbCAnJHttb2RlbH0nIG5vdCBmb3VuZGAsIHtcbiAgICAgICAgICAgIGRpc3BsYXk6ICdzeXN0ZW0nLFxuICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIG9uRG9uZShgRmFpbGVkIHRvIHZhbGlkYXRlIG1vZGVsOiAkeyhlcnJvciBhcyBFcnJvcikubWVzc2FnZX1gLCB7XG4gICAgICAgICAgZGlzcGxheTogJ3N5c3RlbScsXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gc2V0TW9kZWwobW9kZWxWYWx1ZTogc3RyaW5nIHwgbnVsbCk6IHZvaWQge1xuICAgICAgc2V0QXBwU3RhdGUocHJldiA9PiAoe1xuICAgICAgICAuLi5wcmV2LFxuICAgICAgICBtYWluTG9vcE1vZGVsOiBtb2RlbFZhbHVlLFxuICAgICAgICBtYWluTG9vcE1vZGVsRm9yU2Vzc2lvbjogbnVsbCxcbiAgICAgIH0pKVxuICAgICAgbGV0IG1lc3NhZ2UgPSBgU2V0IG1vZGVsIHRvICR7Y2hhbGsuYm9sZChyZW5kZXJNb2RlbExhYmVsKG1vZGVsVmFsdWUpKX1gXG5cbiAgICAgIGxldCB3YXNGYXN0TW9kZVRvZ2dsZWRPbiA9IHVuZGVmaW5lZFxuICAgICAgaWYgKGlzRmFzdE1vZGVFbmFibGVkKCkpIHtcbiAgICAgICAgY2xlYXJGYXN0TW9kZUNvb2xkb3duKClcbiAgICAgICAgaWYgKCFpc0Zhc3RNb2RlU3VwcG9ydGVkQnlNb2RlbChtb2RlbFZhbHVlKSAmJiBpc0Zhc3RNb2RlKSB7XG4gICAgICAgICAgc2V0QXBwU3RhdGUocHJldiA9PiAoe1xuICAgICAgICAgICAgLi4ucHJldixcbiAgICAgICAgICAgIGZhc3RNb2RlOiBmYWxzZSxcbiAgICAgICAgICB9KSlcbiAgICAgICAgICB3YXNGYXN0TW9kZVRvZ2dsZWRPbiA9IGZhbHNlXG4gICAgICAgICAgLy8gRG8gbm90IHVwZGF0ZSBmYXN0IG1vZGUgaW4gc2V0dGluZ3Mgc2luY2UgdGhpcyBpcyBhbiBhdXRvbWF0aWMgZG93bmdyYWRlXG4gICAgICAgIH0gZWxzZSBpZiAoaXNGYXN0TW9kZVN1cHBvcnRlZEJ5TW9kZWwobW9kZWxWYWx1ZSkgJiYgaXNGYXN0TW9kZSkge1xuICAgICAgICAgIG1lc3NhZ2UgKz0gYCDCtyBGYXN0IG1vZGUgT05gXG4gICAgICAgICAgd2FzRmFzdE1vZGVUb2dnbGVkT24gPSB0cnVlXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKFxuICAgICAgICBpc0JpbGxlZEFzRXh0cmFVc2FnZShcbiAgICAgICAgICBtb2RlbFZhbHVlLFxuICAgICAgICAgIHdhc0Zhc3RNb2RlVG9nZ2xlZE9uID09PSB0cnVlLFxuICAgICAgICAgIGlzT3B1czFtTWVyZ2VFbmFibGVkKCksXG4gICAgICAgIClcbiAgICAgICkge1xuICAgICAgICBtZXNzYWdlICs9IGAgwrcgQmlsbGVkIGFzIGV4dHJhIHVzYWdlYFxuICAgICAgfVxuXG4gICAgICBpZiAod2FzRmFzdE1vZGVUb2dnbGVkT24gPT09IGZhbHNlKSB7XG4gICAgICAgIC8vIEZhc3QgbW9kZSB3YXMgdG9nZ2xlZCBvZmYsIHNob3cgc3VmZml4IGFmdGVyIGV4dHJhIHVzYWdlIGJpbGxpbmdcbiAgICAgICAgbWVzc2FnZSArPSBgIMK3IEZhc3QgbW9kZSBPRkZgXG4gICAgICB9XG5cbiAgICAgIG9uRG9uZShtZXNzYWdlKVxuICAgIH1cblxuICAgIHZvaWQgaGFuZGxlTW9kZWxDaGFuZ2UoKVxuICB9LCBbbW9kZWwsIG9uRG9uZSwgc2V0QXBwU3RhdGVdKVxuXG4gIHJldHVybiBudWxsXG59XG5cbmZ1bmN0aW9uIGlzS25vd25BbGlhcyhtb2RlbDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiAoTU9ERUxfQUxJQVNFUyBhcyByZWFkb25seSBzdHJpbmdbXSkuaW5jbHVkZXMoXG4gICAgbW9kZWwudG9Mb3dlckNhc2UoKS50cmltKCksXG4gIClcbn1cblxuZnVuY3Rpb24gaXNPcHVzMW1VbmF2YWlsYWJsZShtb2RlbDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGNvbnN0IG0gPSBtb2RlbC50b0xvd2VyQ2FzZSgpXG4gIHJldHVybiAoXG4gICAgIWNoZWNrT3B1czFtQWNjZXNzKCkgJiZcbiAgICAhaXNPcHVzMW1NZXJnZUVuYWJsZWQoKSAmJlxuICAgIG0uaW5jbHVkZXMoJ29wdXMnKSAmJlxuICAgIG0uaW5jbHVkZXMoJ1sxbV0nKVxuICApXG59XG5cbmZ1bmN0aW9uIGlzU29ubmV0MW1VbmF2YWlsYWJsZShtb2RlbDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGNvbnN0IG0gPSBtb2RlbC50b0xvd2VyQ2FzZSgpXG4gIC8vIFdhcm4gYWJvdXQgU29ubmV0IGFuZCBTb25uZXQgNC42LCBidXQgbm90IFNvbm5ldCA0LjUgc2luY2UgdGhhdCBoYWRcbiAgLy8gYSBkaWZmZXJlbnQgYWNjZXNzIGNyaXRlcmlhLlxuICByZXR1cm4gKFxuICAgICFjaGVja1Nvbm5ldDFtQWNjZXNzKCkgJiZcbiAgICAobS5pbmNsdWRlcygnc29ubmV0WzFtXScpIHx8IG0uaW5jbHVkZXMoJ3Nvbm5ldC00LTZbMW1dJykpXG4gIClcbn1cblxuZnVuY3Rpb24gU2hvd01vZGVsQW5kQ2xvc2Uoe1xuICBvbkRvbmUsXG59OiB7XG4gIG9uRG9uZTogKHJlc3VsdD86IHN0cmluZykgPT4gdm9pZFxufSk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IG1haW5Mb29wTW9kZWwgPSB1c2VBcHBTdGF0ZShzID0+IHMubWFpbkxvb3BNb2RlbClcbiAgY29uc3QgbWFpbkxvb3BNb2RlbEZvclNlc3Npb24gPSB1c2VBcHBTdGF0ZShzID0+IHMubWFpbkxvb3BNb2RlbEZvclNlc3Npb24pXG4gIGNvbnN0IGVmZm9ydFZhbHVlID0gdXNlQXBwU3RhdGUocyA9PiBzLmVmZm9ydFZhbHVlKVxuICBjb25zdCBkaXNwbGF5TW9kZWwgPSByZW5kZXJNb2RlbExhYmVsKG1haW5Mb29wTW9kZWwpXG4gIGNvbnN0IGVmZm9ydEluZm8gPVxuICAgIGVmZm9ydFZhbHVlICE9PSB1bmRlZmluZWQgPyBgIChlZmZvcnQ6ICR7ZWZmb3J0VmFsdWV9KWAgOiAnJ1xuXG4gIGlmIChtYWluTG9vcE1vZGVsRm9yU2Vzc2lvbikge1xuICAgIG9uRG9uZShcbiAgICAgIGBDdXJyZW50IG1vZGVsOiAke2NoYWxrLmJvbGQocmVuZGVyTW9kZWxMYWJlbChtYWluTG9vcE1vZGVsRm9yU2Vzc2lvbikpfSAoc2Vzc2lvbiBvdmVycmlkZSBmcm9tIHBsYW4gbW9kZSlcXG5CYXNlIG1vZGVsOiAke2Rpc3BsYXlNb2RlbH0ke2VmZm9ydEluZm99YCxcbiAgICApXG4gIH0gZWxzZSB7XG4gICAgb25Eb25lKGBDdXJyZW50IG1vZGVsOiAke2Rpc3BsYXlNb2RlbH0ke2VmZm9ydEluZm99YClcbiAgfVxuXG4gIHJldHVybiBudWxsXG59XG5cbmV4cG9ydCBjb25zdCBjYWxsOiBMb2NhbEpTWENvbW1hbmRDYWxsID0gYXN5bmMgKG9uRG9uZSwgX2NvbnRleHQsIGFyZ3MpID0+IHtcbiAgYXJncyA9IGFyZ3M/LnRyaW0oKSB8fCAnJ1xuICBpZiAoQ09NTU9OX0lORk9fQVJHUy5pbmNsdWRlcyhhcmdzKSkge1xuICAgIGxvZ0V2ZW50KCd0ZW5ndV9tb2RlbF9jb21tYW5kX2lubGluZV9oZWxwJywge1xuICAgICAgYXJnczogYXJncyBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgIH0pXG4gICAgcmV0dXJuIDxTaG93TW9kZWxBbmRDbG9zZSBvbkRvbmU9e29uRG9uZX0gLz5cbiAgfVxuICBpZiAoQ09NTU9OX0hFTFBfQVJHUy5pbmNsdWRlcyhhcmdzKSkge1xuICAgIG9uRG9uZShcbiAgICAgICdSdW4gL21vZGVsIHRvIG9wZW4gdGhlIG1vZGVsIHNlbGVjdGlvbiBtZW51LCBvciAvbW9kZWwgW21vZGVsTmFtZV0gdG8gc2V0IHRoZSBtb2RlbC4nLFxuICAgICAgeyBkaXNwbGF5OiAnc3lzdGVtJyB9LFxuICAgIClcbiAgICByZXR1cm5cbiAgfVxuXG4gIGlmIChhcmdzKSB7XG4gICAgbG9nRXZlbnQoJ3Rlbmd1X21vZGVsX2NvbW1hbmRfaW5saW5lJywge1xuICAgICAgYXJnczogYXJncyBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgIH0pXG4gICAgcmV0dXJuIDxTZXRNb2RlbEFuZENsb3NlIGFyZ3M9e2FyZ3N9IG9uRG9uZT17b25Eb25lfSAvPlxuICB9XG5cbiAgcmV0dXJuIDxNb2RlbFBpY2tlcldyYXBwZXIgb25Eb25lPXtvbkRvbmV9IC8+XG59XG5cbmZ1bmN0aW9uIHJlbmRlck1vZGVsTGFiZWwobW9kZWw6IHN0cmluZyB8IG51bGwpOiBzdHJpbmcge1xuICBjb25zdCByZW5kZXJlZCA9IHJlbmRlckRlZmF1bHRNb2RlbFNldHRpbmcoXG4gICAgbW9kZWwgPz8gZ2V0RGVmYXVsdE1haW5Mb29wTW9kZWxTZXR0aW5nKCksXG4gIClcbiAgcmV0dXJuIG1vZGVsID09PSBudWxsID8gYCR7cmVuZGVyZWR9IChkZWZhdWx0KWAgOiByZW5kZXJlZFxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBT0EsS0FBSyxNQUFNLE9BQU87QUFDekIsT0FBTyxLQUFLQyxLQUFLLE1BQU0sT0FBTztBQUM5QixjQUFjQyxvQkFBb0IsUUFBUSxtQkFBbUI7QUFDN0QsU0FBU0MsV0FBVyxRQUFRLGlDQUFpQztBQUM3RCxTQUFT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 \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjaGFsayIsIlJlYWN0IiwiQ29tbWFuZFJlc3VsdERpc3BsYXkiLCJNb2RlbFBpY2tlciIsIkNPTU1PTl9IRUxQX0FSR1MiLCJDT01NT05fSU5GT19BUkdTIiwiQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyIsImxvZ0V2ZW50IiwidXNlQXBwU3RhdGUiLCJ1c2VTZXRBcHBTdGF0ZSIsIkxvY2FsSlNYQ29tbWFuZENhbGwiLCJFZmZvcnRMZXZlbCIsImlzQmlsbGVkQXNFeHRyYVVzYWdlIiwiY2xlYXJGYXN0TW9kZUNvb2xkb3duIiwiaXNGYXN0TW9kZUF2YWlsYWJsZSIsImlzRmFzdE1vZGVFbmFibGVkIiwiaXNGYXN0TW9kZVN1cHBvcnRlZEJ5TW9kZWwiLCJNT0RFTF9BTElBU0VTIiwiY2hlY2tPcHVzMW1BY2Nlc3MiLCJjaGVja1Nvbm5ldDFtQWNjZXNzIiwiZ2V0RGVmYXVsdE1haW5Mb29wTW9kZWxTZXR0aW5nIiwiaXNPcHVzMW1NZXJnZUVuYWJsZWQiLCJyZW5kZXJEZWZhdWx0TW9kZWxTZXR0aW5nIiwiaXNNb2RlbEFsbG93ZWQiLCJ2YWxpZGF0ZU1vZGVsIiwiTW9kZWxQaWNrZXJXcmFwcGVyIiwidDAiLCIkIiwiX2MiLCJvbkRvbmUiLCJtYWluTG9vcE1vZGVsIiwiX3RlbXAiLCJtYWluTG9vcE1vZGVsRm9yU2Vzc2lvbiIsIl90ZW1wMiIsImlzRmFzdE1vZGUiLCJfdGVtcDMiLCJzZXRBcHBTdGF0ZSIsInQxIiwiaGFuZGxlQ2FuY2VsIiwiYWN0aW9uIiwiZGlzcGxheU1vZGVsIiwicmVuZGVyTW9kZWxMYWJlbCIsImJvbGQiLCJkaXNwbGF5IiwidDIiLCJoYW5kbGVTZWxlY3QiLCJtb2RlbCIsImVmZm9ydCIsImZyb21fbW9kZWwiLCJ0b19tb2RlbCIsInByZXYiLCJtZXNzYWdlIiwidW5kZWZpbmVkIiwid2FzRmFzdE1vZGVUb2dnbGVkT24iLCJfdGVtcDQiLCJ0MyIsInQ0IiwicHJldl8wIiwiZmFzdE1vZGUiLCJzXzEiLCJzIiwic18wIiwiU2V0TW9kZWxBbmRDbG9zZSIsImFyZ3MiLCJyZXN1bHQiLCJvcHRpb25zIiwiUmVhY3ROb2RlIiwidXNlRWZmZWN0IiwiaGFuZGxlTW9kZWxDaGFuZ2UiLCJQcm9taXNlIiwiaXNPcHVzMW1VbmF2YWlsYWJsZSIsImlzU29ubmV0MW1VbmF2YWlsYWJsZSIsInNldE1vZGVsIiwiaXNLbm93bkFsaWFzIiwidmFsaWQiLCJlcnJvciIsIkVycm9yIiwibW9kZWxWYWx1ZSIsImluY2x1ZGVzIiwidG9Mb3dlckNhc2UiLCJ0cmltIiwibSIsIlNob3dNb2RlbEFuZENsb3NlIiwiX3RlbXA3IiwiX3RlbXA4IiwiZWZmb3J0VmFsdWUiLCJfdGVtcDkiLCJlZmZvcnRJbmZvIiwiY2FsbCIsIl9jb250ZXh0IiwicmVuZGVyZWQiXSwic291cmNlcyI6WyJtb2RlbC50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNoYWxrIGZyb20gJ2NoYWxrJ1xuaW1wb3J0ICogYXMgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgdHlwZSB7IENvbW1hbmRSZXN1bHREaXNwbGF5IH0gZnJvbSAnLi4vLi4vY29tbWFuZHMuanMnXG5pbXBvcnQgeyBNb2RlbFBpY2tlciB9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvTW9kZWxQaWNrZXIuanMnXG5pbXBvcnQgeyBDT01NT05fSEVMUF9BUkdTLCBDT01NT05fSU5GT19BUkdTIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzL3htbC5qcydcbmltcG9ydCB7XG4gIHR5cGUgQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyxcbiAgbG9nRXZlbnQsXG59IGZyb20gJy4uLy4uL3NlcnZpY2VzL2FuYWx5dGljcy9pbmRleC5qcydcbmltcG9ydCB7IHVzZUFwcFN0YXRlLCB1c2VTZXRBcHBTdGF0ZSB9IGZyb20gJy4uLy4uL3N0YXRlL0FwcFN0YXRlLmpzJ1xuaW1wb3J0IHR5cGUgeyBMb2NhbEpTWENvbW1hbmRDYWxsIH0gZnJvbSAnLi4vLi4vdHlwZXMvY29tbWFuZC5qcydcbmltcG9ydCB0eXBlIHsgRWZmb3J0TGV2ZWwgfSBmcm9tICcuLi8uLi91dGlscy9lZmZvcnQuanMnXG5pbXBvcnQgeyBpc0JpbGxlZEFzRXh0cmFVc2FnZSB9IGZyb20gJy4uLy4uL3V0aWxzL2V4dHJhVXNhZ2UuanMnXG5pbXBvcnQge1xuICBjbGVhckZhc3RNb2RlQ29vbGRvd24sXG4gIGlzRmFzdE1vZGVBdmFpbGFibGUsXG4gIGlzRmFzdE1vZGVFbmFibGVkLFxuICBpc0Zhc3RNb2RlU3VwcG9ydGVkQnlNb2RlbCxcbn0gZnJvbSAnLi4vLi4vdXRpbHMvZmFzdE1vZGUuanMnXG5pbXBvcnQgeyBNT0RFTF9BTElBU0VTIH0gZnJvbSAnLi4vLi4vdXRpbHMvbW9kZWwvYWxpYXNlcy5qcydcbmltcG9ydCB7XG4gIGNoZWNrT3B1czFtQWNjZXNzLFxuICBjaGVja1Nvbm5ldDFtQWNjZXNzLFxufSBmcm9tICcuLi8uLi91dGlscy9tb2RlbC9jaGVjazFtQWNjZXNzLmpzJ1xuaW1wb3J0IHtcbiAgZ2V0RGVmYXVsdE1haW5Mb29wTW9kZWxTZXR0aW5nLFxuICBpc09wdXMxbU1lcmdlRW5hYmxlZCxcbiAgcmVuZGVyRGVmYXVsdE1vZGVsU2V0dGluZyxcbn0gZnJvbSAnLi4vLi4vdXRpbHMvbW9kZWwvbW9kZWwuanMnXG5pbXBvcnQgeyBpc01vZGVsQWxsb3dlZCB9IGZyb20gJy4uLy4uL3V0aWxzL21vZGVsL21vZGVsQWxsb3dsaXN0LmpzJ1xuaW1wb3J0IHsgdmFsaWRhdGVNb2RlbCB9IGZyb20gJy4uLy4uL3V0aWxzL21vZGVsL3ZhbGlkYXRlTW9kZWwuanMnXG5cbmZ1bmN0aW9uIE1vZGVsUGlja2VyV3JhcHBlcih7XG4gIG9uRG9uZSxcbn06IHtcbiAgb25Eb25lOiAoXG4gICAgcmVzdWx0Pzogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7IGRpc3BsYXk/OiBDb21tYW5kUmVzdWx0RGlzcGxheSB9LFxuICApID0+IHZvaWRcbn0pOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBtYWluTG9vcE1vZGVsID0gdXNlQXBwU3RhdGUocyA9PiBzLm1haW5Mb29wTW9kZWwpXG4gIGNvbnN0IG1haW5Mb29wTW9kZWxGb3JTZXNzaW9uID0gdXNlQXBwU3RhdGUocyA9PiBzLm1haW5Mb29wTW9kZWxGb3JTZXNzaW9uKVxuICBjb25zdCBpc0Zhc3RNb2RlID0gdXNlQXBwU3RhdGUocyA9PiBzLmZhc3RNb2RlKVxuICBjb25zdCBzZXRBcHBTdGF0ZSA9IHVzZVNldEFwcFN0YXRlKClcblxuICBmdW5jdGlvbiBoYW5kbGVDYW5jZWwoKTogdm9pZCB7XG4gICAgbG9nRXZlbnQoJ3Rlbmd1X21vZGVsX2NvbW1hbmRfbWVudScsIHtcbiAgICAgIGFjdGlvbjpcbiAgICAgICAgJ2NhbmNlbCcgYXMgQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyxcbiAgICB9KVxuICAgIGNvbnN0IGRpc3BsYXlNb2RlbCA9IHJlbmRlck1vZGVsTGFiZWwobWFpbkxvb3BNb2RlbClcbiAgICBvbkRvbmUoYEtlcHQgbW9kZWwgYXMgJHtjaGFsay5ib2xkKGRpc3BsYXlNb2RlbCl9YCwge1xuICAgICAgZGlzcGxheTogJ3N5c3RlbScsXG4gICAgfSlcbiAgfVxuXG4gIGZ1bmN0aW9uIGhhbmRsZVNlbGVjdChcbiAgICBtb2RlbDogc3RyaW5nIHwgbnVsbCxcbiAgICBlZmZvcnQ6IEVmZm9ydExldmVsIHwgdW5kZWZpbmVkLFxuICApOiB2b2lkIHtcbiAgICBsb2dFdmVudCgndGVuZ3VfbW9kZWxfY29tbWFuZF9tZW51Jywge1xuICAgICAgYWN0aW9uOlxuICAgICAgICBtb2RlbCBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgICAgZnJvbV9tb2RlbDpcbiAgICAgICAgbWFpbkxvb3BNb2RlbCBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgICAgdG9fbW9kZWw6XG4gICAgICAgIG1vZGVsIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gICAgfSlcbiAgICBzZXRBcHBTdGF0ZShwcmV2ID0+ICh7XG4gICAgICAuLi5wcmV2LFxuICAgICAgbWFpbkxvb3BNb2RlbDogbW9kZWwsXG4gICAgICBtYWluTG9vcE1vZGVsRm9yU2Vzc2lvbjogbnVsbCxcbiAgICB9KSlcblxuICAgIGxldCBtZXNzYWdlID0gYFNldCBtb2RlbCB0byAke2NoYWxrLmJvbGQocmVuZGVyTW9kZWxMYWJlbChtb2RlbCkpfWBcbiAgICBpZiAoZWZmb3J0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIG1lc3NhZ2UgKz0gYCB3aXRoICR7Y2hhbGsuYm9sZChlZmZvcnQpfSBlZmZvcnRgXG4gICAgfVxuXG4gICAgLy8gVHVybiBvZmYgZmFzdCBtb2RlIGlmIHN3aXRjaGluZyB0byB1bnN1cHBvcnRlZCBtb2RlbFxuICAgIGxldCB3YXNGYXN0TW9kZVRvZ2dsZWRPbiA9IHVuZGVmaW5lZFxuICAgIGlmIChpc0Zhc3RNb2RlRW5hYmxlZCgpKSB7XG4gICAgICBjbGVhckZhc3RNb2RlQ29vbGRvd24oKVxuICAgICAgaWYgKCFpc0Zhc3RNb2RlU3VwcG9ydGVkQnlNb2RlbChtb2RlbCkgJiYgaXNGYXN0TW9kZSkge1xuICAgICAgICBzZXRBcHBTdGF0ZShwcmV2ID0+ICh7XG4gICAgICAgICAgLi4ucHJldixcbiAgICAgICAgICBmYXN0TW9kZTogZmFsc2UsXG4gICAgICAgIH0pKVxuICAgICAgICB3YXNGYXN0TW9kZVRvZ2dsZWRPbiA9IGZhbHNlXG4gICAgICAgIC8vIERvIG5vdCB1cGRhdGUgZmFzdCBtb2RlIGluIHNldHRpbmdzIHNpbmNlIHRoaXMgaXMgYW4gYXV0b21hdGljIGRvd25ncmFkZVxuICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgaXNGYXN0TW9kZVN1cHBvcnRlZEJ5TW9kZWwobW9kZWwpICYmXG4gICAgICAgIGlzRmFzdE1vZGVBdmFpbGFibGUoKSAmJlxuICAgICAgICBpc0Zhc3RNb2RlXG4gICAgICApIHtcbiAgICAgICAgbWVzc2FnZSArPSBgIMK3IEZhc3QgbW9kZSBPTmBcbiAgICAgICAgd2FzRmFzdE1vZGVUb2dnbGVkT24gPSB0cnVlXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgaXNCaWxsZWRBc0V4dHJhVXNhZ2UoXG4gICAgICAgIG1vZGVsLFxuICAgICAgICB3YXNGYXN0TW9kZVRvZ2dsZWRPbiA9PT0gdHJ1ZSxcbiAgICAgICAgaXNPcHVzMW1NZXJnZUVuYWJsZWQoKSxcbiAgICAgIClcbiAgICApIHtcbiAgICAgIG1lc3NhZ2UgKz0gYCDCtyBCaWxsZWQgYXMgZXh0cmEgdXNhZ2VgXG4gICAgfVxuXG4gICAgaWYgKHdhc0Zhc3RNb2RlVG9nZ2xlZE9uID09PSBmYWxzZSkge1xuICAgICAgLy8gRmFzdCBtb2RlIHdhcyB0b2dnbGVkIG9mZiwgc2hvdyBzdWZmaXggYWZ0ZXIgZXh0cmEgdXNhZ2UgYmlsbGluZ1xuICAgICAgbWVzc2FnZSArPSBgIMK3IEZhc3QgbW9kZSBPRkZgXG4gICAgfVxuXG4gICAgb25Eb25lKG1lc3NhZ2UpXG4gIH1cblxuICByZXR1cm4gKFxuICAgIDxNb2RlbFBpY2tlclxuICAgICAgaW5pdGlhbD17bWFpbkxvb3BNb2RlbH1cbiAgICAgIHNlc3Npb25Nb2RlbD17bWFpbkxvb3BNb2RlbEZvclNlc3Npb259XG4gICAgICBvblNlbGVjdD17aGFuZGxlU2VsZWN0fVxuICAgICAgb25DYW5jZWw9e2hhbmRsZUNhbmNlbH1cbiAgICAgIGlzU3RhbmRhbG9uZUNvbW1hbmRcbiAgICAgIHNob3dGYXN0TW9kZU5vdGljZT17XG4gICAgICAgIGlzRmFzdE1vZGVFbmFibGVkKCkgJiZcbiAgICAgICAgaXNGYXN0TW9kZSAmJlxuICAgICAgICBpc0Zhc3RNb2RlU3VwcG9ydGVkQnlNb2RlbChtYWluTG9vcE1vZGVsKSAmJlxuICAgICAgICBpc0Zhc3RNb2RlQXZhaWxhYmxlKClcbiAgICAgIH1cbiAgICAvPlxuICApXG59XG5cbmZ1bmN0aW9uIFNldE1vZGVsQW5kQ2xvc2Uoe1xuICBhcmdzLFxuICBvbkRvbmUsXG59OiB7XG4gIGFyZ3M6IHN0cmluZ1xuICBvbkRvbmU6IChcbiAgICByZXN1bHQ/OiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHsgZGlzcGxheT86IENvbW1hbmRSZXN1bHREaXNwbGF5IH0sXG4gICkgPT4gdm9pZFxufSk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IGlzRmFzdE1vZGUgPSB1c2VBcHBTdGF0ZShzID0+IHMuZmFzdE1vZGUpXG4gIGNvbnN0IHNldEFwcFN0YXRlID0gdXNlU2V0QXBwU3RhdGUoKVxuICBjb25zdCBtb2RlbCA9IGFyZ3MgPT09ICdkZWZhdWx0JyA/IG51bGwgOiBhcmdzXG5cbiAgUmVhY3QudXNlRWZmZWN0KCgpID0+IHtcbiAgICBhc3luYyBmdW5jdGlvbiBoYW5kbGVNb2RlbENoYW5nZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgIGlmIChtb2RlbCAmJiAhaXNNb2RlbEFsbG93ZWQobW9kZWwpKSB7XG4gICAgICAgIG9uRG9uZShcbiAgICAgICAgICBgTW9kZWwgJyR7bW9kZWx9JyBpcyBub3QgYXZhaWxhYmxlLiBZb3VyIG9yZ2FuaXphdGlvbiByZXN0cmljdHMgbW9kZWwgc2VsZWN0aW9uLmAsXG4gICAgICAgICAgeyBkaXNwbGF5OiAnc3lzdGVtJyB9LFxuICAgICAgICApXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICAvLyBAW01PREVMIExBVU5DSF06IFVwZGF0ZSBjaGVjayBmb3IgMU0gYWNjZXNzLlxuICAgICAgaWYgKG1vZGVsICYmIGlzT3B1czFtVW5hdmFpbGFibGUobW9kZWwpKSB7XG4gICAgICAgIG9uRG9uZShcbiAgICAgICAgICBgT3B1cyA0LjYgd2l0aCAxTSBjb250ZXh0IGlzIG5vdCBhdmFpbGFibGUgZm9yIHlvdXIgYWNjb3VudC4gTGVhcm4gbW9yZTogaHR0cHM6Ly9jb2RlLmNsYXVkZS5jb20vZG9jcy9lbi9tb2RlbC1jb25maWcjZXh0ZW5kZWQtY29udGV4dC13aXRoLTFtYCxcbiAgICAgICAgICB7IGRpc3BsYXk6ICdzeXN0ZW0nIH0sXG4gICAgICAgIClcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGlmIChtb2RlbCAmJiBpc1Nvbm5ldDFtVW5hdmFpbGFibGUobW9kZWwpKSB7XG4gICAgICAgIG9uRG9uZShcbiAgICAgICAgICBgU29ubmV0IDQuNiB3aXRoIDFNIGNvbnRleHQgaXMgbm90IGF2YWlsYWJsZSBmb3IgeW91ciBhY2NvdW50LiBMZWFybiBtb3JlOiBodHRwczovL2NvZGUuY2xhdWRlLmNvbS9kb2NzL2VuL21vZGVsLWNvbmZpZyNleHRlbmRlZC1jb250ZXh0LXdpdGgtMW1gLFxuICAgICAgICAgIHsgZGlzcGxheTogJ3N5c3RlbScgfSxcbiAgICAgICAgKVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgLy8gU2tpcCB2YWxpZGF0aW9uIGZvciBkZWZhdWx0IG1vZGVsXG4gICAgICBpZiAoIW1vZGVsKSB7XG4gICAgICAgIHNldE1vZGVsKG51bGwpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICAvLyBTa2lwIHZhbGlkYXRpb24gZm9yIGtub3duIGFsaWFzZXMgLSB0aGV5J3JlIHByZWRlZmluZWQgYW5kIHNob3VsZCB3b3JrXG4gICAgICBpZiAoaXNLbm93bkFsaWFzKG1vZGVsKSkge1xuICAgICAgICBzZXRNb2RlbChtb2RlbClcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIC8vIFZhbGlkYXRlIGFuZCBzZXQgY3VzdG9tIG1vZGVsXG4gICAgICB0cnkge1xuICAgICAgICAvLyBEb24ndCB1c2UgcGFyc2VVc2VyU3BlY2lmaWVkTW9kZWwgZm9yIG5vbi1hbGlhc2VzIHNpbmNlIGl0IGxvd2VyY2FzZXMgdGhlIGlucHV0XG4gICAgICAgIC8vIGFuZCBtb2RlbCBuYW1lcyBhcmUgY2FzZS1zZW5zaXRpdmVcbiAgICAgICAgY29uc3QgeyB2YWxpZCwgZXJyb3IgfSA9IGF3YWl0IHZhbGlkYXRlTW9kZWwobW9kZWwpXG5cbiAgICAgICAgaWYgKHZhbGlkKSB7XG4gICAgICAgICAgc2V0TW9kZWwobW9kZWwpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgb25Eb25lKGVycm9yIHx8IGBNb2RlbCAnJHttb2RlbH0nIG5vdCBmb3VuZGAsIHtcbiAgICAgICAgICAgIGRpc3BsYXk6ICdzeXN0ZW0nLFxuICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIG9uRG9uZShgRmFpbGVkIHRvIHZhbGlkYXRlIG1vZGVsOiAkeyhlcnJvciBhcyBFcnJvcikubWVzc2FnZX1gLCB7XG4gICAgICAgICAgZGlzcGxheTogJ3N5c3RlbScsXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gc2V0TW9kZWwobW9kZWxWYWx1ZTogc3RyaW5nIHwgbnVsbCk6IHZvaWQge1xuICAgICAgc2V0QXBwU3RhdGUocHJldiA9PiAoe1xuICAgICAgICAuLi5wcmV2LFxuICAgICAgICBtYWluTG9vcE1vZGVsOiBtb2RlbFZhbHVlLFxuICAgICAgICBtYWluTG9vcE1vZGVsRm9yU2Vzc2lvbjogbnVsbCxcbiAgICAgIH0pKVxuICAgICAgbGV0IG1lc3NhZ2UgPSBgU2V0IG1vZGVsIHRvICR7Y2hhbGsuYm9sZChyZW5kZXJNb2RlbExhYmVsKG1vZGVsVmFsdWUpKX1gXG5cbiAgICAgIGxldCB3YXNGYXN0TW9kZVRvZ2dsZWRPbiA9IHVuZGVmaW5lZFxuICAgICAgaWYgKGlzRmFzdE1vZGVFbmFibGVkKCkpIHtcbiAgICAgICAgY2xlYXJGYXN0TW9kZUNvb2xkb3duKClcbiAgICAgICAgaWYgKCFpc0Zhc3RNb2RlU3VwcG9ydGVkQnlNb2RlbChtb2RlbFZhbHVlKSAmJiBpc0Zhc3RNb2RlKSB7XG4gICAgICAgICAgc2V0QXBwU3RhdGUocHJldiA9PiAoe1xuICAgICAgICAgICAgLi4ucHJldixcbiAgICAgICAgICAgIGZhc3RNb2RlOiBmYWxzZSxcbiAgICAgICAgICB9KSlcbiAgICAgICAgICB3YXNGYXN0TW9kZVRvZ2dsZWRPbiA9IGZhbHNlXG4gICAgICAgICAgLy8gRG8gbm90IHVwZGF0ZSBmYXN0IG1vZGUgaW4gc2V0dGluZ3Mgc2luY2UgdGhpcyBpcyBhbiBhdXRvbWF0aWMgZG93bmdyYWRlXG4gICAgICAgIH0gZWxzZSBpZiAoaXNGYXN0TW9kZVN1cHBvcnRlZEJ5TW9kZWwobW9kZWxWYWx1ZSkgJiYgaXNGYXN0TW9kZSkge1xuICAgICAgICAgIG1lc3NhZ2UgKz0gYCDCtyBGYXN0IG1vZGUgT05gXG4gICAgICAgICAgd2FzRmFzdE1vZGVUb2dnbGVkT24gPSB0cnVlXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKFxuICAgICAgICBpc0JpbGxlZEFzRXh0cmFVc2FnZShcbiAgICAgICAgICBtb2RlbFZhbHVlLFxuICAgICAgICAgIHdhc0Zhc3RNb2RlVG9nZ2xlZE9uID09PSB0cnVlLFxuICAgICAgICAgIGlzT3B1czFtTWVyZ2VFbmFibGVkKCksXG4gICAgICAgIClcbiAgICAgICkge1xuICAgICAgICBtZXNzYWdlICs9IGAgwrcgQmlsbGVkIGFzIGV4dHJhIHVzYWdlYFxuICAgICAgfVxuXG4gICAgICBpZiAod2FzRmFzdE1vZGVUb2dnbGVkT24gPT09IGZhbHNlKSB7XG4gICAgICAgIC8vIEZhc3QgbW9kZSB3YXMgdG9nZ2xlZCBvZmYsIHNob3cgc3VmZml4IGFmdGVyIGV4dHJhIHVzYWdlIGJpbGxpbmdcbiAgICAgICAgbWVzc2FnZSArPSBgIMK3IEZhc3QgbW9kZSBPRkZgXG4gICAgICB9XG5cbiAgICAgIG9uRG9uZShtZXNzYWdlKVxuICAgIH1cblxuICAgIHZvaWQgaGFuZGxlTW9kZWxDaGFuZ2UoKVxuICB9LCBbbW9kZWwsIG9uRG9uZSwgc2V0QXBwU3RhdGVdKVxuXG4gIHJldHVybiBudWxsXG59XG5cbmZ1bmN0aW9uIGlzS25vd25BbGlhcyhtb2RlbDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiAoTU9ERUxfQUxJQVNFUyBhcyByZWFkb25seSBzdHJpbmdbXSkuaW5jbHVkZXMoXG4gICAgbW9kZWwudG9Mb3dlckNhc2UoKS50cmltKCksXG4gIClcbn1cblxuZnVuY3Rpb24gaXNPcHVzMW1VbmF2YWlsYWJsZShtb2RlbDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGNvbnN0IG0gPSBtb2RlbC50b0xvd2VyQ2FzZSgpXG4gIHJldHVybiAoXG4gICAgIWNoZWNrT3B1czFtQWNjZXNzKCkgJiZcbiAgICAhaXNPcHVzMW1NZXJnZUVuYWJsZWQoKSAmJlxuICAgIG0uaW5jbHVkZXMoJ29wdXMnKSAmJlxuICAgIG0uaW5jbHVkZXMoJ1sxbV0nKVxuICApXG59XG5cbmZ1bmN0aW9uIGlzU29ubmV0MW1VbmF2YWlsYWJsZShtb2RlbDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGNvbnN0IG0gPSBtb2RlbC50b0xvd2VyQ2FzZSgpXG4gIC8vIFdhcm4gYWJvdXQgU29ubmV0IGFuZCBTb25uZXQgNC42LCBidXQgbm90IFNvbm5ldCA0LjUgc2luY2UgdGhhdCBoYWRcbiAgLy8gYSBkaWZmZXJlbnQgYWNjZXNzIGNyaXRlcmlhLlxuICByZXR1cm4gKFxuICAgICFjaGVja1Nvbm5ldDFtQWNjZXNzKCkgJiZcbiAgICAobS5pbmNsdWRlcygnc29ubmV0WzFtXScpIHx8IG0uaW5jbHVkZXMoJ3Nvbm5ldC00LTZbMW1dJykpXG4gIClcbn1cblxuZnVuY3Rpb24gU2hvd01vZGVsQW5kQ2xvc2Uoe1xuICBvbkRvbmUsXG59OiB7XG4gIG9uRG9uZTogKHJlc3VsdD86IHN0cmluZykgPT4gdm9pZFxufSk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGNvbnN0IG1haW5Mb29wTW9kZWwgPSB1c2VBcHBTdGF0ZShzID0+IHMubWFpbkxvb3BNb2RlbClcbiAgY29uc3QgbWFpbkxvb3BNb2RlbEZvclNlc3Npb24gPSB1c2VBcHBTdGF0ZShzID0+IHMubWFpbkxvb3BNb2RlbEZvclNlc3Npb24pXG4gIGNvbnN0IGVmZm9ydFZhbHVlID0gdXNlQXBwU3RhdGUocyA9PiBzLmVmZm9ydFZhbHVlKVxuICBjb25zdCBkaXNwbGF5TW9kZWwgPSByZW5kZXJNb2RlbExhYmVsKG1haW5Mb29wTW9kZWwpXG4gIGNvbnN0IGVmZm9ydEluZm8gPVxuICAgIGVmZm9ydFZhbHVlICE9PSB1bmRlZmluZWQgPyBgIChlZmZvcnQ6ICR7ZWZmb3J0VmFsdWV9KWAgOiAnJ1xuXG4gIGlmIChtYWluTG9vcE1vZGVsRm9yU2Vzc2lvbikge1xuICAgIG9uRG9uZShcbiAgICAgIGBDdXJyZW50IG1vZGVsOiAke2NoYWxrLmJvbGQocmVuZGVyTW9kZWxMYWJlbChtYWluTG9vcE1vZGVsRm9yU2Vzc2lvbikpfSAoc2Vzc2lvbiBvdmVycmlkZSBmcm9tIHBsYW4gbW9kZSlcXG5CYXNlIG1vZGVsOiAke2Rpc3BsYXlNb2RlbH0ke2VmZm9ydEluZm99YCxcbiAgICApXG4gIH0gZWxzZSB7XG4gICAgb25Eb25lKGBDdXJyZW50IG1vZGVsOiAke2Rpc3BsYXlNb2RlbH0ke2VmZm9ydEluZm99YClcbiAgfVxuXG4gIHJldHVybiBudWxsXG59XG5cbmV4cG9ydCBjb25zdCBjYWxsOiBMb2NhbEpTWENvbW1hbmRDYWxsID0gYXN5bmMgKG9uRG9uZSwgX2NvbnRleHQsIGFyZ3MpID0+IHtcbiAgYXJncyA9IGFyZ3M/LnRyaW0oKSB8fCAnJ1xuICBpZiAoQ09NTU9OX0lORk9fQVJHUy5pbmNsdWRlcyhhcmdzKSkge1xuICAgIGxvZ0V2ZW50KCd0ZW5ndV9tb2RlbF9jb21tYW5kX2lubGluZV9oZWxwJywge1xuICAgICAgYXJnczogYXJncyBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgIH0pXG4gICAgcmV0dXJuIDxTaG93TW9kZWxBbmRDbG9zZSBvbkRvbmU9e29uRG9uZX0gLz5cbiAgfVxuICBpZiAoQ09NTU9OX0hFTFBfQVJHUy5pbmNsdWRlcyhhcmdzKSkge1xuICAgIG9uRG9uZShcbiAgICAgICdSdW4gL21vZGVsIHRvIG9wZW4gdGhlIG1vZGVsIHNlbGVjdGlvbiBtZW51LCBvciAvbW9kZWwgW21vZGVsTmFtZV0gdG8gc2V0IHRoZSBtb2RlbC4nLFxuICAgICAgeyBkaXNwbGF5OiAnc3lzdGVtJyB9LFxuICAgIClcbiAgICByZXR1cm5cbiAgfVxuXG4gIGlmIChhcmdzKSB7XG4gICAgbG9nRXZlbnQoJ3Rlbmd1X21vZGVsX2NvbW1hbmRfaW5saW5lJywge1xuICAgICAgYXJnczogYXJncyBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgIH0pXG4gICAgcmV0dXJuIDxTZXRNb2RlbEFuZENsb3NlIGFyZ3M9e2FyZ3N9IG9uRG9uZT17b25Eb25lfSAvPlxuICB9XG5cbiAgcmV0dXJuIDxNb2RlbFBpY2tlcldyYXBwZXIgb25Eb25lPXtvbkRvbmV9IC8+XG59XG5cbmZ1bmN0aW9uIHJlbmRlck1vZGVsTGFiZWwobW9kZWw6IHN0cmluZyB8IG51bGwpOiBzdHJpbmcge1xuICBjb25zdCByZW5kZXJlZCA9IHJlbmRlckRlZmF1bHRNb2RlbFNldHRpbmcoXG4gICAgbW9kZWwgPz8gZ2V0RGVmYXVsdE1haW5Mb29wTW9kZWxTZXR0aW5nKCksXG4gIClcbiAgcmV0dXJuIG1vZGVsID09PSBudWxsID8gYCR7cmVuZGVyZWR9IChkZWZhdWx0KWAgOiByZW5kZXJlZFxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBT0EsS0FBSyxNQUFNLE9BQU87QUFDekIsT0FBTyxLQUFLQyxLQUFLLE1BQU0sT0FBTztBQUM5QixjQUFjQyxvQkFBb0IsUUFBUSxtQkFBbUI7QUFDN0QsU0FBU0MsV0FBVyxRQUFRLGlDQUFpQztBQUM3RCxTQUFT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 diff --git a/src/commands/ultraplan.tsx b/src/commands/ultraplan.tsx index 17710eb1..942c8085 100644 --- a/src/commands/ultraplan.tsx +++ b/src/commands/ultraplan.tsx @@ -30,7 +30,7 @@ export const CCR_TERMS_URL = 'https://code.claude.com/docs/en/claude-code-on-the // load: the GrowthBook cache is empty at import and `/config` Gates can flip // it between invocations. function getUltraplanModel(): string { - return getFeatureValue_CACHED_MAY_BE_STALE('tengu_ultraplan_model', ALL_MODEL_CONFIGS.opus46.firstParty); + return getFeatureValue_CACHED_MAY_BE_STALE('tengu_ultraplan_model', ALL_MODEL_CONFIGS.opus48.firstParty); } // prompt.txt is wrapped in so the CCR browser hides @@ -468,4 +468,4 @@ export default { call }) } satisfies Command; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJyZWFkRmlsZVN5bmMiLCJSRU1PVEVfQ09OVFJPTF9ESVNDT05ORUNURURfTVNHIiwiQ29tbWFuZCIsIkRJQU1PTkRfT1BFTiIsImdldFJlbW90ZVNlc3Npb25VcmwiLCJnZXRGZWF0dXJlVmFsdWVfQ0FDSEVEX01BWV9CRV9TVEFMRSIsIkFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMiLCJsb2dFdmVudCIsIkFwcFN0YXRlIiwiY2hlY2tSZW1vdGVBZ2VudEVsaWdpYmlsaXR5IiwiZm9ybWF0UHJlY29uZGl0aW9uRXJyb3IiLCJSZW1vdGVBZ2VudFRhc2siLCJSZW1vdGVBZ2VudFRhc2tTdGF0ZSIsInJlZ2lzdGVyUmVtb3RlQWdlbnRUYXNrIiwiTG9jYWxKU1hDb21tYW5kQ2FsbCIsImxvZ0ZvckRlYnVnZ2luZyIsImVycm9yTWVzc2FnZSIsImxvZ0Vycm9yIiwiZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24iLCJBTExfTU9ERUxfQ09ORklHUyIsInVwZGF0ZVRhc2tTdGF0ZSIsImFyY2hpdmVSZW1vdGVTZXNzaW9uIiwidGVsZXBvcnRUb1JlbW90ZSIsInBvbGxGb3JBcHByb3ZlZEV4aXRQbGFuTW9kZSIsIlVsdHJhcGxhblBvbGxFcnJvciIsIlVMVFJBUExBTl9USU1FT1VUX01TIiwiQ0NSX1RFUk1TX1VSTCIsImdldFVsdHJhcGxhbk1vZGVsIiwib3B1czQ2IiwiZmlyc3RQYXJ0eSIsIl9yYXdQcm9tcHQiLCJyZXF1aXJlIiwiREVGQVVMVF9JTlNUUlVDVElPTlMiLCJkZWZhdWx0IiwidHJpbUVuZCIsIlVMVFJBUExBTl9JTlNUUlVDVElPTlMiLCJwcm9jZXNzIiwiZW52IiwiVUxUUkFQTEFOX1BST01QVF9GSUxFIiwiYnVpbGRVbHRyYXBsYW5Qcm9tcHQiLCJibHVyYiIsInNlZWRQbGFuIiwicGFydHMiLCJwdXNoIiwiam9pbiIsInN0YXJ0RGV0YWNoZWRQb2xsIiwidGFza0lkIiwic2Vzc2lvbklkIiwidXJsIiwiZ2V0QXBwU3RhdGUiLCJzZXRBcHBTdGF0ZSIsImYiLCJwcmV2Iiwic3RhcnRlZCIsIkRhdGUiLCJub3ciLCJmYWlsZWQiLCJwbGFuIiwicmVqZWN0Q291bnQiLCJleGVjdXRpb25UYXJnZXQiLCJwaGFzZSIsInQiLCJzdGF0dXMiLCJuZXh0IiwidW5kZWZpbmVkIiwidWx0cmFwbGFuUGhhc2UiLCJ0YXNrcyIsImR1cmF0aW9uX21zIiwicGxhbl9sZW5ndGgiLCJsZW5ndGgiLCJyZWplY3RfY291bnQiLCJleGVjdXRpb25fdGFyZ2V0IiwidGFzayIsImVuZFRpbWUiLCJ1bHRyYXBsYW5TZXNzaW9uVXJsIiwidmFsdWUiLCJtb2RlIiwidWx0cmFwbGFuUGVuZGluZ0Nob2ljZSIsImUiLCJyZWFzb24iLCJjYXRjaCIsIlN0cmluZyIsImJ1aWxkTGF1bmNoTWVzc2FnZSIsImRpc2Nvbm5lY3RlZEJyaWRnZSIsInByZWZpeCIsImJ1aWxkU2Vzc2lvblJlYWR5TWVzc2FnZSIsImJ1aWxkQWxyZWFkeUFjdGl2ZU1lc3NhZ2UiLCJzdG9wVWx0cmFwbGFuIiwiUHJvbWlzZSIsImtpbGwiLCJ1bHRyYXBsYW5MYXVuY2hpbmciLCJTRVNTSU9OX0lOR1JFU1NfVVJMIiwiaXNNZXRhIiwibGF1bmNoVWx0cmFwbGFuIiwib3B0cyIsInNpZ25hbCIsIkFib3J0U2lnbmFsIiwib25TZXNzaW9uUmVhZHkiLCJtc2ciLCJhY3RpdmUiLCJsYXVuY2hEZXRhY2hlZCIsIm1vZGVsIiwiZWxpZ2liaWxpdHkiLCJlbGlnaWJsZSIsInByZWNvbmRpdGlvbl9lcnJvcnMiLCJlcnJvcnMiLCJtYXAiLCJ0eXBlIiwicmVhc29ucyIsInByb21wdCIsImJ1bmRsZUZhaWxNc2ciLCJzZXNzaW9uIiwiaW5pdGlhbE1lc3NhZ2UiLCJkZXNjcmlwdGlvbiIsInBlcm1pc3Npb25Nb2RlIiwidWx0cmFwbGFuIiwidXNlRGVmYXVsdEVudmlyb25tZW50Iiwib25CdW5kbGVGYWlsIiwiaWQiLCJoYXNfc2VlZF9wbGFuIiwiQm9vbGVhbiIsInJlbW90ZVRhc2tUeXBlIiwidGl0bGUiLCJjb21tYW5kIiwiY29udGV4dCIsImFib3J0Q29udHJvbGxlciIsIkFib3J0Q29udHJvbGxlciIsImlzVWx0cmFwbGFuIiwiZXJyIiwiY2FsbCIsIm9uRG9uZSIsImFyZ3MiLCJ0cmltIiwiZGlzcGxheSIsInVsdHJhcGxhbkxhdW5jaFBlbmRpbmciLCJuYW1lIiwiYXJndW1lbnRIaW50IiwiaXNFbmFibGVkIiwibG9hZCIsInJlc29sdmUiXSwic291cmNlcyI6WyJ1bHRyYXBsYW4udHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJ1xuaW1wb3J0IHsgUkVNT1RFX0NPTlRST0xfRElTQ09OTkVDVEVEX01TRyB9IGZyb20gJy4uL2JyaWRnZS90eXBlcy5qcydcbmltcG9ydCB0eXBlIHsgQ29tbWFuZCB9IGZyb20gJy4uL2NvbW1hbmRzLmpzJ1xuaW1wb3J0IHsgRElBTU9ORF9PUEVOIH0gZnJvbSAnLi4vY29uc3RhbnRzL2ZpZ3VyZXMuanMnXG5pbXBvcnQgeyBnZXRSZW1vdGVTZXNzaW9uVXJsIH0gZnJvbSAnLi4vY29uc3RhbnRzL3Byb2R1Y3QuanMnXG5pbXBvcnQgeyBnZXRGZWF0dXJlVmFsdWVfQ0FDSEVEX01BWV9CRV9TVEFMRSB9IGZyb20gJy4uL3NlcnZpY2VzL2FuYWx5dGljcy9ncm93dGhib29rLmpzJ1xuaW1wb3J0IHtcbiAgdHlwZSBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICBsb2dFdmVudCxcbn0gZnJvbSAnLi4vc2VydmljZXMvYW5hbHl0aWNzL2luZGV4LmpzJ1xuaW1wb3J0IHR5cGUgeyBBcHBTdGF0ZSB9IGZyb20gJy4uL3N0YXRlL0FwcFN0YXRlU3RvcmUuanMnXG5pbXBvcnQge1xuICBjaGVja1JlbW90ZUFnZW50RWxpZ2liaWxpdHksXG4gIGZvcm1hdFByZWNvbmRpdGlvbkVycm9yLFxuICBSZW1vdGVBZ2VudFRhc2ssXG4gIHR5cGUgUmVtb3RlQWdlbnRUYXNrU3RhdGUsXG4gIHJlZ2lzdGVyUmVtb3RlQWdlbnRUYXNrLFxufSBmcm9tICcuLi90YXNrcy9SZW1vdGVBZ2VudFRhc2svUmVtb3RlQWdlbnRUYXNrLmpzJ1xuaW1wb3J0IHR5cGUgeyBMb2NhbEpTWENvbW1hbmRDYWxsIH0gZnJvbSAnLi4vdHlwZXMvY29tbWFuZC5qcydcbmltcG9ydCB7IGxvZ0ZvckRlYnVnZ2luZyB9IGZyb20gJy4uL3V0aWxzL2RlYnVnLmpzJ1xuaW1wb3J0IHsgZXJyb3JNZXNzYWdlIH0gZnJvbSAnLi4vdXRpbHMvZXJyb3JzLmpzJ1xuaW1wb3J0IHsgbG9nRXJyb3IgfSBmcm9tICcuLi91dGlscy9sb2cuanMnXG5pbXBvcnQgeyBlbnF1ZXVlUGVuZGluZ05vdGlmaWNhdGlvbiB9IGZyb20gJy4uL3V0aWxzL21lc3NhZ2VRdWV1ZU1hbmFnZXIuanMnXG5pbXBvcnQgeyBBTExfTU9ERUxfQ09ORklHUyB9IGZyb20gJy4uL3V0aWxzL21vZGVsL2NvbmZpZ3MuanMnXG5pbXBvcnQgeyB1cGRhdGVUYXNrU3RhdGUgfSBmcm9tICcuLi91dGlscy90YXNrL2ZyYW1ld29yay5qcydcbmltcG9ydCB7IGFyY2hpdmVSZW1vdGVTZXNzaW9uLCB0ZWxlcG9ydFRvUmVtb3RlIH0gZnJvbSAnLi4vdXRpbHMvdGVsZXBvcnQuanMnXG5pbXBvcnQge1xuICBwb2xsRm9yQXBwcm92ZWRFeGl0UGxhbk1vZGUsXG4gIFVsdHJhcGxhblBvbGxFcnJvcixcbn0gZnJvbSAnLi4vdXRpbHMvdWx0cmFwbGFuL2NjclNlc3Npb24uanMnXG5cbi8vIFRPRE8ocHJvZC1oYXJkZW5pbmcpOiBPQXV0aCB0b2tlbiBtYXkgZ28gc3RhbGUgb3ZlciB0aGUgMzBtaW4gcG9sbDtcbi8vIGNvbnNpZGVyIHJlZnJlc2guXG5cbi8vIE11bHRpLWFnZW50IGV4cGxvcmF0aW9uIGlzIHNsb3c7IDMwbWluIHRpbWVvdXQuXG5jb25zdCBVTFRSQVBMQU5fVElNRU9VVF9NUyA9IDMwICogNjAgKiAxMDAwXG5cbmV4cG9ydCBjb25zdCBDQ1JfVEVSTVNfVVJMID1cbiAgJ2h0dHBzOi8vY29kZS5jbGF1ZGUuY29tL2RvY3MvZW4vY2xhdWRlLWNvZGUtb24tdGhlLXdlYidcblxuLy8gQ0NSIHJ1bnMgYWdhaW5zdCB0aGUgZmlyc3QtcGFydHkgQVBJIOKAlCB1c2UgdGhlIGNhbm9uaWNhbCBJRCwgbm90IHRoZVxuLy8gcHJvdmlkZXItc3BlY2lmaWMgc3RyaW5nIGdldE1vZGVsU3RyaW5ncygpIHdvdWxkIHJldHVybiAod2hpY2ggbWF5IGJlIGFcbi8vIEJlZHJvY2sgQVJOIG9yIFZlcnRleCBJRCBvbiB0aGUgbG9jYWwgQ0xJKS4gUmVhZCBhdCBjYWxsIHRpbWUsIG5vdCBtb2R1bGVcbi8vIGxvYWQ6IHRoZSBHcm93dGhCb29rIGNhY2hlIGlzIGVtcHR5IGF0IGltcG9ydCBhbmQgYC9jb25maWdgIEdhdGVzIGNhbiBmbGlwXG4vLyBpdCBiZXR3ZWVuIGludm9jYXRpb25zLlxuZnVuY3Rpb24gZ2V0VWx0cmFwbGFuTW9kZWwoKTogc3RyaW5nIHtcbiAgcmV0dXJuIGdldEZlYXR1cmVWYWx1ZV9DQUNIRURfTUFZX0JFX1NUQUxFKFxuICAgICd0ZW5ndV91bHRyYXBsYW5fbW9kZWwnLFxuICAgIEFMTF9NT0RFTF9DT05GSUdTLm9wdXM0Ni5maXJzdFBhcnR5LFxuICApXG59XG5cbi8vIHByb21wdC50eHQgaXMgd3JhcHBlZCBpbiA8c3lzdGVtLXJlbWluZGVyPiBzbyB0aGUgQ0NSIGJyb3dzZXIgaGlkZXNcbi8vIHNjYWZmb2xkaW5nIChDTElfQkxPQ0tfVEFHUyBkcm9wcGVkIGJ5IHN0cmlwU3lzdGVtTm90aWZpY2F0aW9ucylcbi8vIHdoaWxlIHRoZSBtb2RlbCBzdGlsbCBzZWVzIGZ1bGwgdGV4dC5cbi8vIFBocmFzaW5nIGRlbGliZXJhdGVseSBhdm9pZHMgdGhlIGZlYXR1cmUgbmFtZSBiZWNhdXNlXG4vLyB0aGUgcmVtb3RlIENDUiBDTEkgcnVucyBrZXl3b3JkIGRldGVjdGlvbiBvbiByYXcgaW5wdXQgYmVmb3JlXG4vLyBhbnkgdGFnIHN0cmlwcGluZywgYW5kIGEgYmFyZSBcInVsdHJhcGxhblwiIGluIHRoZSBwcm9tcHQgd291bGQgc2VsZi10cmlnZ2VyIGFzXG4vLyAvdWx0cmFwbGFuLCB3aGljaCBpcyBmaWx0ZXJlZCBvdXQgb2YgaGVhZGxlc3MgbW9kZSBhcyBcIlVua25vd24gc2tpbGxcIlxuLy9cbi8vIEJ1bmRsZXIgaW5saW5lcyAudHh0IGFzIGEgc3RyaW5nOyB0aGUgdGVzdCBydW5uZXIgd3JhcHMgaXQgYXMge2RlZmF1bHR9LlxuLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0cyAqL1xuY29uc3QgX3Jhd1Byb21wdCA9IHJlcXVpcmUoJy4uL3V0aWxzL3VsdHJhcGxhbi9wcm9tcHQudHh0Jylcbi8qIGVzbGludC1lbmFibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0cyAqL1xuY29uc3QgREVGQVVMVF9JTlNUUlVDVElPTlM6IHN0cmluZyA9IChcbiAgdHlwZW9mIF9yYXdQcm9tcHQgPT09ICdzdHJpbmcnID8gX3Jhd1Byb21wdCA6IF9yYXdQcm9tcHQuZGVmYXVsdFxuKS50cmltRW5kKClcblxuLy8gRGV2LW9ubHkgcHJvbXB0IG92ZXJyaWRlIHJlc29sdmVkIGVhZ2VybHkgYXQgbW9kdWxlIGxvYWQuXG4vLyBHYXRlZCB0byBhbnQgYnVpbGRzIChVU0VSX1RZUEUgaXMgYSBidWlsZC10aW1lIGRlZmluZSxcbi8vIHNvIHRoZSBvdmVycmlkZSBwYXRoIGlzIERDRSdkIGZyb20gZXh0ZXJuYWwgYnVpbGRzKS5cbi8vIFNoZWxsLXNldCBlbnYgb25seSwgc28gdG9wLWxldmVsIHByb2Nlc3MuZW52IHJlYWQgaXMgZmluZVxuLy8g4oCUIHNldHRpbmdzLmVudiBuZXZlciBpbmplY3RzIHRoaXMuXG4vKiBlc2xpbnQtZGlzYWJsZSBjdXN0b20tcnVsZXMvbm8tcHJvY2Vzcy1lbnYtdG9wLWxldmVsLCBjdXN0b20tcnVsZXMvbm8tc3luYy1mcyAtLSBhbnQtb25seSBkZXYgb3ZlcnJpZGU7IGVhZ2VyIHRvcC1sZXZlbCByZWFkIGlzIHRoZSBwb2ludCAoY3Jhc2ggYXQgc3RhcnR1cCwgbm90IHNpbGVudGx5IGluc2lkZSB0aGUgc2xhc2gtY29tbWFuZCB0cnkvY2F0Y2gpICovXG5jb25zdCBVTFRSQVBMQU5fSU5TVFJVQ1RJT05TOiBzdHJpbmcgPVxuICBcImV4dGVybmFsXCIgPT09ICdhbnQnICYmIHByb2Nlc3MuZW52LlVMVFJBUExBTl9QUk9NUFRfRklMRVxuICAgID8gcmVhZEZpbGVTeW5jKHByb2Nlc3MuZW52LlVMVFJBUExBTl9QUk9NUFRfRklMRSwgJ3V0ZjgnKS50cmltRW5kKClcbiAgICA6IERFRkFVTFRfSU5TVFJVQ1RJT05TXG4vKiBlc2xpbnQtZW5hYmxlIGN1c3RvbS1ydWxlcy9uby1wcm9jZXNzLWVudi10b3AtbGV2ZWwsIGN1c3RvbS1ydWxlcy9uby1zeW5jLWZzICovXG5cbi8qKlxuICogQXNzZW1ibGUgdGhlIGluaXRpYWwgQ0NSIHVzZXIgbWVzc2FnZS4gc2VlZFBsYW4gYW5kIGJsdXJiIHN0YXkgb3V0c2lkZSB0aGVcbiAqIHN5c3RlbS1yZW1pbmRlciBzbyB0aGUgYnJvd3NlciByZW5kZXJzIHRoZW07IHNjYWZmb2xkaW5nIGlzIGhpZGRlbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkVWx0cmFwbGFuUHJvbXB0KGJsdXJiOiBzdHJpbmcsIHNlZWRQbGFuPzogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgcGFydHM6IHN0cmluZ1tdID0gW11cbiAgaWYgKHNlZWRQbGFuKSB7XG4gICAgcGFydHMucHVzaCgnSGVyZSBpcyBhIGRyYWZ0IHBsYW4gdG8gcmVmaW5lOicsICcnLCBzZWVkUGxhbiwgJycpXG4gIH1cbiAgcGFydHMucHVzaChVTFRSQVBMQU5fSU5TVFJVQ1RJT05TKVxuICBpZiAoYmx1cmIpIHtcbiAgICBwYXJ0cy5wdXNoKCcnLCBibHVyYilcbiAgfVxuICByZXR1cm4gcGFydHMuam9pbignXFxuJylcbn1cblxuZnVuY3Rpb24gc3RhcnREZXRhY2hlZFBvbGwoXG4gIHRhc2tJZDogc3RyaW5nLFxuICBzZXNzaW9uSWQ6IHN0cmluZyxcbiAgdXJsOiBzdHJpbmcsXG4gIGdldEFwcFN0YXRlOiAoKSA9PiBBcHBTdGF0ZSxcbiAgc2V0QXBwU3RhdGU6IChmOiAocHJldjogQXBwU3RhdGUpID0+IEFwcFN0YXRlKSA9PiB2b2lkLFxuKTogdm9pZCB7XG4gIGNvbnN0IHN0YXJ0ZWQgPSBEYXRlLm5vdygpXG4gIGxldCBmYWlsZWQgPSBmYWxzZVxuICB2b2lkIChhc3luYyAoKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHsgcGxhbiwgcmVqZWN0Q291bnQsIGV4ZWN1dGlvblRhcmdldCB9ID1cbiAgICAgICAgYXdhaXQgcG9sbEZvckFwcHJvdmVkRXhpdFBsYW5Nb2RlKFxuICAgICAgICAgIHNlc3Npb25JZCxcbiAgICAgICAgICBVTFRSQVBMQU5fVElNRU9VVF9NUyxcbiAgICAgICAgICBwaGFzZSA9PiB7XG4gICAgICAgICAgICBpZiAocGhhc2UgPT09ICduZWVkc19pbnB1dCcpXG4gICAgICAgICAgICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fYXdhaXRpbmdfaW5wdXQnLCB7fSlcbiAgICAgICAgICAgIHVwZGF0ZVRhc2tTdGF0ZTxSZW1vdGVBZ2VudFRhc2tTdGF0ZT4odGFza0lkLCBzZXRBcHBTdGF0ZSwgdCA9PiB7XG4gICAgICAgICAgICAgIGlmICh0LnN0YXR1cyAhPT0gJ3J1bm5pbmcnKSByZXR1cm4gdFxuICAgICAgICAgICAgICBjb25zdCBuZXh0ID0gcGhhc2UgPT09ICdydW5uaW5nJyA/IHVuZGVmaW5lZCA6IHBoYXNlXG4gICAgICAgICAgICAgIHJldHVybiB0LnVsdHJhcGxhblBoYXNlID09PSBuZXh0XG4gICAgICAgICAgICAgICAgPyB0XG4gICAgICAgICAgICAgICAgOiB7IC4uLnQsIHVsdHJhcGxhblBoYXNlOiBuZXh0IH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgfSxcbiAgICAgICAgICAoKSA9PiBnZXRBcHBTdGF0ZSgpLnRhc2tzPy5bdGFza0lkXT8uc3RhdHVzICE9PSAncnVubmluZycsXG4gICAgICAgIClcbiAgICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fYXBwcm92ZWQnLCB7XG4gICAgICAgIGR1cmF0aW9uX21zOiBEYXRlLm5vdygpIC0gc3RhcnRlZCxcbiAgICAgICAgcGxhbl9sZW5ndGg6IHBsYW4ubGVuZ3RoLFxuICAgICAgICByZWplY3RfY291bnQ6IHJlamVjdENvdW50LFxuICAgICAgICBleGVjdXRpb25fdGFyZ2V0OlxuICAgICAgICAgIGV4ZWN1dGlvblRhcmdldCBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgICAgfSlcbiAgICAgIGlmIChleGVjdXRpb25UYXJnZXQgPT09ICdyZW1vdGUnKSB7XG4gICAgICAgIC8vIFVzZXIgY2hvc2UgXCJleGVjdXRlIGluIENDUlwiIGluIHRoZSBicm93c2VyIFBsYW5Nb2RhbCDigJQgdGhlIHJlbW90ZVxuICAgICAgICAvLyBzZXNzaW9uIGlzIG5vdyBjb2RpbmcuIFNraXAgYXJjaGl2ZSAoQVJDSElWRSBoYXMgbm8gcnVubmluZy1jaGVjayxcbiAgICAgICAgLy8gd291bGQga2lsbCBtaWQtZXhlY3V0aW9uKSBhbmQgc2tpcCB0aGUgY2hvaWNlIGRpYWxvZyAoYWxyZWFkeSBjaG9zZSkuXG4gICAgICAgIC8vIEd1YXJkIG9uIHRhc2sgc3RhdHVzIHNvIGEgcG9sbCB0aGF0IHJlc29sdmVzIGFmdGVyIHN0b3BVbHRyYXBsYW5cbiAgICAgICAgLy8gZG9lc24ndCBub3RpZnkgZm9yIGEga2lsbGVkIHNlc3Npb24uXG4gICAgICAgIGNvbnN0IHRhc2sgPSBnZXRBcHBTdGF0ZSgpLnRhc2tzPy5bdGFza0lkXVxuICAgICAgICBpZiAodGFzaz8uc3RhdHVzICE9PSAncnVubmluZycpIHJldHVyblxuICAgICAgICB1cGRhdGVUYXNrU3RhdGU8UmVtb3RlQWdlbnRUYXNrU3RhdGU+KHRhc2tJZCwgc2V0QXBwU3RhdGUsIHQgPT5cbiAgICAgICAgICB0LnN0YXR1cyAhPT0gJ3J1bm5pbmcnXG4gICAgICAgICAgICA/IHRcbiAgICAgICAgICAgIDogeyAuLi50LCBzdGF0dXM6ICdjb21wbGV0ZWQnLCBlbmRUaW1lOiBEYXRlLm5vdygpIH0sXG4gICAgICAgIClcbiAgICAgICAgc2V0QXBwU3RhdGUocHJldiA9PlxuICAgICAgICAgIHByZXYudWx0cmFwbGFuU2Vzc2lvblVybCA9PT0gdXJsXG4gICAgICAgICAgICA/IHsgLi4ucHJldiwgdWx0cmFwbGFuU2Vzc2lvblVybDogdW5kZWZpbmVkIH1cbiAgICAgICAgICAgIDogcHJldixcbiAgICAgICAgKVxuICAgICAgICBlbnF1ZXVlUGVuZGluZ05vdGlmaWNhdGlvbih7XG4gICAgICAgICAgdmFsdWU6IFtcbiAgICAgICAgICAgIGBVbHRyYXBsYW4gYXBwcm92ZWQg4oCUIGV4ZWN1dGluZyBpbiBDbGF1ZGUgQ29kZSBvbiB0aGUgd2ViLiBGb2xsb3cgYWxvbmcgYXQ6ICR7dXJsfWAsXG4gICAgICAgICAgICAnJyxcbiAgICAgICAgICAgICdSZXN1bHRzIHdpbGwgbGFuZCBhcyBhIHB1bGwgcmVxdWVzdCB3aGVuIHRoZSByZW1vdGUgc2Vzc2lvbiBmaW5pc2hlcy4gVGhlcmUgaXMgbm90aGluZyB0byBkbyBoZXJlLicsXG4gICAgICAgICAgXS5qb2luKCdcXG4nKSxcbiAgICAgICAgICBtb2RlOiAndGFzay1ub3RpZmljYXRpb24nLFxuICAgICAgICB9KVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gVGVsZXBvcnQ6IHNldCBwZW5kaW5nQ2hvaWNlIHNvIFJFUEwgbW91bnRzIFVsdHJhcGxhbkNob2ljZURpYWxvZy5cbiAgICAgICAgLy8gVGhlIGRpYWxvZyBvd25zIGFyY2hpdmUgKyBVUkwgY2xlYXIgb24gY2hvaWNlLiBHdWFyZCBvbiB0YXNrIHN0YXR1c1xuICAgICAgICAvLyBzbyBhIHBvbGwgdGhhdCByZXNvbHZlcyBhZnRlciBzdG9wVWx0cmFwbGFuIGRvZXNuJ3QgcmVzdXJyZWN0IHRoZVxuICAgICAgICAvLyBkaWFsb2cgZm9yIGEga2lsbGVkIHNlc3Npb24uXG4gICAgICAgIHNldEFwcFN0YXRlKHByZXYgPT4ge1xuICAgICAgICAgIGNvbnN0IHRhc2sgPSBwcmV2LnRhc2tzPy5bdGFza0lkXVxuICAgICAgICAgIGlmICghdGFzayB8fCB0YXNrLnN0YXR1cyAhPT0gJ3J1bm5pbmcnKSByZXR1cm4gcHJldlxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAuLi5wcmV2LFxuICAgICAgICAgICAgdWx0cmFwbGFuUGVuZGluZ0Nob2ljZTogeyBwbGFuLCBzZXNzaW9uSWQsIHRhc2tJZCB9LFxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyBJZiB0aGUgdGFzayB3YXMgc3RvcHBlZCAoc3RvcFVsdHJhcGxhbiBzZXRzIHN0YXR1cz1raWxsZWQpLCB0aGUgcG9sbFxuICAgICAgLy8gZXJyb3JpbmcgaXMgZXhwZWN0ZWQg4oCUIHNraXAgdGhlIGZhaWx1cmUgbm90aWZpY2F0aW9uIGFuZCBjbGVhbnVwXG4gICAgICAvLyAoa2lsbCgpIGFscmVhZHkgYXJjaGl2ZWQ7IHN0b3BVbHRyYXBsYW4gY2xlYXJlZCB0aGUgVVJMKS5cbiAgICAgIGNvbnN0IHRhc2sgPSBnZXRBcHBTdGF0ZSgpLnRhc2tzPy5bdGFza0lkXVxuICAgICAgaWYgKHRhc2s/LnN0YXR1cyAhPT0gJ3J1bm5pbmcnKSByZXR1cm5cbiAgICAgIGZhaWxlZCA9IHRydWVcbiAgICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fZmFpbGVkJywge1xuICAgICAgICBkdXJhdGlvbl9tczogRGF0ZS5ub3coKSAtIHN0YXJ0ZWQsXG4gICAgICAgIHJlYXNvbjogKGUgaW5zdGFuY2VvZiBVbHRyYXBsYW5Qb2xsRXJyb3JcbiAgICAgICAgICA/IGUucmVhc29uXG4gICAgICAgICAgOiAnbmV0d29ya19vcl91bmtub3duJykgYXMgQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyxcbiAgICAgICAgcmVqZWN0X2NvdW50OlxuICAgICAgICAgIGUgaW5zdGFuY2VvZiBVbHRyYXBsYW5Qb2xsRXJyb3IgPyBlLnJlamVjdENvdW50IDogdW5kZWZpbmVkLFxuICAgICAgfSlcbiAgICAgIGVucXVldWVQZW5kaW5nTm90aWZpY2F0aW9uKHtcbiAgICAgICAgdmFsdWU6IGBVbHRyYXBsYW4gZmFpbGVkOiAke2Vycm9yTWVzc2FnZShlKX1cXG5cXG5TZXNzaW9uOiAke3VybH1gLFxuICAgICAgICBtb2RlOiAndGFzay1ub3RpZmljYXRpb24nLFxuICAgICAgfSlcbiAgICAgIC8vIEVycm9yIHBhdGggb3ducyBjbGVhbnVwOyB0ZWxlcG9ydCBwYXRoIGRlZmVycyB0byB0aGUgZGlhbG9nOyByZW1vdGVcbiAgICAgIC8vIHBhdGggaGFuZGxlZCBpdHMgb3duIGNsZWFudXAgYWJvdmUuXG4gICAgICB2b2lkIGFyY2hpdmVSZW1vdGVTZXNzaW9uKHNlc3Npb25JZCkuY2F0Y2goZSA9PlxuICAgICAgICBsb2dGb3JEZWJ1Z2dpbmcoYHVsdHJhcGxhbiBhcmNoaXZlIGZhaWxlZDogJHtTdHJpbmcoZSl9YCksXG4gICAgICApXG4gICAgICBzZXRBcHBTdGF0ZShwcmV2ID0+XG4gICAgICAgIC8vIENvbXBhcmUgYWdhaW5zdCB0aGlzIHBvbGwncyBVUkwgc28gYSBuZXdlciByZWxhdW5jaGVkIHNlc3Npb24nc1xuICAgICAgICAvLyBVUkwgaXNuJ3QgY2xlYXJlZCBieSBhIHN0YWxlIHBvbGwgZXJyb3Jpbmcgb3V0LlxuICAgICAgICBwcmV2LnVsdHJhcGxhblNlc3Npb25VcmwgPT09IHVybFxuICAgICAgICAgID8geyAuLi5wcmV2LCB1bHRyYXBsYW5TZXNzaW9uVXJsOiB1bmRlZmluZWQgfVxuICAgICAgICAgIDogcHJldixcbiAgICAgIClcbiAgICB9IGZpbmFsbHkge1xuICAgICAgLy8gUmVtb3RlIHBhdGggYWxyZWFkeSBzZXQgc3RhdHVzPWNvbXBsZXRlZCBhYm92ZTsgdGVsZXBvcnQgcGF0aFxuICAgICAgLy8gbGVhdmVzIHN0YXR1cz1ydW5uaW5nIHNvIHRoZSBwaWxsIHNob3dzIHRoZSB1bHRyYXBsYW5QaGFzZSBzdGF0ZVxuICAgICAgLy8gdW50aWwgVWx0cmFwbGFuQ2hvaWNlRGlhbG9nIGNvbXBsZXRlcyB0aGUgdGFzayBhZnRlciB0aGUgdXNlcidzXG4gICAgICAvLyBjaG9pY2UuIFNldHRpbmcgY29tcGxldGVkIGhlcmUgd291bGQgZmlsdGVyIHRoZSB0YXNrIG91dCBvZlxuICAgICAgLy8gaXNCYWNrZ3JvdW5kVGFzayBiZWZvcmUgdGhlIHBpbGwgY2FuIHJlbmRlciB0aGUgcGhhc2Ugc3RhdGUuXG4gICAgICAvLyBGYWlsdXJlIHBhdGggaGFzIG5vIGRpYWxvZywgc28gaXQgb3ducyB0aGUgc3RhdHVzIHRyYW5zaXRpb24gaGVyZS5cbiAgICAgIGlmIChmYWlsZWQpIHtcbiAgICAgICAgdXBkYXRlVGFza1N0YXRlPFJlbW90ZUFnZW50VGFza1N0YXRlPih0YXNrSWQsIHNldEFwcFN0YXRlLCB0ID0+XG4gICAgICAgICAgdC5zdGF0dXMgIT09ICdydW5uaW5nJ1xuICAgICAgICAgICAgPyB0XG4gICAgICAgICAgICA6IHsgLi4udCwgc3RhdHVzOiAnZmFpbGVkJywgZW5kVGltZTogRGF0ZS5ub3coKSB9LFxuICAgICAgICApXG4gICAgICB9XG4gICAgfVxuICB9KSgpXG59XG5cbi8vIFJlbmRlcnMgaW1tZWRpYXRlbHkgc28gdGhlIHRlcm1pbmFsIGRvZXNuJ3QgYXBwZWFyIGh1bmcgZHVyaW5nIHRoZVxuLy8gbXVsdGktc2Vjb25kIHRlbGVwb3J0VG9SZW1vdGUgcm91bmQtdHJpcC5cbmZ1bmN0aW9uIGJ1aWxkTGF1bmNoTWVzc2FnZShkaXNjb25uZWN0ZWRCcmlkZ2U/OiBib29sZWFuKTogc3RyaW5nIHtcbiAgY29uc3QgcHJlZml4ID0gZGlzY29ubmVjdGVkQnJpZGdlID8gYCR7UkVNT1RFX0NPTlRST0xfRElTQ09OTkVDVEVEX01TR30gYCA6ICcnXG4gIHJldHVybiBgJHtESUFNT05EX09QRU59IHVsdHJhcGxhblxcbiR7cHJlZml4fVN0YXJ0aW5nIENsYXVkZSBDb2RlIG9uIHRoZSB3ZWLigKZgXG59XG5cbmZ1bmN0aW9uIGJ1aWxkU2Vzc2lvblJlYWR5TWVzc2FnZSh1cmw6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgJHtESUFNT05EX09QRU59IHVsdHJhcGxhbiDCtyBNb25pdG9yIHByb2dyZXNzIGluIENsYXVkZSBDb2RlIG9uIHRoZSB3ZWIgJHt1cmx9XFxuWW91IGNhbiBjb250aW51ZSB3b3JraW5nIOKAlCB3aGVuIHRoZSAke0RJQU1PTkRfT1BFTn0gZmlsbHMsIHByZXNzIOKGkyB0byB2aWV3IHJlc3VsdHNgXG59XG5cbmZ1bmN0aW9uIGJ1aWxkQWxyZWFkeUFjdGl2ZU1lc3NhZ2UodXJsOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBzdHJpbmcge1xuICByZXR1cm4gdXJsXG4gICAgPyBgdWx0cmFwbGFuOiBhbHJlYWR5IHBvbGxpbmcuIE9wZW4gJHt1cmx9IHRvIGNoZWNrIHN0YXR1cywgb3Igd2FpdCBmb3IgdGhlIHBsYW4gdG8gbGFuZCBoZXJlLmBcbiAgICA6ICd1bHRyYXBsYW46IGFscmVhZHkgbGF1bmNoaW5nLiBQbGVhc2Ugd2FpdCBmb3IgdGhlIHNlc3Npb24gdG8gc3RhcnQuJ1xufVxuXG4vKipcbiAqIFN0b3AgYSBydW5uaW5nIHVsdHJhcGxhbjogYXJjaGl2ZSB0aGUgcmVtb3RlIHNlc3Npb24gKGhhbHRzIGl0IGJ1dCBrZWVwcyB0aGVcbiAqIFVSTCB2aWV3YWJsZSksIGtpbGwgdGhlIGxvY2FsIHRhc2sgZW50cnkgKGNsZWFycyB0aGUgcGlsbCksIGFuZCBjbGVhclxuICogdWx0cmFwbGFuU2Vzc2lvblVybCAocmUtYXJtcyB0aGUga2V5d29yZCB0cmlnZ2VyKS4gc3RhcnREZXRhY2hlZFBvbGwnc1xuICogc2hvdWxkU3RvcCBjYWxsYmFjayBzZWVzIHRoZSBraWxsZWQgc3RhdHVzIG9uIGl0cyBuZXh0IHRpY2sgYW5kIHRocm93cztcbiAqIHRoZSBjYXRjaCBibG9jayBlYXJseS1yZXR1cm5zIHdoZW4gc3RhdHVzICE9PSAncnVubmluZycuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdG9wVWx0cmFwbGFuKFxuICB0YXNrSWQ6IHN0cmluZyxcbiAgc2Vzc2lvbklkOiBzdHJpbmcsXG4gIHNldEFwcFN0YXRlOiAoZjogKHByZXY6IEFwcFN0YXRlKSA9PiBBcHBTdGF0ZSkgPT4gdm9pZCxcbik6IFByb21pc2U8dm9pZD4ge1xuICAvLyBSZW1vdGVBZ2VudFRhc2sua2lsbCBhcmNoaXZlcyB0aGUgc2Vzc2lvbiAod2l0aCAuY2F0Y2gpIOKAlCBubyBzZXBhcmF0ZVxuICAvLyBhcmNoaXZlIGNhbGwgbmVlZGVkIGhlcmUuXG4gIGF3YWl0IFJlbW90ZUFnZW50VGFzay5raWxsKHRhc2tJZCwgc2V0QXBwU3RhdGUpXG4gIHNldEFwcFN0YXRlKHByZXYgPT5cbiAgICBwcmV2LnVsdHJhcGxhblNlc3Npb25VcmwgfHxcbiAgICBwcmV2LnVsdHJhcGxhblBlbmRpbmdDaG9pY2UgfHxcbiAgICBwcmV2LnVsdHJhcGxhbkxhdW5jaGluZ1xuICAgICAgPyB7XG4gICAgICAgICAgLi4ucHJldixcbiAgICAgICAgICB1bHRyYXBsYW5TZXNzaW9uVXJsOiB1bmRlZmluZWQsXG4gICAgICAgICAgdWx0cmFwbGFuUGVuZGluZ0Nob2ljZTogdW5kZWZpbmVkLFxuICAgICAgICAgIHVsdHJhcGxhbkxhdW5jaGluZzogdW5kZWZpbmVkLFxuICAgICAgICB9XG4gICAgICA6IHByZXYsXG4gIClcbiAgY29uc3QgdXJsID0gZ2V0UmVtb3RlU2Vzc2lvblVybChzZXNzaW9uSWQsIHByb2Nlc3MuZW52LlNFU1NJT05fSU5HUkVTU19VUkwpXG4gIGVucXVldWVQZW5kaW5nTm90aWZpY2F0aW9uKHtcbiAgICB2YWx1ZTogYFVsdHJhcGxhbiBzdG9wcGVkLlxcblxcblNlc3Npb246ICR7dXJsfWAsXG4gICAgbW9kZTogJ3Rhc2stbm90aWZpY2F0aW9uJyxcbiAgfSlcbiAgZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24oe1xuICAgIHZhbHVlOlxuICAgICAgJ1RoZSB1c2VyIHN0b3BwZWQgdGhlIHVsdHJhcGxhbiBzZXNzaW9uIGFib3ZlLiBEbyBub3QgcmVzcG9uZCB0byB0aGUgc3RvcCBub3RpZmljYXRpb24g4oCUIHdhaXQgZm9yIHRoZWlyIG5leHQgbWVzc2FnZS4nLFxuICAgIG1vZGU6ICd0YXNrLW5vdGlmaWNhdGlvbicsXG4gICAgaXNNZXRhOiB0cnVlLFxuICB9KVxufVxuXG4vKipcbiAqIFNoYXJlZCBlbnRyeSBmb3IgdGhlIHNsYXNoIGNvbW1hbmQsIGtleXdvcmQgdHJpZ2dlciwgYW5kIHRoZSBwbGFuLWFwcHJvdmFsXG4gKiBkaWFsb2cncyBcIlVsdHJhcGxhblwiIGJ1dHRvbi4gV2hlbiBzZWVkUGxhbiBpcyBwcmVzZW50IChkaWFsb2cgcGF0aCksIGl0IGlzXG4gKiBwcmVwZW5kZWQgYXMgYSBkcmFmdCB0byByZWZpbmU7IGJsdXJiIG1heSBiZSBlbXB0eSBpbiB0aGF0IGNhc2UuXG4gKlxuICogUmVzb2x2ZXMgaW1tZWRpYXRlbHkgd2l0aCB0aGUgdXNlci1mYWNpbmcgbWVzc2FnZS4gRWxpZ2liaWxpdHkgY2hlY2ssXG4gKiBzZXNzaW9uIGNyZWF0aW9uLCBhbmQgdGFzayByZWdpc3RyYXRpb24gcnVuIGRldGFjaGVkIGFuZCBmYWlsdXJlcyBzdXJmYWNlIHZpYVxuICogZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsYXVuY2hVbHRyYXBsYW4ob3B0czoge1xuICBibHVyYjogc3RyaW5nXG4gIHNlZWRQbGFuPzogc3RyaW5nXG4gIGdldEFwcFN0YXRlOiAoKSA9PiBBcHBTdGF0ZVxuICBzZXRBcHBTdGF0ZTogKGY6IChwcmV2OiBBcHBTdGF0ZSkgPT4gQXBwU3RhdGUpID0+IHZvaWRcbiAgc2lnbmFsOiBBYm9ydFNpZ25hbFxuICAvKiogVHJ1ZSBpZiB0aGUgY2FsbGVyIGRpc2Nvbm5lY3RlZCBSZW1vdGUgQ29udHJvbCBiZWZvcmUgbGF1bmNoaW5nLiAqL1xuICBkaXNjb25uZWN0ZWRCcmlkZ2U/OiBib29sZWFuXG4gIC8qKlxuICAgKiBDYWxsZWQgb25jZSB0ZWxlcG9ydFRvUmVtb3RlIHJlc29sdmVzIHdpdGggYSBzZXNzaW9uIFVSTC4gQ2FsbGVycyB0aGF0XG4gICAqIGhhdmUgc2V0TWVzc2FnZXMgKFJFUEwpIGFwcGVuZCB0aGlzIGFzIGEgc2Vjb25kIHRyYW5zY3JpcHQgbWVzc2FnZSBzbyB0aGVcbiAgICogVVJMIGlzIHZpc2libGUgd2l0aG91dCBvcGVuaW5nIHRoZSDihpMgZGV0YWlsIHZpZXcuIENhbGxlcnMgd2l0aG91dFxuICAgKiB0cmFuc2NyaXB0IGFjY2VzcyAoRXhpdFBsYW5Nb2RlUGVybWlzc2lvblJlcXVlc3QpIG9taXQgdGhpcyDigJQgdGhlIHBpbGxcbiAgICogc3RpbGwgc2hvd3MgbGl2ZSBzdGF0dXMuXG4gICAqL1xuICBvblNlc3Npb25SZWFkeT86IChtc2c6IHN0cmluZykgPT4gdm9pZFxufSk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHtcbiAgICBibHVyYixcbiAgICBzZWVkUGxhbixcbiAgICBnZXRBcHBTdGF0ZSxcbiAgICBzZXRBcHBTdGF0ZSxcbiAgICBzaWduYWwsXG4gICAgZGlzY29ubmVjdGVkQnJpZGdlLFxuICAgIG9uU2Vzc2lvblJlYWR5LFxuICB9ID0gb3B0c1xuXG4gIGNvbnN0IHsgdWx0cmFwbGFuU2Vzc2lvblVybDogYWN0aXZlLCB1bHRyYXBsYW5MYXVuY2hpbmcgfSA9IGdldEFwcFN0YXRlKClcbiAgaWYgKGFjdGl2ZSB8fCB1bHRyYXBsYW5MYXVuY2hpbmcpIHtcbiAgICBsb2dFdmVudCgndGVuZ3VfdWx0cmFwbGFuX2NyZWF0ZV9mYWlsZWQnLCB7XG4gICAgICByZWFzb246IChhY3RpdmVcbiAgICAgICAgPyAnYWxyZWFkeV9wb2xsaW5nJ1xuICAgICAgICA6ICdhbHJlYWR5X2xhdW5jaGluZycpIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gICAgfSlcbiAgICByZXR1cm4gYnVpbGRBbHJlYWR5QWN0aXZlTWVzc2FnZShhY3RpdmUpXG4gIH1cblxuICBpZiAoIWJsdXJiICYmICFzZWVkUGxhbikge1xuICAgIC8vIE5vIGV2ZW50IOKAlCBiYXJlIC91bHRyYXBsYW4gaXMgYSB1c2FnZSBxdWVyeSwgbm90IGFuIGF0dGVtcHQuXG4gICAgcmV0dXJuIFtcbiAgICAgIC8vIFJlbmRlcmVkIHZpYSA8TWFya2Rvd24+OyByYXcgPG1lc3NhZ2U+IGlzIHRva2VuaXplZCBhcyBIVE1MXG4gICAgICAvLyBhbmQgZHJvcHBlZC4gQmFja3NsYXNoLWVzY2FwZSB0aGUgYnJhY2tldHMuXG4gICAgICAnVXNhZ2U6IC91bHRyYXBsYW4gXFxcXDxwcm9tcHRcXFxcPiwgb3IgaW5jbHVkZSBcInVsdHJhcGxhblwiIGFueXdoZXJlJyxcbiAgICAgICdpbiB5b3VyIHByb21wdCcsXG4gICAgICAnJyxcbiAgICAgICdBZHZhbmNlZCBtdWx0aS1hZ2VudCBwbGFuIG1vZGUgd2l0aCBvdXIgbW9zdCBwb3dlcmZ1bCBtb2RlbCcsXG4gICAgICAnKE9wdXMpLiBSdW5zIGluIENsYXVkZSBDb2RlIG9uIHRoZSB3ZWIuIFdoZW4gdGhlIHBsYW4gaXMgcmVhZHksJyxcbiAgICAgICd5b3UgY2FuIGV4ZWN1dGUgaXQgaW4gdGhlIHdlYiBzZXNzaW9uIG9yIHNlbmQgaXQgYmFjayBoZXJlLicsXG4gICAgICAnVGVybWluYWwgc3RheXMgZnJlZSB3aGlsZSB0aGUgcmVtb3RlIHBsYW5zLicsXG4gICAgICAnUmVxdWlyZXMgL2xvZ2luLicsXG4gICAgICAnJyxcbiAgICAgIGBUZXJtczogJHtDQ1JfVEVSTVNfVVJMfWAsXG4gICAgXS5qb2luKCdcXG4nKVxuICB9XG5cbiAgLy8gU2V0IHN5bmNocm9ub3VzbHkgYmVmb3JlIHRoZSBkZXRhY2hlZCBmbG93IHRvIHByZXZlbnQgZHVwbGljYXRlIGxhdW5jaGVzXG4gIC8vIGR1cmluZyB0aGUgdGVsZXBvcnRUb1JlbW90ZSB3aW5kb3cuXG4gIHNldEFwcFN0YXRlKHByZXYgPT5cbiAgICBwcmV2LnVsdHJhcGxhbkxhdW5jaGluZyA/IHByZXYgOiB7IC4uLnByZXYsIHVsdHJhcGxhbkxhdW5jaGluZzogdHJ1ZSB9LFxuICApXG4gIHZvaWQgbGF1bmNoRGV0YWNoZWQoe1xuICAgIGJsdXJiLFxuICAgIHNlZWRQbGFuLFxuICAgIGdldEFwcFN0YXRlLFxuICAgIHNldEFwcFN0YXRlLFxuICAgIHNpZ25hbCxcbiAgICBvblNlc3Npb25SZWFkeSxcbiAgfSlcbiAgcmV0dXJuIGJ1aWxkTGF1bmNoTWVzc2FnZShkaXNjb25uZWN0ZWRCcmlkZ2UpXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGxhdW5jaERldGFjaGVkKG9wdHM6IHtcbiAgYmx1cmI6IHN0cmluZ1xuICBzZWVkUGxhbj86IHN0cmluZ1xuICBnZXRBcHBTdGF0ZTogKCkgPT4gQXBwU3RhdGVcbiAgc2V0QXBwU3RhdGU6IChmOiAocHJldjogQXBwU3RhdGUpID0+IEFwcFN0YXRlKSA9PiB2b2lkXG4gIHNpZ25hbDogQWJvcnRTaWduYWxcbiAgb25TZXNzaW9uUmVhZHk/OiAobXNnOiBzdHJpbmcpID0+IHZvaWRcbn0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgeyBibHVyYiwgc2VlZFBsYW4sIGdldEFwcFN0YXRlLCBzZXRBcHBTdGF0ZSwgc2lnbmFsLCBvblNlc3Npb25SZWFkeSB9ID1cbiAgICBvcHRzXG4gIC8vIEhvaXN0ZWQgc28gdGhlIGNhdGNoIGJsb2NrIGNhbiBhcmNoaXZlIHRoZSByZW1vdGUgc2Vzc2lvbiBpZiBhbiBlcnJvclxuICAvLyBvY2N1cnMgYWZ0ZXIgdGVsZXBvcnRUb1JlbW90ZSBzdWNjZWVkcyAoYXZvaWRzIDMwbWluIG9ycGhhbikuXG4gIGxldCBzZXNzaW9uSWQ6IHN0cmluZyB8IHVuZGVmaW5lZFxuICB0cnkge1xuICAgIGNvbnN0IG1vZGVsID0gZ2V0VWx0cmFwbGFuTW9kZWwoKVxuXG4gICAgY29uc3QgZWxpZ2liaWxpdHkgPSBhd2FpdCBjaGVja1JlbW90ZUFnZW50RWxpZ2liaWxpdHkoKVxuICAgIGlmICghZWxpZ2liaWxpdHkuZWxpZ2libGUpIHtcbiAgICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fY3JlYXRlX2ZhaWxlZCcsIHtcbiAgICAgICAgcmVhc29uOlxuICAgICAgICAgICdwcmVjb25kaXRpb24nIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gICAgICAgIHByZWNvbmRpdGlvbl9lcnJvcnM6IGVsaWdpYmlsaXR5LmVycm9yc1xuICAgICAgICAgIC5tYXAoZSA9PiBlLnR5cGUpXG4gICAgICAgICAgLmpvaW4oXG4gICAgICAgICAgICAnLCcsXG4gICAgICAgICAgKSBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgICAgfSlcbiAgICAgIGNvbnN0IHJlYXNvbnMgPSBlbGlnaWJpbGl0eS5lcnJvcnMubWFwKGZvcm1hdFByZWNvbmRpdGlvbkVycm9yKS5qb2luKCdcXG4nKVxuICAgICAgZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24oe1xuICAgICAgICB2YWx1ZTogYHVsdHJhcGxhbjogY2Fubm90IGxhdW5jaCByZW1vdGUgc2Vzc2lvbiDigJRcXG4ke3JlYXNvbnN9YCxcbiAgICAgICAgbW9kZTogJ3Rhc2stbm90aWZpY2F0aW9uJyxcbiAgICAgIH0pXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBjb25zdCBwcm9tcHQgPSBidWlsZFVsdHJhcGxhblByb21wdChibHVyYiwgc2VlZFBsYW4pXG4gICAgbGV0IGJ1bmRsZUZhaWxNc2c6IHN0cmluZyB8IHVuZGVmaW5lZFxuICAgIGNvbnN0IHNlc3Npb24gPSBhd2FpdCB0ZWxlcG9ydFRvUmVtb3RlKHtcbiAgICAgIGluaXRpYWxNZXNzYWdlOiBwcm9tcHQsXG4gICAgICBkZXNjcmlwdGlvbjogYmx1cmIgfHwgJ1JlZmluZSBsb2NhbCBwbGFuJyxcbiAgICAgIG1vZGVsLFxuICAgICAgcGVybWlzc2lvbk1vZGU6ICdwbGFuJyxcbiAgICAgIHVsdHJhcGxhbjogdHJ1ZSxcbiAgICAgIHNpZ25hbCxcbiAgICAgIHVzZURlZmF1bHRFbnZpcm9ubWVudDogdHJ1ZSxcbiAgICAgIG9uQnVuZGxlRmFpbDogbXNnID0+IHtcbiAgICAgICAgYnVuZGxlRmFpbE1zZyA9IG1zZ1xuICAgICAgfSxcbiAgICB9KVxuICAgIGlmICghc2Vzc2lvbikge1xuICAgICAgbG9nRXZlbnQoJ3Rlbmd1X3VsdHJhcGxhbl9jcmVhdGVfZmFpbGVkJywge1xuICAgICAgICByZWFzb246IChidW5kbGVGYWlsTXNnXG4gICAgICAgICAgPyAnYnVuZGxlX2ZhaWwnXG4gICAgICAgICAgOiAndGVsZXBvcnRfbnVsbCcpIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gICAgICB9KVxuICAgICAgZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24oe1xuICAgICAgICB2YWx1ZTogYHVsdHJhcGxhbjogc2Vzc2lvbiBjcmVhdGlvbiBmYWlsZWQke2J1bmRsZUZhaWxNc2cgPyBgIOKAlCAke2J1bmRsZUZhaWxNc2d9YCA6ICcnfS4gU2VlIC0tZGVidWcgZm9yIGRldGFpbHMuYCxcbiAgICAgICAgbW9kZTogJ3Rhc2stbm90aWZpY2F0aW9uJyxcbiAgICAgIH0pXG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgc2Vzc2lvbklkID0gc2Vzc2lvbi5pZFxuXG4gICAgY29uc3QgdXJsID0gZ2V0UmVtb3RlU2Vzc2lvblVybChzZXNzaW9uLmlkLCBwcm9jZXNzLmVudi5TRVNTSU9OX0lOR1JFU1NfVVJMKVxuICAgIHNldEFwcFN0YXRlKHByZXYgPT4gKHtcbiAgICAgIC4uLnByZXYsXG4gICAgICB1bHRyYXBsYW5TZXNzaW9uVXJsOiB1cmwsXG4gICAgICB1bHRyYXBsYW5MYXVuY2hpbmc6IHVuZGVmaW5lZCxcbiAgICB9KSlcbiAgICBvblNlc3Npb25SZWFkeT8uKGJ1aWxkU2Vzc2lvblJlYWR5TWVzc2FnZSh1cmwpKVxuICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fbGF1bmNoZWQnLCB7XG4gICAgICBoYXNfc2VlZF9wbGFuOiBCb29sZWFuKHNlZWRQbGFuKSxcbiAgICAgIG1vZGVsOlxuICAgICAgICBtb2RlbCBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgIH0pXG4gICAgLy8gVE9ETygjMjM5ODUpOiByZXBsYWNlIHJlZ2lzdGVyUmVtb3RlQWdlbnRUYXNrICsgc3RhcnREZXRhY2hlZFBvbGwgd2l0aFxuICAgIC8vIEV4aXRQbGFuTW9kZVNjYW5uZXIgaW5zaWRlIHN0YXJ0UmVtb3RlU2Vzc2lvblBvbGxpbmcuXG4gICAgY29uc3QgeyB0YXNrSWQgfSA9IHJlZ2lzdGVyUmVtb3RlQWdlbnRUYXNrKHtcbiAgICAgIHJlbW90ZVRhc2tUeXBlOiAndWx0cmFwbGFuJyxcbiAgICAgIHNlc3Npb246IHsgaWQ6IHNlc3Npb24uaWQsIHRpdGxlOiBibHVyYiB8fCAnVWx0cmFwbGFuJyB9LFxuICAgICAgY29tbWFuZDogYmx1cmIsXG4gICAgICBjb250ZXh0OiB7XG4gICAgICAgIGFib3J0Q29udHJvbGxlcjogbmV3IEFib3J0Q29udHJvbGxlcigpLFxuICAgICAgICBnZXRBcHBTdGF0ZSxcbiAgICAgICAgc2V0QXBwU3RhdGUsXG4gICAgICB9LFxuICAgICAgaXNVbHRyYXBsYW46IHRydWUsXG4gICAgfSlcbiAgICBzdGFydERldGFjaGVkUG9sbCh0YXNrSWQsIHNlc3Npb24uaWQsIHVybCwgZ2V0QXBwU3RhdGUsIHNldEFwcFN0YXRlKVxuICB9IGNhdGNoIChlKSB7XG4gICAgbG9nRXJyb3IoZSlcbiAgICBsb2dFdmVudCgndGVuZ3VfdWx0cmFwbGFuX2NyZWF0ZV9mYWlsZWQnLCB7XG4gICAgICByZWFzb246XG4gICAgICAgICd1bmV4cGVjdGVkX2Vycm9yJyBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgIH0pXG4gICAgZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24oe1xuICAgICAgdmFsdWU6IGB1bHRyYXBsYW46IHVuZXhwZWN0ZWQgZXJyb3Ig4oCUICR7ZXJyb3JNZXNzYWdlKGUpfWAsXG4gICAgICBtb2RlOiAndGFzay1ub3RpZmljYXRpb24nLFxuICAgIH0pXG4gICAgaWYgKHNlc3Npb25JZCkge1xuICAgICAgLy8gRXJyb3IgYWZ0ZXIgdGVsZXBvcnQgc3VjY2VlZGVkIOKAlCBhcmNoaXZlIHNvIHRoZSByZW1vdGUgZG9lc24ndCBzaXRcbiAgICAgIC8vIHJ1bm5pbmcgZm9yIDMwbWluIHdpdGggbm9ib2R5IHBvbGxpbmcgaXQuXG4gICAgICB2b2lkIGFyY2hpdmVSZW1vdGVTZXNzaW9uKHNlc3Npb25JZCkuY2F0Y2goZXJyID0+XG4gICAgICAgIGxvZ0ZvckRlYnVnZ2luZygndWx0cmFwbGFuOiBmYWlsZWQgdG8gYXJjaGl2ZSBvcnBoYW5lZCBzZXNzaW9uJywgZXJyKSxcbiAgICAgIClcbiAgICAgIC8vIHVsdHJhcGxhblNlc3Npb25VcmwgbWF5IGhhdmUgYmVlbiBzZXQgYmVmb3JlIHRoZSB0aHJvdzsgY2xlYXIgaXQgc29cbiAgICAgIC8vIHRoZSBcImFscmVhZHkgcG9sbGluZ1wiIGd1YXJkIGRvZXNuJ3QgYmxvY2sgZnV0dXJlIGxhdW5jaGVzLlxuICAgICAgc2V0QXBwU3RhdGUocHJldiA9PlxuICAgICAgICBwcmV2LnVsdHJhcGxhblNlc3Npb25VcmxcbiAgICAgICAgICA/IHsgLi4ucHJldiwgdWx0cmFwbGFuU2Vzc2lvblVybDogdW5kZWZpbmVkIH1cbiAgICAgICAgICA6IHByZXYsXG4gICAgICApXG4gICAgfVxuICB9IGZpbmFsbHkge1xuICAgIC8vIE5vLW9wIG9uIHN1Y2Nlc3M6IHRoZSB1cmwtc2V0dGluZyBzZXRBcHBTdGF0ZSBhbHJlYWR5IGNsZWFyZWQgdGhpcy5cbiAgICBzZXRBcHBTdGF0ZShwcmV2ID0+XG4gICAgICBwcmV2LnVsdHJhcGxhbkxhdW5jaGluZ1xuICAgICAgICA/IHsgLi4ucHJldiwgdWx0cmFwbGFuTGF1bmNoaW5nOiB1bmRlZmluZWQgfVxuICAgICAgICA6IHByZXYsXG4gICAgKVxuICB9XG59XG5cbmNvbnN0IGNhbGw6IExvY2FsSlNYQ29tbWFuZENhbGwgPSBhc3luYyAob25Eb25lLCBjb250ZXh0LCBhcmdzKSA9PiB7XG4gIGNvbnN0IGJsdXJiID0gYXJncy50cmltKClcblxuICAvLyBCYXJlIC91bHRyYXBsYW4gKG5vIGFyZ3MsIG5vIHNlZWQgcGxhbikganVzdCBzaG93cyB1c2FnZSDigJQgbm8gZGlhbG9nLlxuICBpZiAoIWJsdXJiKSB7XG4gICAgY29uc3QgbXNnID0gYXdhaXQgbGF1bmNoVWx0cmFwbGFuKHtcbiAgICAgIGJsdXJiLFxuICAgICAgZ2V0QXBwU3RhdGU6IGNvbnRleHQuZ2V0QXBwU3RhdGUsXG4gICAgICBzZXRBcHBTdGF0ZTogY29udGV4dC5zZXRBcHBTdGF0ZSxcbiAgICAgIHNpZ25hbDogY29udGV4dC5hYm9ydENvbnRyb2xsZXIuc2lnbmFsLFxuICAgIH0pXG4gICAgb25Eb25lKG1zZywgeyBkaXNwbGF5OiAnc3lzdGVtJyB9KVxuICAgIHJldHVybiBudWxsXG4gIH1cblxuICAvLyBHdWFyZCBtYXRjaGVzIGxhdW5jaFVsdHJhcGxhbidzIG93biBjaGVjayDigJQgc2hvd2luZyB0aGUgZGlhbG9nIHdoZW4gYVxuICAvLyBzZXNzaW9uIGlzIGFscmVhZHkgYWN0aXZlIG9yIGxhdW5jaGluZyB3b3VsZCB3YXN0ZSB0aGUgdXNlcidzIGNsaWNrIGFuZCBzZXRcbiAgLy8gaGFzU2VlblVsdHJhcGxhblRlcm1zIGJlZm9yZSB0aGUgbGF1bmNoIGZhaWxzLlxuICBjb25zdCB7IHVsdHJhcGxhblNlc3Npb25Vcmw6IGFjdGl2ZSwgdWx0cmFwbGFuTGF1bmNoaW5nIH0gPVxuICAgIGNvbnRleHQuZ2V0QXBwU3RhdGUoKVxuICBpZiAoYWN0aXZlIHx8IHVsdHJhcGxhbkxhdW5jaGluZykge1xuICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fY3JlYXRlX2ZhaWxlZCcsIHtcbiAgICAgIHJlYXNvbjogKGFjdGl2ZVxuICAgICAgICA/ICdhbHJlYWR5X3BvbGxpbmcnXG4gICAgICAgIDogJ2FscmVhZHlfbGF1bmNoaW5nJykgYXMgQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyxcbiAgICB9KVxuICAgIG9uRG9uZShidWlsZEFscmVhZHlBY3RpdmVNZXNzYWdlKGFjdGl2ZSksIHsgZGlzcGxheTogJ3N5c3RlbScgfSlcbiAgICByZXR1cm4gbnVsbFxuICB9XG5cbiAgLy8gTW91bnQgdGhlIHByZS1sYXVuY2ggZGlhbG9nIHZpYSBmb2N1c2VkSW5wdXREaWFsb2cgKGJvdHRvbSByZWdpb24sIGxpa2VcbiAgLy8gcGVybWlzc2lvbiBkaWFsb2dzKSByYXRoZXIgdGhhbiByZXR1cm5pbmcgSlNYICh0cmFuc2NyaXB0IGFyZWEsIGFuY2hvcnNcbiAgLy8gYXQgdG9wIG9mIHNjcm9sbGJhY2spLiBSRVBMLnRzeCBoYW5kbGVzIGxhdW5jaC9jbGVhci9jYW5jZWwgb24gY2hvaWNlLlxuICBjb250ZXh0LnNldEFwcFN0YXRlKHByZXYgPT4gKHsgLi4ucHJldiwgdWx0cmFwbGFuTGF1bmNoUGVuZGluZzogeyBibHVyYiB9IH0pKVxuICAvLyAnc2tpcCcgc3VwcHJlc3NlcyB0aGUgKG5vIGNvbnRlbnQpIGVjaG8g4oCUIHRoZSBkaWFsb2cncyBjaG9pY2UgaGFuZGxlclxuICAvLyBhZGRzIHRoZSByZWFsIC91bHRyYXBsYW4gZWNobyArIGxhdW5jaCBjb25maXJtYXRpb24uXG4gIG9uRG9uZSh1bmRlZmluZWQsIHsgZGlzcGxheTogJ3NraXAnIH0pXG4gIHJldHVybiBudWxsXG59XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgdHlwZTogJ2xvY2FsLWpzeCcsXG4gIG5hbWU6ICd1bHRyYXBsYW4nLFxuICBkZXNjcmlwdGlvbjogYH4xMOKAkzMwIG1pbiDCtyBDbGF1ZGUgQ29kZSBvbiB0aGUgd2ViIGRyYWZ0cyBhbiBhZHZhbmNlZCBwbGFuIHlvdSBjYW4gZWRpdCBhbmQgYXBwcm92ZS4gU2VlICR7Q0NSX1RFUk1TX1VSTH1gLFxuICBhcmd1bWVudEhpbnQ6ICc8cHJvbXB0PicsXG4gIGlzRW5hYmxlZDogKCkgPT4gXCJleHRlcm5hbFwiID09PSAnYW50JyxcbiAgbG9hZDogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKHsgY2FsbCB9KSxcbn0gc2F0aXNmaWVzIENvbW1hbmRcbiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsWUFBWSxRQUFRLElBQUk7QUFDakMsU0FBU0MsK0JBQStCLFFBQVEsb0JBQW9CO0FBQ3BFLGNBQWNDLE9BQU8sUUFBUSxnQkFBZ0I7QUFDN0MsU0FBU0MsWUFBWSxRQUFRLHlCQUF5QjtBQUN0RCxTQUFTQyxtQkFBbUIsUUFBUSx5QkFBeUI7QUFDN0QsU0FBU0MsbUNBQW1DLFFBQVEscUNBQXFDO0FBQ3pGLFNBQ0UsS0FBS0MsMERBQTBELEVBQy9EQyxRQUFRLFFBQ0gsZ0NBQWdDO0FBQ3ZDLGNBQWNDLFFBQVEsUUFBUSwyQkFBMkI7QUFDekQsU0FDRUMsMkJBQTJCLEVBQzNCQyx1QkFBdUIsRUFDdkJDLGVBQWUsRUFDZixLQUFLQyxvQkFBb0IsRUFDekJDLHVCQUF1QixRQUNsQiw2Q0FBNkM7QUFDcEQsY0FBY0MsbUJBQW1CLFFBQVEscUJBQXFCO0FBQzlELFNBQVNDLGVBQWUsUUFB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 \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJyZWFkRmlsZVN5bmMiLCJSRU1PVEVfQ09OVFJPTF9ESVNDT05ORUNURURfTVNHIiwiQ29tbWFuZCIsIkRJQU1PTkRfT1BFTiIsImdldFJlbW90ZVNlc3Npb25VcmwiLCJnZXRGZWF0dXJlVmFsdWVfQ0FDSEVEX01BWV9CRV9TVEFMRSIsIkFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMiLCJsb2dFdmVudCIsIkFwcFN0YXRlIiwiY2hlY2tSZW1vdGVBZ2VudEVsaWdpYmlsaXR5IiwiZm9ybWF0UHJlY29uZGl0aW9uRXJyb3IiLCJSZW1vdGVBZ2VudFRhc2siLCJSZW1vdGVBZ2VudFRhc2tTdGF0ZSIsInJlZ2lzdGVyUmVtb3RlQWdlbnRUYXNrIiwiTG9jYWxKU1hDb21tYW5kQ2FsbCIsImxvZ0ZvckRlYnVnZ2luZyIsImVycm9yTWVzc2FnZSIsImxvZ0Vycm9yIiwiZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24iLCJBTExfTU9ERUxfQ09ORklHUyIsInVwZGF0ZVRhc2tTdGF0ZSIsImFyY2hpdmVSZW1vdGVTZXNzaW9uIiwidGVsZXBvcnRUb1JlbW90ZSIsInBvbGxGb3JBcHByb3ZlZEV4aXRQbGFuTW9kZSIsIlVsdHJhcGxhblBvbGxFcnJvciIsIlVMVFJBUExBTl9USU1FT1VUX01TIiwiQ0NSX1RFUk1TX1VSTCIsImdldFVsdHJhcGxhbk1vZGVsIiwib3B1czQ2IiwiZmlyc3RQYXJ0eSIsIl9yYXdQcm9tcHQiLCJyZXF1aXJlIiwiREVGQVVMVF9JTlNUUlVDVElPTlMiLCJkZWZhdWx0IiwidHJpbUVuZCIsIlVMVFJBUExBTl9JTlNUUlVDVElPTlMiLCJwcm9jZXNzIiwiZW52IiwiVUxUUkFQTEFOX1BST01QVF9GSUxFIiwiYnVpbGRVbHRyYXBsYW5Qcm9tcHQiLCJibHVyYiIsInNlZWRQbGFuIiwicGFydHMiLCJwdXNoIiwiam9pbiIsInN0YXJ0RGV0YWNoZWRQb2xsIiwidGFza0lkIiwic2Vzc2lvbklkIiwidXJsIiwiZ2V0QXBwU3RhdGUiLCJzZXRBcHBTdGF0ZSIsImYiLCJwcmV2Iiwic3RhcnRlZCIsIkRhdGUiLCJub3ciLCJmYWlsZWQiLCJwbGFuIiwicmVqZWN0Q291bnQiLCJleGVjdXRpb25UYXJnZXQiLCJwaGFzZSIsInQiLCJzdGF0dXMiLCJuZXh0IiwidW5kZWZpbmVkIiwidWx0cmFwbGFuUGhhc2UiLCJ0YXNrcyIsImR1cmF0aW9uX21zIiwicGxhbl9sZW5ndGgiLCJsZW5ndGgiLCJyZWplY3RfY291bnQiLCJleGVjdXRpb25fdGFyZ2V0IiwidGFzayIsImVuZFRpbWUiLCJ1bHRyYXBsYW5TZXNzaW9uVXJsIiwidmFsdWUiLCJtb2RlIiwidWx0cmFwbGFuUGVuZGluZ0Nob2ljZSIsImUiLCJyZWFzb24iLCJjYXRjaCIsIlN0cmluZyIsImJ1aWxkTGF1bmNoTWVzc2FnZSIsImRpc2Nvbm5lY3RlZEJyaWRnZSIsInByZWZpeCIsImJ1aWxkU2Vzc2lvblJlYWR5TWVzc2FnZSIsImJ1aWxkQWxyZWFkeUFjdGl2ZU1lc3NhZ2UiLCJzdG9wVWx0cmFwbGFuIiwiUHJvbWlzZSIsImtpbGwiLCJ1bHRyYXBsYW5MYXVuY2hpbmciLCJTRVNTSU9OX0lOR1JFU1NfVVJMIiwiaXNNZXRhIiwibGF1bmNoVWx0cmFwbGFuIiwib3B0cyIsInNpZ25hbCIsIkFib3J0U2lnbmFsIiwib25TZXNzaW9uUmVhZHkiLCJtc2ciLCJhY3RpdmUiLCJsYXVuY2hEZXRhY2hlZCIsIm1vZGVsIiwiZWxpZ2liaWxpdHkiLCJlbGlnaWJsZSIsInByZWNvbmRpdGlvbl9lcnJvcnMiLCJlcnJvcnMiLCJtYXAiLCJ0eXBlIiwicmVhc29ucyIsInByb21wdCIsImJ1bmRsZUZhaWxNc2ciLCJzZXNzaW9uIiwiaW5pdGlhbE1lc3NhZ2UiLCJkZXNjcmlwdGlvbiIsInBlcm1pc3Npb25Nb2RlIiwidWx0cmFwbGFuIiwidXNlRGVmYXVsdEVudmlyb25tZW50Iiwib25CdW5kbGVGYWlsIiwiaWQiLCJoYXNfc2VlZF9wbGFuIiwiQm9vbGVhbiIsInJlbW90ZVRhc2tUeXBlIiwidGl0bGUiLCJjb21tYW5kIiwiY29udGV4dCIsImFib3J0Q29udHJvbGxlciIsIkFib3J0Q29udHJvbGxlciIsImlzVWx0cmFwbGFuIiwiZXJyIiwiY2FsbCIsIm9uRG9uZSIsImFyZ3MiLCJ0cmltIiwiZGlzcGxheSIsInVsdHJhcGxhbkxhdW5jaFBlbmRpbmciLCJuYW1lIiwiYXJndW1lbnRIaW50IiwiaXNFbmFibGVkIiwibG9hZCIsInJlc29sdmUiXSwic291cmNlcyI6WyJ1bHRyYXBsYW4udHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJ1xuaW1wb3J0IHsgUkVNT1RFX0NPTlRST0xfRElTQ09OTkVDVEVEX01TRyB9IGZyb20gJy4uL2JyaWRnZS90eXBlcy5qcydcbmltcG9ydCB0eXBlIHsgQ29tbWFuZCB9IGZyb20gJy4uL2NvbW1hbmRzLmpzJ1xuaW1wb3J0IHsgRElBTU9ORF9PUEVOIH0gZnJvbSAnLi4vY29uc3RhbnRzL2ZpZ3VyZXMuanMnXG5pbXBvcnQgeyBnZXRSZW1vdGVTZXNzaW9uVXJsIH0gZnJvbSAnLi4vY29uc3RhbnRzL3Byb2R1Y3QuanMnXG5pbXBvcnQgeyBnZXRGZWF0dXJlVmFsdWVfQ0FDSEVEX01BWV9CRV9TVEFMRSB9IGZyb20gJy4uL3NlcnZpY2VzL2FuYWx5dGljcy9ncm93dGhib29rLmpzJ1xuaW1wb3J0IHtcbiAgdHlwZSBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICBsb2dFdmVudCxcbn0gZnJvbSAnLi4vc2VydmljZXMvYW5hbHl0aWNzL2luZGV4LmpzJ1xuaW1wb3J0IHR5cGUgeyBBcHBTdGF0ZSB9IGZyb20gJy4uL3N0YXRlL0FwcFN0YXRlU3RvcmUuanMnXG5pbXBvcnQge1xuICBjaGVja1JlbW90ZUFnZW50RWxpZ2liaWxpdHksXG4gIGZvcm1hdFByZWNvbmRpdGlvbkVycm9yLFxuICBSZW1vdGVBZ2VudFRhc2ssXG4gIHR5cGUgUmVtb3RlQWdlbnRUYXNrU3RhdGUsXG4gIHJlZ2lzdGVyUmVtb3RlQWdlbnRUYXNrLFxufSBmcm9tICcuLi90YXNrcy9SZW1vdGVBZ2VudFRhc2svUmVtb3RlQWdlbnRUYXNrLmpzJ1xuaW1wb3J0IHR5cGUgeyBMb2NhbEpTWENvbW1hbmRDYWxsIH0gZnJvbSAnLi4vdHlwZXMvY29tbWFuZC5qcydcbmltcG9ydCB7IGxvZ0ZvckRlYnVnZ2luZyB9IGZyb20gJy4uL3V0aWxzL2RlYnVnLmpzJ1xuaW1wb3J0IHsgZXJyb3JNZXNzYWdlIH0gZnJvbSAnLi4vdXRpbHMvZXJyb3JzLmpzJ1xuaW1wb3J0IHsgbG9nRXJyb3IgfSBmcm9tICcuLi91dGlscy9sb2cuanMnXG5pbXBvcnQgeyBlbnF1ZXVlUGVuZGluZ05vdGlmaWNhdGlvbiB9IGZyb20gJy4uL3V0aWxzL21lc3NhZ2VRdWV1ZU1hbmFnZXIuanMnXG5pbXBvcnQgeyBBTExfTU9ERUxfQ09ORklHUyB9IGZyb20gJy4uL3V0aWxzL21vZGVsL2NvbmZpZ3MuanMnXG5pbXBvcnQgeyB1cGRhdGVUYXNrU3RhdGUgfSBmcm9tICcuLi91dGlscy90YXNrL2ZyYW1ld29yay5qcydcbmltcG9ydCB7IGFyY2hpdmVSZW1vdGVTZXNzaW9uLCB0ZWxlcG9ydFRvUmVtb3RlIH0gZnJvbSAnLi4vdXRpbHMvdGVsZXBvcnQuanMnXG5pbXBvcnQge1xuICBwb2xsRm9yQXBwcm92ZWRFeGl0UGxhbk1vZGUsXG4gIFVsdHJhcGxhblBvbGxFcnJvcixcbn0gZnJvbSAnLi4vdXRpbHMvdWx0cmFwbGFuL2NjclNlc3Npb24uanMnXG5cbi8vIFRPRE8ocHJvZC1oYXJkZW5pbmcpOiBPQXV0aCB0b2tlbiBtYXkgZ28gc3RhbGUgb3ZlciB0aGUgMzBtaW4gcG9sbDtcbi8vIGNvbnNpZGVyIHJlZnJlc2guXG5cbi8vIE11bHRpLWFnZW50IGV4cGxvcmF0aW9uIGlzIHNsb3c7IDMwbWluIHRpbWVvdXQuXG5jb25zdCBVTFRSQVBMQU5fVElNRU9VVF9NUyA9IDMwICogNjAgKiAxMDAwXG5cbmV4cG9ydCBjb25zdCBDQ1JfVEVSTVNfVVJMID1cbiAgJ2h0dHBzOi8vY29kZS5jbGF1ZGUuY29tL2RvY3MvZW4vY2xhdWRlLWNvZGUtb24tdGhlLXdlYidcblxuLy8gQ0NSIHJ1bnMgYWdhaW5zdCB0aGUgZmlyc3QtcGFydHkgQVBJIOKAlCB1c2UgdGhlIGNhbm9uaWNhbCBJRCwgbm90IHRoZVxuLy8gcHJvdmlkZXItc3BlY2lmaWMgc3RyaW5nIGdldE1vZGVsU3RyaW5ncygpIHdvdWxkIHJldHVybiAod2hpY2ggbWF5IGJlIGFcbi8vIEJlZHJvY2sgQVJOIG9yIFZlcnRleCBJRCBvbiB0aGUgbG9jYWwgQ0xJKS4gUmVhZCBhdCBjYWxsIHRpbWUsIG5vdCBtb2R1bGVcbi8vIGxvYWQ6IHRoZSBHcm93dGhCb29rIGNhY2hlIGlzIGVtcHR5IGF0IGltcG9ydCBhbmQgYC9jb25maWdgIEdhdGVzIGNhbiBmbGlwXG4vLyBpdCBiZXR3ZWVuIGludm9jYXRpb25zLlxuZnVuY3Rpb24gZ2V0VWx0cmFwbGFuTW9kZWwoKTogc3RyaW5nIHtcbiAgcmV0dXJuIGdldEZlYXR1cmVWYWx1ZV9DQUNIRURfTUFZX0JFX1NUQUxFKFxuICAgICd0ZW5ndV91bHRyYXBsYW5fbW9kZWwnLFxuICAgIEFMTF9NT0RFTF9DT05GSUdTLm9wdXM0Ni5maXJzdFBhcnR5LFxuICApXG59XG5cbi8vIHByb21wdC50eHQgaXMgd3JhcHBlZCBpbiA8c3lzdGVtLXJlbWluZGVyPiBzbyB0aGUgQ0NSIGJyb3dzZXIgaGlkZXNcbi8vIHNjYWZmb2xkaW5nIChDTElfQkxPQ0tfVEFHUyBkcm9wcGVkIGJ5IHN0cmlwU3lzdGVtTm90aWZpY2F0aW9ucylcbi8vIHdoaWxlIHRoZSBtb2RlbCBzdGlsbCBzZWVzIGZ1bGwgdGV4dC5cbi8vIFBocmFzaW5nIGRlbGliZXJhdGVseSBhdm9pZHMgdGhlIGZlYXR1cmUgbmFtZSBiZWNhdXNlXG4vLyB0aGUgcmVtb3RlIENDUiBDTEkgcnVucyBrZXl3b3JkIGRldGVjdGlvbiBvbiByYXcgaW5wdXQgYmVmb3JlXG4vLyBhbnkgdGFnIHN0cmlwcGluZywgYW5kIGEgYmFyZSBcInVsdHJhcGxhblwiIGluIHRoZSBwcm9tcHQgd291bGQgc2VsZi10cmlnZ2VyIGFzXG4vLyAvdWx0cmFwbGFuLCB3aGljaCBpcyBmaWx0ZXJlZCBvdXQgb2YgaGVhZGxlc3MgbW9kZSBhcyBcIlVua25vd24gc2tpbGxcIlxuLy9cbi8vIEJ1bmRsZXIgaW5saW5lcyAudHh0IGFzIGEgc3RyaW5nOyB0aGUgdGVzdCBydW5uZXIgd3JhcHMgaXQgYXMge2RlZmF1bHR9LlxuLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0cyAqL1xuY29uc3QgX3Jhd1Byb21wdCA9IHJlcXVpcmUoJy4uL3V0aWxzL3VsdHJhcGxhbi9wcm9tcHQudHh0Jylcbi8qIGVzbGludC1lbmFibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0cyAqL1xuY29uc3QgREVGQVVMVF9JTlNUUlVDVElPTlM6IHN0cmluZyA9IChcbiAgdHlwZW9mIF9yYXdQcm9tcHQgPT09ICdzdHJpbmcnID8gX3Jhd1Byb21wdCA6IF9yYXdQcm9tcHQuZGVmYXVsdFxuKS50cmltRW5kKClcblxuLy8gRGV2LW9ubHkgcHJvbXB0IG92ZXJyaWRlIHJlc29sdmVkIGVhZ2VybHkgYXQgbW9kdWxlIGxvYWQuXG4vLyBHYXRlZCB0byBhbnQgYnVpbGRzIChVU0VSX1RZUEUgaXMgYSBidWlsZC10aW1lIGRlZmluZSxcbi8vIHNvIHRoZSBvdmVycmlkZSBwYXRoIGlzIERDRSdkIGZyb20gZXh0ZXJuYWwgYnVpbGRzKS5cbi8vIFNoZWxsLXNldCBlbnYgb25seSwgc28gdG9wLWxldmVsIHByb2Nlc3MuZW52IHJlYWQgaXMgZmluZVxuLy8g4oCUIHNldHRpbmdzLmVudiBuZXZlciBpbmplY3RzIHRoaXMuXG4vKiBlc2xpbnQtZGlzYWJsZSBjdXN0b20tcnVsZXMvbm8tcHJvY2Vzcy1lbnYtdG9wLWxldmVsLCBjdXN0b20tcnVsZXMvbm8tc3luYy1mcyAtLSBhbnQtb25seSBkZXYgb3ZlcnJpZGU7IGVhZ2VyIHRvcC1sZXZlbCByZWFkIGlzIHRoZSBwb2ludCAoY3Jhc2ggYXQgc3RhcnR1cCwgbm90IHNpbGVudGx5IGluc2lkZSB0aGUgc2xhc2gtY29tbWFuZCB0cnkvY2F0Y2gpICovXG5jb25zdCBVTFRSQVBMQU5fSU5TVFJVQ1RJT05TOiBzdHJpbmcgPVxuICBcImV4dGVybmFsXCIgPT09ICdhbnQnICYmIHByb2Nlc3MuZW52LlVMVFJBUExBTl9QUk9NUFRfRklMRVxuICAgID8gcmVhZEZpbGVTeW5jKHByb2Nlc3MuZW52LlVMVFJBUExBTl9QUk9NUFRfRklMRSwgJ3V0ZjgnKS50cmltRW5kKClcbiAgICA6IERFRkFVTFRfSU5TVFJVQ1RJT05TXG4vKiBlc2xpbnQtZW5hYmxlIGN1c3RvbS1ydWxlcy9uby1wcm9jZXNzLWVudi10b3AtbGV2ZWwsIGN1c3RvbS1ydWxlcy9uby1zeW5jLWZzICovXG5cbi8qKlxuICogQXNzZW1ibGUgdGhlIGluaXRpYWwgQ0NSIHVzZXIgbWVzc2FnZS4gc2VlZFBsYW4gYW5kIGJsdXJiIHN0YXkgb3V0c2lkZSB0aGVcbiAqIHN5c3RlbS1yZW1pbmRlciBzbyB0aGUgYnJvd3NlciByZW5kZXJzIHRoZW07IHNjYWZmb2xkaW5nIGlzIGhpZGRlbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkVWx0cmFwbGFuUHJvbXB0KGJsdXJiOiBzdHJpbmcsIHNlZWRQbGFuPzogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgcGFydHM6IHN0cmluZ1tdID0gW11cbiAgaWYgKHNlZWRQbGFuKSB7XG4gICAgcGFydHMucHVzaCgnSGVyZSBpcyBhIGRyYWZ0IHBsYW4gdG8gcmVmaW5lOicsICcnLCBzZWVkUGxhbiwgJycpXG4gIH1cbiAgcGFydHMucHVzaChVTFRSQVBMQU5fSU5TVFJVQ1RJT05TKVxuICBpZiAoYmx1cmIpIHtcbiAgICBwYXJ0cy5wdXNoKCcnLCBibHVyYilcbiAgfVxuICByZXR1cm4gcGFydHMuam9pbignXFxuJylcbn1cblxuZnVuY3Rpb24gc3RhcnREZXRhY2hlZFBvbGwoXG4gIHRhc2tJZDogc3RyaW5nLFxuICBzZXNzaW9uSWQ6IHN0cmluZyxcbiAgdXJsOiBzdHJpbmcsXG4gIGdldEFwcFN0YXRlOiAoKSA9PiBBcHBTdGF0ZSxcbiAgc2V0QXBwU3RhdGU6IChmOiAocHJldjogQXBwU3RhdGUpID0+IEFwcFN0YXRlKSA9PiB2b2lkLFxuKTogdm9pZCB7XG4gIGNvbnN0IHN0YXJ0ZWQgPSBEYXRlLm5vdygpXG4gIGxldCBmYWlsZWQgPSBmYWxzZVxuICB2b2lkIChhc3luYyAoKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHsgcGxhbiwgcmVqZWN0Q291bnQsIGV4ZWN1dGlvblRhcmdldCB9ID1cbiAgICAgICAgYXdhaXQgcG9sbEZvckFwcHJvdmVkRXhpdFBsYW5Nb2RlKFxuICAgICAgICAgIHNlc3Npb25JZCxcbiAgICAgICAgICBVTFRSQVBMQU5fVElNRU9VVF9NUyxcbiAgICAgICAgICBwaGFzZSA9PiB7XG4gICAgICAgICAgICBpZiAocGhhc2UgPT09ICduZWVkc19pbnB1dCcpXG4gICAgICAgICAgICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fYXdhaXRpbmdfaW5wdXQnLCB7fSlcbiAgICAgICAgICAgIHVwZGF0ZVRhc2tTdGF0ZTxSZW1vdGVBZ2VudFRhc2tTdGF0ZT4odGFza0lkLCBzZXRBcHBTdGF0ZSwgdCA9PiB7XG4gICAgICAgICAgICAgIGlmICh0LnN0YXR1cyAhPT0gJ3J1bm5pbmcnKSByZXR1cm4gdFxuICAgICAgICAgICAgICBjb25zdCBuZXh0ID0gcGhhc2UgPT09ICdydW5uaW5nJyA/IHVuZGVmaW5lZCA6IHBoYXNlXG4gICAgICAgICAgICAgIHJldHVybiB0LnVsdHJhcGxhblBoYXNlID09PSBuZXh0XG4gICAgICAgICAgICAgICAgPyB0XG4gICAgICAgICAgICAgICAgOiB7IC4uLnQsIHVsdHJhcGxhblBoYXNlOiBuZXh0IH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgfSxcbiAgICAgICAgICAoKSA9PiBnZXRBcHBTdGF0ZSgpLnRhc2tzPy5bdGFza0lkXT8uc3RhdHVzICE9PSAncnVubmluZycsXG4gICAgICAgIClcbiAgICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fYXBwcm92ZWQnLCB7XG4gICAgICAgIGR1cmF0aW9uX21zOiBEYXRlLm5vdygpIC0gc3RhcnRlZCxcbiAgICAgICAgcGxhbl9sZW5ndGg6IHBsYW4ubGVuZ3RoLFxuICAgICAgICByZWplY3RfY291bnQ6IHJlamVjdENvdW50LFxuICAgICAgICBleGVjdXRpb25fdGFyZ2V0OlxuICAgICAgICAgIGV4ZWN1dGlvblRhcmdldCBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgICAgfSlcbiAgICAgIGlmIChleGVjdXRpb25UYXJnZXQgPT09ICdyZW1vdGUnKSB7XG4gICAgICAgIC8vIFVzZXIgY2hvc2UgXCJleGVjdXRlIGluIENDUlwiIGluIHRoZSBicm93c2VyIFBsYW5Nb2RhbCDigJQgdGhlIHJlbW90ZVxuICAgICAgICAvLyBzZXNzaW9uIGlzIG5vdyBjb2RpbmcuIFNraXAgYXJjaGl2ZSAoQVJDSElWRSBoYXMgbm8gcnVubmluZy1jaGVjayxcbiAgICAgICAgLy8gd291bGQga2lsbCBtaWQtZXhlY3V0aW9uKSBhbmQgc2tpcCB0aGUgY2hvaWNlIGRpYWxvZyAoYWxyZWFkeSBjaG9zZSkuXG4gICAgICAgIC8vIEd1YXJkIG9uIHRhc2sgc3RhdHVzIHNvIGEgcG9sbCB0aGF0IHJlc29sdmVzIGFmdGVyIHN0b3BVbHRyYXBsYW5cbiAgICAgICAgLy8gZG9lc24ndCBub3RpZnkgZm9yIGEga2lsbGVkIHNlc3Npb24uXG4gICAgICAgIGNvbnN0IHRhc2sgPSBnZXRBcHBTdGF0ZSgpLnRhc2tzPy5bdGFza0lkXVxuICAgICAgICBpZiAodGFzaz8uc3RhdHVzICE9PSAncnVubmluZycpIHJldHVyblxuICAgICAgICB1cGRhdGVUYXNrU3RhdGU8UmVtb3RlQWdlbnRUYXNrU3RhdGU+KHRhc2tJZCwgc2V0QXBwU3RhdGUsIHQgPT5cbiAgICAgICAgICB0LnN0YXR1cyAhPT0gJ3J1bm5pbmcnXG4gICAgICAgICAgICA/IHRcbiAgICAgICAgICAgIDogeyAuLi50LCBzdGF0dXM6ICdjb21wbGV0ZWQnLCBlbmRUaW1lOiBEYXRlLm5vdygpIH0sXG4gICAgICAgIClcbiAgICAgICAgc2V0QXBwU3RhdGUocHJldiA9PlxuICAgICAgICAgIHByZXYudWx0cmFwbGFuU2Vzc2lvblVybCA9PT0gdXJsXG4gICAgICAgICAgICA/IHsgLi4ucHJldiwgdWx0cmFwbGFuU2Vzc2lvblVybDogdW5kZWZpbmVkIH1cbiAgICAgICAgICAgIDogcHJldixcbiAgICAgICAgKVxuICAgICAgICBlbnF1ZXVlUGVuZGluZ05vdGlmaWNhdGlvbih7XG4gICAgICAgICAgdmFsdWU6IFtcbiAgICAgICAgICAgIGBVbHRyYXBsYW4gYXBwcm92ZWQg4oCUIGV4ZWN1dGluZyBpbiBDbGF1ZGUgQ29kZSBvbiB0aGUgd2ViLiBGb2xsb3cgYWxvbmcgYXQ6ICR7dXJsfWAsXG4gICAgICAgICAgICAnJyxcbiAgICAgICAgICAgICdSZXN1bHRzIHdpbGwgbGFuZCBhcyBhIHB1bGwgcmVxdWVzdCB3aGVuIHRoZSByZW1vdGUgc2Vzc2lvbiBmaW5pc2hlcy4gVGhlcmUgaXMgbm90aGluZyB0byBkbyBoZXJlLicsXG4gICAgICAgICAgXS5qb2luKCdcXG4nKSxcbiAgICAgICAgICBtb2RlOiAndGFzay1ub3RpZmljYXRpb24nLFxuICAgICAgICB9KVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gVGVsZXBvcnQ6IHNldCBwZW5kaW5nQ2hvaWNlIHNvIFJFUEwgbW91bnRzIFVsdHJhcGxhbkNob2ljZURpYWxvZy5cbiAgICAgICAgLy8gVGhlIGRpYWxvZyBvd25zIGFyY2hpdmUgKyBVUkwgY2xlYXIgb24gY2hvaWNlLiBHdWFyZCBvbiB0YXNrIHN0YXR1c1xuICAgICAgICAvLyBzbyBhIHBvbGwgdGhhdCByZXNvbHZlcyBhZnRlciBzdG9wVWx0cmFwbGFuIGRvZXNuJ3QgcmVzdXJyZWN0IHRoZVxuICAgICAgICAvLyBkaWFsb2cgZm9yIGEga2lsbGVkIHNlc3Npb24uXG4gICAgICAgIHNldEFwcFN0YXRlKHByZXYgPT4ge1xuICAgICAgICAgIGNvbnN0IHRhc2sgPSBwcmV2LnRhc2tzPy5bdGFza0lkXVxuICAgICAgICAgIGlmICghdGFzayB8fCB0YXNrLnN0YXR1cyAhPT0gJ3J1bm5pbmcnKSByZXR1cm4gcHJldlxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAuLi5wcmV2LFxuICAgICAgICAgICAgdWx0cmFwbGFuUGVuZGluZ0Nob2ljZTogeyBwbGFuLCBzZXNzaW9uSWQsIHRhc2tJZCB9LFxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyBJZiB0aGUgdGFzayB3YXMgc3RvcHBlZCAoc3RvcFVsdHJhcGxhbiBzZXRzIHN0YXR1cz1raWxsZWQpLCB0aGUgcG9sbFxuICAgICAgLy8gZXJyb3JpbmcgaXMgZXhwZWN0ZWQg4oCUIHNraXAgdGhlIGZhaWx1cmUgbm90aWZpY2F0aW9uIGFuZCBjbGVhbnVwXG4gICAgICAvLyAoa2lsbCgpIGFscmVhZHkgYXJjaGl2ZWQ7IHN0b3BVbHRyYXBsYW4gY2xlYXJlZCB0aGUgVVJMKS5cbiAgICAgIGNvbnN0IHRhc2sgPSBnZXRBcHBTdGF0ZSgpLnRhc2tzPy5bdGFza0lkXVxuICAgICAgaWYgKHRhc2s/LnN0YXR1cyAhPT0gJ3J1bm5pbmcnKSByZXR1cm5cbiAgICAgIGZhaWxlZCA9IHRydWVcbiAgICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fZmFpbGVkJywge1xuICAgICAgICBkdXJhdGlvbl9tczogRGF0ZS5ub3coKSAtIHN0YXJ0ZWQsXG4gICAgICAgIHJlYXNvbjogKGUgaW5zdGFuY2VvZiBVbHRyYXBsYW5Qb2xsRXJyb3JcbiAgICAgICAgICA/IGUucmVhc29uXG4gICAgICAgICAgOiAnbmV0d29ya19vcl91bmtub3duJykgYXMgQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyxcbiAgICAgICAgcmVqZWN0X2NvdW50OlxuICAgICAgICAgIGUgaW5zdGFuY2VvZiBVbHRyYXBsYW5Qb2xsRXJyb3IgPyBlLnJlamVjdENvdW50IDogdW5kZWZpbmVkLFxuICAgICAgfSlcbiAgICAgIGVucXVldWVQZW5kaW5nTm90aWZpY2F0aW9uKHtcbiAgICAgICAgdmFsdWU6IGBVbHRyYXBsYW4gZmFpbGVkOiAke2Vycm9yTWVzc2FnZShlKX1cXG5cXG5TZXNzaW9uOiAke3VybH1gLFxuICAgICAgICBtb2RlOiAndGFzay1ub3RpZmljYXRpb24nLFxuICAgICAgfSlcbiAgICAgIC8vIEVycm9yIHBhdGggb3ducyBjbGVhbnVwOyB0ZWxlcG9ydCBwYXRoIGRlZmVycyB0byB0aGUgZGlhbG9nOyByZW1vdGVcbiAgICAgIC8vIHBhdGggaGFuZGxlZCBpdHMgb3duIGNsZWFudXAgYWJvdmUuXG4gICAgICB2b2lkIGFyY2hpdmVSZW1vdGVTZXNzaW9uKHNlc3Npb25JZCkuY2F0Y2goZSA9PlxuICAgICAgICBsb2dGb3JEZWJ1Z2dpbmcoYHVsdHJhcGxhbiBhcmNoaXZlIGZhaWxlZDogJHtTdHJpbmcoZSl9YCksXG4gICAgICApXG4gICAgICBzZXRBcHBTdGF0ZShwcmV2ID0+XG4gICAgICAgIC8vIENvbXBhcmUgYWdhaW5zdCB0aGlzIHBvbGwncyBVUkwgc28gYSBuZXdlciByZWxhdW5jaGVkIHNlc3Npb24nc1xuICAgICAgICAvLyBVUkwgaXNuJ3QgY2xlYXJlZCBieSBhIHN0YWxlIHBvbGwgZXJyb3Jpbmcgb3V0LlxuICAgICAgICBwcmV2LnVsdHJhcGxhblNlc3Npb25VcmwgPT09IHVybFxuICAgICAgICAgID8geyAuLi5wcmV2LCB1bHRyYXBsYW5TZXNzaW9uVXJsOiB1bmRlZmluZWQgfVxuICAgICAgICAgIDogcHJldixcbiAgICAgIClcbiAgICB9IGZpbmFsbHkge1xuICAgICAgLy8gUmVtb3RlIHBhdGggYWxyZWFkeSBzZXQgc3RhdHVzPWNvbXBsZXRlZCBhYm92ZTsgdGVsZXBvcnQgcGF0aFxuICAgICAgLy8gbGVhdmVzIHN0YXR1cz1ydW5uaW5nIHNvIHRoZSBwaWxsIHNob3dzIHRoZSB1bHRyYXBsYW5QaGFzZSBzdGF0ZVxuICAgICAgLy8gdW50aWwgVWx0cmFwbGFuQ2hvaWNlRGlhbG9nIGNvbXBsZXRlcyB0aGUgdGFzayBhZnRlciB0aGUgdXNlcidzXG4gICAgICAvLyBjaG9pY2UuIFNldHRpbmcgY29tcGxldGVkIGhlcmUgd291bGQgZmlsdGVyIHRoZSB0YXNrIG91dCBvZlxuICAgICAgLy8gaXNCYWNrZ3JvdW5kVGFzayBiZWZvcmUgdGhlIHBpbGwgY2FuIHJlbmRlciB0aGUgcGhhc2Ugc3RhdGUuXG4gICAgICAvLyBGYWlsdXJlIHBhdGggaGFzIG5vIGRpYWxvZywgc28gaXQgb3ducyB0aGUgc3RhdHVzIHRyYW5zaXRpb24gaGVyZS5cbiAgICAgIGlmIChmYWlsZWQpIHtcbiAgICAgICAgdXBkYXRlVGFza1N0YXRlPFJlbW90ZUFnZW50VGFza1N0YXRlPih0YXNrSWQsIHNldEFwcFN0YXRlLCB0ID0+XG4gICAgICAgICAgdC5zdGF0dXMgIT09ICdydW5uaW5nJ1xuICAgICAgICAgICAgPyB0XG4gICAgICAgICAgICA6IHsgLi4udCwgc3RhdHVzOiAnZmFpbGVkJywgZW5kVGltZTogRGF0ZS5ub3coKSB9LFxuICAgICAgICApXG4gICAgICB9XG4gICAgfVxuICB9KSgpXG59XG5cbi8vIFJlbmRlcnMgaW1tZWRpYXRlbHkgc28gdGhlIHRlcm1pbmFsIGRvZXNuJ3QgYXBwZWFyIGh1bmcgZHVyaW5nIHRoZVxuLy8gbXVsdGktc2Vjb25kIHRlbGVwb3J0VG9SZW1vdGUgcm91bmQtdHJpcC5cbmZ1bmN0aW9uIGJ1aWxkTGF1bmNoTWVzc2FnZShkaXNjb25uZWN0ZWRCcmlkZ2U/OiBib29sZWFuKTogc3RyaW5nIHtcbiAgY29uc3QgcHJlZml4ID0gZGlzY29ubmVjdGVkQnJpZGdlID8gYCR7UkVNT1RFX0NPTlRST0xfRElTQ09OTkVDVEVEX01TR30gYCA6ICcnXG4gIHJldHVybiBgJHtESUFNT05EX09QRU59IHVsdHJhcGxhblxcbiR7cHJlZml4fVN0YXJ0aW5nIENsYXVkZSBDb2RlIG9uIHRoZSB3ZWLigKZgXG59XG5cbmZ1bmN0aW9uIGJ1aWxkU2Vzc2lvblJlYWR5TWVzc2FnZSh1cmw6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgJHtESUFNT05EX09QRU59IHVsdHJhcGxhbiDCtyBNb25pdG9yIHByb2dyZXNzIGluIENsYXVkZSBDb2RlIG9uIHRoZSB3ZWIgJHt1cmx9XFxuWW91IGNhbiBjb250aW51ZSB3b3JraW5nIOKAlCB3aGVuIHRoZSAke0RJQU1PTkRfT1BFTn0gZmlsbHMsIHByZXNzIOKGkyB0byB2aWV3IHJlc3VsdHNgXG59XG5cbmZ1bmN0aW9uIGJ1aWxkQWxyZWFkeUFjdGl2ZU1lc3NhZ2UodXJsOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBzdHJpbmcge1xuICByZXR1cm4gdXJsXG4gICAgPyBgdWx0cmFwbGFuOiBhbHJlYWR5IHBvbGxpbmcuIE9wZW4gJHt1cmx9IHRvIGNoZWNrIHN0YXR1cywgb3Igd2FpdCBmb3IgdGhlIHBsYW4gdG8gbGFuZCBoZXJlLmBcbiAgICA6ICd1bHRyYXBsYW46IGFscmVhZHkgbGF1bmNoaW5nLiBQbGVhc2Ugd2FpdCBmb3IgdGhlIHNlc3Npb24gdG8gc3RhcnQuJ1xufVxuXG4vKipcbiAqIFN0b3AgYSBydW5uaW5nIHVsdHJhcGxhbjogYXJjaGl2ZSB0aGUgcmVtb3RlIHNlc3Npb24gKGhhbHRzIGl0IGJ1dCBrZWVwcyB0aGVcbiAqIFVSTCB2aWV3YWJsZSksIGtpbGwgdGhlIGxvY2FsIHRhc2sgZW50cnkgKGNsZWFycyB0aGUgcGlsbCksIGFuZCBjbGVhclxuICogdWx0cmFwbGFuU2Vzc2lvblVybCAocmUtYXJtcyB0aGUga2V5d29yZCB0cmlnZ2VyKS4gc3RhcnREZXRhY2hlZFBvbGwnc1xuICogc2hvdWxkU3RvcCBjYWxsYmFjayBzZWVzIHRoZSBraWxsZWQgc3RhdHVzIG9uIGl0cyBuZXh0IHRpY2sgYW5kIHRocm93cztcbiAqIHRoZSBjYXRjaCBibG9jayBlYXJseS1yZXR1cm5zIHdoZW4gc3RhdHVzICE9PSAncnVubmluZycuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdG9wVWx0cmFwbGFuKFxuICB0YXNrSWQ6IHN0cmluZyxcbiAgc2Vzc2lvbklkOiBzdHJpbmcsXG4gIHNldEFwcFN0YXRlOiAoZjogKHByZXY6IEFwcFN0YXRlKSA9PiBBcHBTdGF0ZSkgPT4gdm9pZCxcbik6IFByb21pc2U8dm9pZD4ge1xuICAvLyBSZW1vdGVBZ2VudFRhc2sua2lsbCBhcmNoaXZlcyB0aGUgc2Vzc2lvbiAod2l0aCAuY2F0Y2gpIOKAlCBubyBzZXBhcmF0ZVxuICAvLyBhcmNoaXZlIGNhbGwgbmVlZGVkIGhlcmUuXG4gIGF3YWl0IFJlbW90ZUFnZW50VGFzay5raWxsKHRhc2tJZCwgc2V0QXBwU3RhdGUpXG4gIHNldEFwcFN0YXRlKHByZXYgPT5cbiAgICBwcmV2LnVsdHJhcGxhblNlc3Npb25VcmwgfHxcbiAgICBwcmV2LnVsdHJhcGxhblBlbmRpbmdDaG9pY2UgfHxcbiAgICBwcmV2LnVsdHJhcGxhbkxhdW5jaGluZ1xuICAgICAgPyB7XG4gICAgICAgICAgLi4ucHJldixcbiAgICAgICAgICB1bHRyYXBsYW5TZXNzaW9uVXJsOiB1bmRlZmluZWQsXG4gICAgICAgICAgdWx0cmFwbGFuUGVuZGluZ0Nob2ljZTogdW5kZWZpbmVkLFxuICAgICAgICAgIHVsdHJhcGxhbkxhdW5jaGluZzogdW5kZWZpbmVkLFxuICAgICAgICB9XG4gICAgICA6IHByZXYsXG4gIClcbiAgY29uc3QgdXJsID0gZ2V0UmVtb3RlU2Vzc2lvblVybChzZXNzaW9uSWQsIHByb2Nlc3MuZW52LlNFU1NJT05fSU5HUkVTU19VUkwpXG4gIGVucXVldWVQZW5kaW5nTm90aWZpY2F0aW9uKHtcbiAgICB2YWx1ZTogYFVsdHJhcGxhbiBzdG9wcGVkLlxcblxcblNlc3Npb246ICR7dXJsfWAsXG4gICAgbW9kZTogJ3Rhc2stbm90aWZpY2F0aW9uJyxcbiAgfSlcbiAgZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24oe1xuICAgIHZhbHVlOlxuICAgICAgJ1RoZSB1c2VyIHN0b3BwZWQgdGhlIHVsdHJhcGxhbiBzZXNzaW9uIGFib3ZlLiBEbyBub3QgcmVzcG9uZCB0byB0aGUgc3RvcCBub3RpZmljYXRpb24g4oCUIHdhaXQgZm9yIHRoZWlyIG5leHQgbWVzc2FnZS4nLFxuICAgIG1vZGU6ICd0YXNrLW5vdGlmaWNhdGlvbicsXG4gICAgaXNNZXRhOiB0cnVlLFxuICB9KVxufVxuXG4vKipcbiAqIFNoYXJlZCBlbnRyeSBmb3IgdGhlIHNsYXNoIGNvbW1hbmQsIGtleXdvcmQgdHJpZ2dlciwgYW5kIHRoZSBwbGFuLWFwcHJvdmFsXG4gKiBkaWFsb2cncyBcIlVsdHJhcGxhblwiIGJ1dHRvbi4gV2hlbiBzZWVkUGxhbiBpcyBwcmVzZW50IChkaWFsb2cgcGF0aCksIGl0IGlzXG4gKiBwcmVwZW5kZWQgYXMgYSBkcmFmdCB0byByZWZpbmU7IGJsdXJiIG1heSBiZSBlbXB0eSBpbiB0aGF0IGNhc2UuXG4gKlxuICogUmVzb2x2ZXMgaW1tZWRpYXRlbHkgd2l0aCB0aGUgdXNlci1mYWNpbmcgbWVzc2FnZS4gRWxpZ2liaWxpdHkgY2hlY2ssXG4gKiBzZXNzaW9uIGNyZWF0aW9uLCBhbmQgdGFzayByZWdpc3RyYXRpb24gcnVuIGRldGFjaGVkIGFuZCBmYWlsdXJlcyBzdXJmYWNlIHZpYVxuICogZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsYXVuY2hVbHRyYXBsYW4ob3B0czoge1xuICBibHVyYjogc3RyaW5nXG4gIHNlZWRQbGFuPzogc3RyaW5nXG4gIGdldEFwcFN0YXRlOiAoKSA9PiBBcHBTdGF0ZVxuICBzZXRBcHBTdGF0ZTogKGY6IChwcmV2OiBBcHBTdGF0ZSkgPT4gQXBwU3RhdGUpID0+IHZvaWRcbiAgc2lnbmFsOiBBYm9ydFNpZ25hbFxuICAvKiogVHJ1ZSBpZiB0aGUgY2FsbGVyIGRpc2Nvbm5lY3RlZCBSZW1vdGUgQ29udHJvbCBiZWZvcmUgbGF1bmNoaW5nLiAqL1xuICBkaXNjb25uZWN0ZWRCcmlkZ2U/OiBib29sZWFuXG4gIC8qKlxuICAgKiBDYWxsZWQgb25jZSB0ZWxlcG9ydFRvUmVtb3RlIHJlc29sdmVzIHdpdGggYSBzZXNzaW9uIFVSTC4gQ2FsbGVycyB0aGF0XG4gICAqIGhhdmUgc2V0TWVzc2FnZXMgKFJFUEwpIGFwcGVuZCB0aGlzIGFzIGEgc2Vjb25kIHRyYW5zY3JpcHQgbWVzc2FnZSBzbyB0aGVcbiAgICogVVJMIGlzIHZpc2libGUgd2l0aG91dCBvcGVuaW5nIHRoZSDihpMgZGV0YWlsIHZpZXcuIENhbGxlcnMgd2l0aG91dFxuICAgKiB0cmFuc2NyaXB0IGFjY2VzcyAoRXhpdFBsYW5Nb2RlUGVybWlzc2lvblJlcXVlc3QpIG9taXQgdGhpcyDigJQgdGhlIHBpbGxcbiAgICogc3RpbGwgc2hvd3MgbGl2ZSBzdGF0dXMuXG4gICAqL1xuICBvblNlc3Npb25SZWFkeT86IChtc2c6IHN0cmluZykgPT4gdm9pZFxufSk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHtcbiAgICBibHVyYixcbiAgICBzZWVkUGxhbixcbiAgICBnZXRBcHBTdGF0ZSxcbiAgICBzZXRBcHBTdGF0ZSxcbiAgICBzaWduYWwsXG4gICAgZGlzY29ubmVjdGVkQnJpZGdlLFxuICAgIG9uU2Vzc2lvblJlYWR5LFxuICB9ID0gb3B0c1xuXG4gIGNvbnN0IHsgdWx0cmFwbGFuU2Vzc2lvblVybDogYWN0aXZlLCB1bHRyYXBsYW5MYXVuY2hpbmcgfSA9IGdldEFwcFN0YXRlKClcbiAgaWYgKGFjdGl2ZSB8fCB1bHRyYXBsYW5MYXVuY2hpbmcpIHtcbiAgICBsb2dFdmVudCgndGVuZ3VfdWx0cmFwbGFuX2NyZWF0ZV9mYWlsZWQnLCB7XG4gICAgICByZWFzb246IChhY3RpdmVcbiAgICAgICAgPyAnYWxyZWFkeV9wb2xsaW5nJ1xuICAgICAgICA6ICdhbHJlYWR5X2xhdW5jaGluZycpIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gICAgfSlcbiAgICByZXR1cm4gYnVpbGRBbHJlYWR5QWN0aXZlTWVzc2FnZShhY3RpdmUpXG4gIH1cblxuICBpZiAoIWJsdXJiICYmICFzZWVkUGxhbikge1xuICAgIC8vIE5vIGV2ZW50IOKAlCBiYXJlIC91bHRyYXBsYW4gaXMgYSB1c2FnZSBxdWVyeSwgbm90IGFuIGF0dGVtcHQuXG4gICAgcmV0dXJuIFtcbiAgICAgIC8vIFJlbmRlcmVkIHZpYSA8TWFya2Rvd24+OyByYXcgPG1lc3NhZ2U+IGlzIHRva2VuaXplZCBhcyBIVE1MXG4gICAgICAvLyBhbmQgZHJvcHBlZC4gQmFja3NsYXNoLWVzY2FwZSB0aGUgYnJhY2tldHMuXG4gICAgICAnVXNhZ2U6IC91bHRyYXBsYW4gXFxcXDxwcm9tcHRcXFxcPiwgb3IgaW5jbHVkZSBcInVsdHJhcGxhblwiIGFueXdoZXJlJyxcbiAgICAgICdpbiB5b3VyIHByb21wdCcsXG4gICAgICAnJyxcbiAgICAgICdBZHZhbmNlZCBtdWx0aS1hZ2VudCBwbGFuIG1vZGUgd2l0aCBvdXIgbW9zdCBwb3dlcmZ1bCBtb2RlbCcsXG4gICAgICAnKE9wdXMpLiBSdW5zIGluIENsYXVkZSBDb2RlIG9uIHRoZSB3ZWIuIFdoZW4gdGhlIHBsYW4gaXMgcmVhZHksJyxcbiAgICAgICd5b3UgY2FuIGV4ZWN1dGUgaXQgaW4gdGhlIHdlYiBzZXNzaW9uIG9yIHNlbmQgaXQgYmFjayBoZXJlLicsXG4gICAgICAnVGVybWluYWwgc3RheXMgZnJlZSB3aGlsZSB0aGUgcmVtb3RlIHBsYW5zLicsXG4gICAgICAnUmVxdWlyZXMgL2xvZ2luLicsXG4gICAgICAnJyxcbiAgICAgIGBUZXJtczogJHtDQ1JfVEVSTVNfVVJMfWAsXG4gICAgXS5qb2luKCdcXG4nKVxuICB9XG5cbiAgLy8gU2V0IHN5bmNocm9ub3VzbHkgYmVmb3JlIHRoZSBkZXRhY2hlZCBmbG93IHRvIHByZXZlbnQgZHVwbGljYXRlIGxhdW5jaGVzXG4gIC8vIGR1cmluZyB0aGUgdGVsZXBvcnRUb1JlbW90ZSB3aW5kb3cuXG4gIHNldEFwcFN0YXRlKHByZXYgPT5cbiAgICBwcmV2LnVsdHJhcGxhbkxhdW5jaGluZyA/IHByZXYgOiB7IC4uLnByZXYsIHVsdHJhcGxhbkxhdW5jaGluZzogdHJ1ZSB9LFxuICApXG4gIHZvaWQgbGF1bmNoRGV0YWNoZWQoe1xuICAgIGJsdXJiLFxuICAgIHNlZWRQbGFuLFxuICAgIGdldEFwcFN0YXRlLFxuICAgIHNldEFwcFN0YXRlLFxuICAgIHNpZ25hbCxcbiAgICBvblNlc3Npb25SZWFkeSxcbiAgfSlcbiAgcmV0dXJuIGJ1aWxkTGF1bmNoTWVzc2FnZShkaXNjb25uZWN0ZWRCcmlkZ2UpXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGxhdW5jaERldGFjaGVkKG9wdHM6IHtcbiAgYmx1cmI6IHN0cmluZ1xuICBzZWVkUGxhbj86IHN0cmluZ1xuICBnZXRBcHBTdGF0ZTogKCkgPT4gQXBwU3RhdGVcbiAgc2V0QXBwU3RhdGU6IChmOiAocHJldjogQXBwU3RhdGUpID0+IEFwcFN0YXRlKSA9PiB2b2lkXG4gIHNpZ25hbDogQWJvcnRTaWduYWxcbiAgb25TZXNzaW9uUmVhZHk/OiAobXNnOiBzdHJpbmcpID0+IHZvaWRcbn0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgeyBibHVyYiwgc2VlZFBsYW4sIGdldEFwcFN0YXRlLCBzZXRBcHBTdGF0ZSwgc2lnbmFsLCBvblNlc3Npb25SZWFkeSB9ID1cbiAgICBvcHRzXG4gIC8vIEhvaXN0ZWQgc28gdGhlIGNhdGNoIGJsb2NrIGNhbiBhcmNoaXZlIHRoZSByZW1vdGUgc2Vzc2lvbiBpZiBhbiBlcnJvclxuICAvLyBvY2N1cnMgYWZ0ZXIgdGVsZXBvcnRUb1JlbW90ZSBzdWNjZWVkcyAoYXZvaWRzIDMwbWluIG9ycGhhbikuXG4gIGxldCBzZXNzaW9uSWQ6IHN0cmluZyB8IHVuZGVmaW5lZFxuICB0cnkge1xuICAgIGNvbnN0IG1vZGVsID0gZ2V0VWx0cmFwbGFuTW9kZWwoKVxuXG4gICAgY29uc3QgZWxpZ2liaWxpdHkgPSBhd2FpdCBjaGVja1JlbW90ZUFnZW50RWxpZ2liaWxpdHkoKVxuICAgIGlmICghZWxpZ2liaWxpdHkuZWxpZ2libGUpIHtcbiAgICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fY3JlYXRlX2ZhaWxlZCcsIHtcbiAgICAgICAgcmVhc29uOlxuICAgICAgICAgICdwcmVjb25kaXRpb24nIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gICAgICAgIHByZWNvbmRpdGlvbl9lcnJvcnM6IGVsaWdpYmlsaXR5LmVycm9yc1xuICAgICAgICAgIC5tYXAoZSA9PiBlLnR5cGUpXG4gICAgICAgICAgLmpvaW4oXG4gICAgICAgICAgICAnLCcsXG4gICAgICAgICAgKSBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgICAgfSlcbiAgICAgIGNvbnN0IHJlYXNvbnMgPSBlbGlnaWJpbGl0eS5lcnJvcnMubWFwKGZvcm1hdFByZWNvbmRpdGlvbkVycm9yKS5qb2luKCdcXG4nKVxuICAgICAgZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24oe1xuICAgICAgICB2YWx1ZTogYHVsdHJhcGxhbjogY2Fubm90IGxhdW5jaCByZW1vdGUgc2Vzc2lvbiDigJRcXG4ke3JlYXNvbnN9YCxcbiAgICAgICAgbW9kZTogJ3Rhc2stbm90aWZpY2F0aW9uJyxcbiAgICAgIH0pXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBjb25zdCBwcm9tcHQgPSBidWlsZFVsdHJhcGxhblByb21wdChibHVyYiwgc2VlZFBsYW4pXG4gICAgbGV0IGJ1bmRsZUZhaWxNc2c6IHN0cmluZyB8IHVuZGVmaW5lZFxuICAgIGNvbnN0IHNlc3Npb24gPSBhd2FpdCB0ZWxlcG9ydFRvUmVtb3RlKHtcbiAgICAgIGluaXRpYWxNZXNzYWdlOiBwcm9tcHQsXG4gICAgICBkZXNjcmlwdGlvbjogYmx1cmIgfHwgJ1JlZmluZSBsb2NhbCBwbGFuJyxcbiAgICAgIG1vZGVsLFxuICAgICAgcGVybWlzc2lvbk1vZGU6ICdwbGFuJyxcbiAgICAgIHVsdHJhcGxhbjogdHJ1ZSxcbiAgICAgIHNpZ25hbCxcbiAgICAgIHVzZURlZmF1bHRFbnZpcm9ubWVudDogdHJ1ZSxcbiAgICAgIG9uQnVuZGxlRmFpbDogbXNnID0+IHtcbiAgICAgICAgYnVuZGxlRmFpbE1zZyA9IG1zZ1xuICAgICAgfSxcbiAgICB9KVxuICAgIGlmICghc2Vzc2lvbikge1xuICAgICAgbG9nRXZlbnQoJ3Rlbmd1X3VsdHJhcGxhbl9jcmVhdGVfZmFpbGVkJywge1xuICAgICAgICByZWFzb246IChidW5kbGVGYWlsTXNnXG4gICAgICAgICAgPyAnYnVuZGxlX2ZhaWwnXG4gICAgICAgICAgOiAndGVsZXBvcnRfbnVsbCcpIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gICAgICB9KVxuICAgICAgZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24oe1xuICAgICAgICB2YWx1ZTogYHVsdHJhcGxhbjogc2Vzc2lvbiBjcmVhdGlvbiBmYWlsZWQke2J1bmRsZUZhaWxNc2cgPyBgIOKAlCAke2J1bmRsZUZhaWxNc2d9YCA6ICcnfS4gU2VlIC0tZGVidWcgZm9yIGRldGFpbHMuYCxcbiAgICAgICAgbW9kZTogJ3Rhc2stbm90aWZpY2F0aW9uJyxcbiAgICAgIH0pXG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgc2Vzc2lvbklkID0gc2Vzc2lvbi5pZFxuXG4gICAgY29uc3QgdXJsID0gZ2V0UmVtb3RlU2Vzc2lvblVybChzZXNzaW9uLmlkLCBwcm9jZXNzLmVudi5TRVNTSU9OX0lOR1JFU1NfVVJMKVxuICAgIHNldEFwcFN0YXRlKHByZXYgPT4gKHtcbiAgICAgIC4uLnByZXYsXG4gICAgICB1bHRyYXBsYW5TZXNzaW9uVXJsOiB1cmwsXG4gICAgICB1bHRyYXBsYW5MYXVuY2hpbmc6IHVuZGVmaW5lZCxcbiAgICB9KSlcbiAgICBvblNlc3Npb25SZWFkeT8uKGJ1aWxkU2Vzc2lvblJlYWR5TWVzc2FnZSh1cmwpKVxuICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fbGF1bmNoZWQnLCB7XG4gICAgICBoYXNfc2VlZF9wbGFuOiBCb29sZWFuKHNlZWRQbGFuKSxcbiAgICAgIG1vZGVsOlxuICAgICAgICBtb2RlbCBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgIH0pXG4gICAgLy8gVE9ETygjMjM5ODUpOiByZXBsYWNlIHJlZ2lzdGVyUmVtb3RlQWdlbnRUYXNrICsgc3RhcnREZXRhY2hlZFBvbGwgd2l0aFxuICAgIC8vIEV4aXRQbGFuTW9kZVNjYW5uZXIgaW5zaWRlIHN0YXJ0UmVtb3RlU2Vzc2lvblBvbGxpbmcuXG4gICAgY29uc3QgeyB0YXNrSWQgfSA9IHJlZ2lzdGVyUmVtb3RlQWdlbnRUYXNrKHtcbiAgICAgIHJlbW90ZVRhc2tUeXBlOiAndWx0cmFwbGFuJyxcbiAgICAgIHNlc3Npb246IHsgaWQ6IHNlc3Npb24uaWQsIHRpdGxlOiBibHVyYiB8fCAnVWx0cmFwbGFuJyB9LFxuICAgICAgY29tbWFuZDogYmx1cmIsXG4gICAgICBjb250ZXh0OiB7XG4gICAgICAgIGFib3J0Q29udHJvbGxlcjogbmV3IEFib3J0Q29udHJvbGxlcigpLFxuICAgICAgICBnZXRBcHBTdGF0ZSxcbiAgICAgICAgc2V0QXBwU3RhdGUsXG4gICAgICB9LFxuICAgICAgaXNVbHRyYXBsYW46IHRydWUsXG4gICAgfSlcbiAgICBzdGFydERldGFjaGVkUG9sbCh0YXNrSWQsIHNlc3Npb24uaWQsIHVybCwgZ2V0QXBwU3RhdGUsIHNldEFwcFN0YXRlKVxuICB9IGNhdGNoIChlKSB7XG4gICAgbG9nRXJyb3IoZSlcbiAgICBsb2dFdmVudCgndGVuZ3VfdWx0cmFwbGFuX2NyZWF0ZV9mYWlsZWQnLCB7XG4gICAgICByZWFzb246XG4gICAgICAgICd1bmV4cGVjdGVkX2Vycm9yJyBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgIH0pXG4gICAgZW5xdWV1ZVBlbmRpbmdOb3RpZmljYXRpb24oe1xuICAgICAgdmFsdWU6IGB1bHRyYXBsYW46IHVuZXhwZWN0ZWQgZXJyb3Ig4oCUICR7ZXJyb3JNZXNzYWdlKGUpfWAsXG4gICAgICBtb2RlOiAndGFzay1ub3RpZmljYXRpb24nLFxuICAgIH0pXG4gICAgaWYgKHNlc3Npb25JZCkge1xuICAgICAgLy8gRXJyb3IgYWZ0ZXIgdGVsZXBvcnQgc3VjY2VlZGVkIOKAlCBhcmNoaXZlIHNvIHRoZSByZW1vdGUgZG9lc24ndCBzaXRcbiAgICAgIC8vIHJ1bm5pbmcgZm9yIDMwbWluIHdpdGggbm9ib2R5IHBvbGxpbmcgaXQuXG4gICAgICB2b2lkIGFyY2hpdmVSZW1vdGVTZXNzaW9uKHNlc3Npb25JZCkuY2F0Y2goZXJyID0+XG4gICAgICAgIGxvZ0ZvckRlYnVnZ2luZygndWx0cmFwbGFuOiBmYWlsZWQgdG8gYXJjaGl2ZSBvcnBoYW5lZCBzZXNzaW9uJywgZXJyKSxcbiAgICAgIClcbiAgICAgIC8vIHVsdHJhcGxhblNlc3Npb25VcmwgbWF5IGhhdmUgYmVlbiBzZXQgYmVmb3JlIHRoZSB0aHJvdzsgY2xlYXIgaXQgc29cbiAgICAgIC8vIHRoZSBcImFscmVhZHkgcG9sbGluZ1wiIGd1YXJkIGRvZXNuJ3QgYmxvY2sgZnV0dXJlIGxhdW5jaGVzLlxuICAgICAgc2V0QXBwU3RhdGUocHJldiA9PlxuICAgICAgICBwcmV2LnVsdHJhcGxhblNlc3Npb25VcmxcbiAgICAgICAgICA/IHsgLi4ucHJldiwgdWx0cmFwbGFuU2Vzc2lvblVybDogdW5kZWZpbmVkIH1cbiAgICAgICAgICA6IHByZXYsXG4gICAgICApXG4gICAgfVxuICB9IGZpbmFsbHkge1xuICAgIC8vIE5vLW9wIG9uIHN1Y2Nlc3M6IHRoZSB1cmwtc2V0dGluZyBzZXRBcHBTdGF0ZSBhbHJlYWR5IGNsZWFyZWQgdGhpcy5cbiAgICBzZXRBcHBTdGF0ZShwcmV2ID0+XG4gICAgICBwcmV2LnVsdHJhcGxhbkxhdW5jaGluZ1xuICAgICAgICA/IHsgLi4ucHJldiwgdWx0cmFwbGFuTGF1bmNoaW5nOiB1bmRlZmluZWQgfVxuICAgICAgICA6IHByZXYsXG4gICAgKVxuICB9XG59XG5cbmNvbnN0IGNhbGw6IExvY2FsSlNYQ29tbWFuZENhbGwgPSBhc3luYyAob25Eb25lLCBjb250ZXh0LCBhcmdzKSA9PiB7XG4gIGNvbnN0IGJsdXJiID0gYXJncy50cmltKClcblxuICAvLyBCYXJlIC91bHRyYXBsYW4gKG5vIGFyZ3MsIG5vIHNlZWQgcGxhbikganVzdCBzaG93cyB1c2FnZSDigJQgbm8gZGlhbG9nLlxuICBpZiAoIWJsdXJiKSB7XG4gICAgY29uc3QgbXNnID0gYXdhaXQgbGF1bmNoVWx0cmFwbGFuKHtcbiAgICAgIGJsdXJiLFxuICAgICAgZ2V0QXBwU3RhdGU6IGNvbnRleHQuZ2V0QXBwU3RhdGUsXG4gICAgICBzZXRBcHBTdGF0ZTogY29udGV4dC5zZXRBcHBTdGF0ZSxcbiAgICAgIHNpZ25hbDogY29udGV4dC5hYm9ydENvbnRyb2xsZXIuc2lnbmFsLFxuICAgIH0pXG4gICAgb25Eb25lKG1zZywgeyBkaXNwbGF5OiAnc3lzdGVtJyB9KVxuICAgIHJldHVybiBudWxsXG4gIH1cblxuICAvLyBHdWFyZCBtYXRjaGVzIGxhdW5jaFVsdHJhcGxhbidzIG93biBjaGVjayDigJQgc2hvd2luZyB0aGUgZGlhbG9nIHdoZW4gYVxuICAvLyBzZXNzaW9uIGlzIGFscmVhZHkgYWN0aXZlIG9yIGxhdW5jaGluZyB3b3VsZCB3YXN0ZSB0aGUgdXNlcidzIGNsaWNrIGFuZCBzZXRcbiAgLy8gaGFzU2VlblVsdHJhcGxhblRlcm1zIGJlZm9yZSB0aGUgbGF1bmNoIGZhaWxzLlxuICBjb25zdCB7IHVsdHJhcGxhblNlc3Npb25Vcmw6IGFjdGl2ZSwgdWx0cmFwbGFuTGF1bmNoaW5nIH0gPVxuICAgIGNvbnRleHQuZ2V0QXBwU3RhdGUoKVxuICBpZiAoYWN0aXZlIHx8IHVsdHJhcGxhbkxhdW5jaGluZykge1xuICAgIGxvZ0V2ZW50KCd0ZW5ndV91bHRyYXBsYW5fY3JlYXRlX2ZhaWxlZCcsIHtcbiAgICAgIHJlYXNvbjogKGFjdGl2ZVxuICAgICAgICA/ICdhbHJlYWR5X3BvbGxpbmcnXG4gICAgICAgIDogJ2FscmVhZHlfbGF1bmNoaW5nJykgYXMgQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyxcbiAgICB9KVxuICAgIG9uRG9uZShidWlsZEFscmVhZHlBY3RpdmVNZXNzYWdlKGFjdGl2ZSksIHsgZGlzcGxheTogJ3N5c3RlbScgfSlcbiAgICByZXR1cm4gbnVsbFxuICB9XG5cbiAgLy8gTW91bnQgdGhlIHByZS1sYXVuY2ggZGlhbG9nIHZpYSBmb2N1c2VkSW5wdXREaWFsb2cgKGJvdHRvbSByZWdpb24sIGxpa2VcbiAgLy8gcGVybWlzc2lvbiBkaWFsb2dzKSByYXRoZXIgdGhhbiByZXR1cm5pbmcgSlNYICh0cmFuc2NyaXB0IGFyZWEsIGFuY2hvcnNcbiAgLy8gYXQgdG9wIG9mIHNjcm9sbGJhY2spLiBSRVBMLnRzeCBoYW5kbGVzIGxhdW5jaC9jbGVhci9jYW5jZWwgb24gY2hvaWNlLlxuICBjb250ZXh0LnNldEFwcFN0YXRlKHByZXYgPT4gKHsgLi4ucHJldiwgdWx0cmFwbGFuTGF1bmNoUGVuZGluZzogeyBibHVyYiB9IH0pKVxuICAvLyAnc2tpcCcgc3VwcHJlc3NlcyB0aGUgKG5vIGNvbnRlbnQpIGVjaG8g4oCUIHRoZSBkaWFsb2cncyBjaG9pY2UgaGFuZGxlclxuICAvLyBhZGRzIHRoZSByZWFsIC91bHRyYXBsYW4gZWNobyArIGxhdW5jaCBjb25maXJtYXRpb24uXG4gIG9uRG9uZSh1bmRlZmluZWQsIHsgZGlzcGxheTogJ3NraXAnIH0pXG4gIHJldHVybiBudWxsXG59XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgdHlwZTogJ2xvY2FsLWpzeCcsXG4gIG5hbWU6ICd1bHRyYXBsYW4nLFxuICBkZXNjcmlwdGlvbjogYH4xMOKAkzMwIG1pbiDCtyBDbGF1ZGUgQ29kZSBvbiB0aGUgd2ViIGRyYWZ0cyBhbiBhZHZhbmNlZCBwbGFuIHlvdSBjYW4gZWRpdCBhbmQgYXBwcm92ZS4gU2VlICR7Q0NSX1RFUk1TX1VSTH1gLFxuICBhcmd1bWVudEhpbnQ6ICc8cHJvbXB0PicsXG4gIGlzRW5hYmxlZDogKCkgPT4gXCJleHRlcm5hbFwiID09PSAnYW50JyxcbiAgbG9hZDogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKHsgY2FsbCB9KSxcbn0gc2F0aXNmaWVzIENvbW1hbmRcbiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsWUFBWSxRQUFRLElBQUk7QUFDakMsU0FBU0MsK0JBQStCLFFBQVEsb0JBQW9CO0FBQ3BFLGNBQWNDLE9BQU8sUUFBUSxnQkFBZ0I7QUFDN0MsU0FBU0MsWUFBWSxRQUFRLHlCQUF5QjtBQUN0RCxTQUFTQyxtQkFBbUIsUUFBUSx5QkFBeUI7QUFDN0QsU0FBU0MsbUNBQW1DLFFBQVEscUNBQXFDO0FBQ3pGLFNBQ0UsS0FBS0MsMERBQTBELEVBQy9EQyxRQUFRLFFBQ0gsZ0NBQWdDO0FBQ3ZDLGNBQWNDLFFBQVEsUUFBUSwyQkFBMkI7QUFDekQsU0FDRUMsMkJBQTJCLEVBQzNCQyx1QkFBdUIsRUFDdkJDLGVBQWUsRUFDZixLQUFLQyxvQkFBb0IsRUFDekJDLHVCQUF1QixRQUNsQiw2Q0FBNkM7QUFDcEQsY0FBY0MsbUJBQW1CLFFBQVEscUJBQXFCO0FBQzlELFNBQVNDLGVBQWUsUUFBUSxtQkFBbUI7QUFDbkQsU0FBU0MsWUFBWSxRQUFRLG9CQUFvQjtBQUNqRCxTQUFTQyxRQUFRLFFBQVEsaUJBQWlCO0FBQzFDLFNBQVNDLDBCQUEwQixRQUFRLGlDQUFpQztBQUM1RSxTQUFTQyxpQkFBaUIsUUFBUSwyQkFBMkI7QUFDN0QsU0FBU0MsZUFBZSxRQUFRLDRCQUE0QjtBQUM1RCxTQUFTQyxvQkFBb0IsRUFBRUMsZ0JBQWdCLFFBQVEsc0JBQXNCO0FBQzdFLFNBQ0VDLDJCQUEyQixFQUMzQkMsa0JBQWtCLFFBQ2Isa0NBQWtDOztBQUV6QztBQUNBOztBQUVBO0FBQ0EsTUFBTUMsb0JBQW9CLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJO0FBRTNDLE9BQU8sTUFBTUMsYUFBYSxHQUN4Qix3REFBd0Q7O0FBRTFEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTQyxpQkFBaUJBLENBQUEsQ0FBRSxFQUFFLE1BQU0sQ0FBQztFQUNuQyxPQUFPdEIsbUNBQW1DLENBQ3hDLHVCQUF1QixFQUN2QmMsaUJBQWlCLENBQUNTLE1BQU0sQ0FBQ0MsVUFDM0IsQ0FBQztBQUNIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTUMsVUFBVSxHQUFHQyxPQUFPLENBQUMsK0JBQStCLENBQUM7QUFDM0Q7QUFDQSxNQUFNQyxvQkFBb0IsRUFBRSxNQUFNLEdBQUcsQ0FDbkMsT0FBT0YsVUFBVSxLQUFLLFFBQVEsR0FBR0EsVUFBVSxHQUFHQSxVQUFVLENBQUNHLE9BQU8sRUFDaEVDLE9BQU8sQ0FBQyxDQUFDOztBQUVYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU1DLHNCQUFzQixFQUFFLE1BQU0sR0FDbEMsVUFBVSxLQUFLLEtBQUssSUFBSUMsT0FBTyxDQUFDQyxHQUFHLENBQUNDLHFCQUFxQixHQUNyRHRDLFlBQVksQ0FBQ29DLE9BQU8sQ0FBQ0MsR0FBRyxDQUFDQyxxQkFBcUIsRUFBRSxNQUFNLENBQUMsQ0FBQ0osT0FBTyxDQUFDLENBQUMsR0FDakVGLG9CQUFvQjtBQUMxQjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU8sU0FBU08sb0JBQW9CQSxDQUFDQyxLQUFLLEVBQUUsTUFBTSxFQUFFQyxRQUFpQixDQUFSLEVBQUUsTUFBTSxDQUFDLEVBQUUsTUFBTSxDQUFDO0VBQzdFLE1BQU1DLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFO0VBQzFCLElBQUlELFFBQVEsRUFBRTtJQUNaQyxLQUFLLENBQUNDLElBQUksQ0FBQyxpQ0FBaUMsRUFBRSxFQUFFLEVBQUVGLFFBQVEsRUFBRSxFQUFFLENBQUM7RUFDakU7RUFDQUMsS0FBSyxDQUFDQyxJQUFJLENBQUNSLHNCQUFzQixDQUFDO0VBQ2xDLElBQUlLLEtBQUssRUFBRTtJQUNURSxLQUFLLENBQUNDLElBQUksQ0FBQyxFQUFFLEVBQUVILEtBQUssQ0FBQztFQUN2QjtFQUNBLE9BQU9FLEtBQUssQ0FBQ0UsSUFBSSxDQUFDLElBQUksQ0FBQztBQUN6QjtBQUVBLFNBQVNDLGlCQUFpQkEsQ0FDeEJDLE1BQU0sRUFBRSxNQUFNLEVBQ2RDLFNBQVMsRUFBRSxNQUFNLEVBQ2pCQyxHQUFHLEVBQUUsTUFBTSxFQUNYQyxXQUFXLEVBQUUsR0FBRyxHQUFHekMsUUFBUSxFQUMzQjBDLFdBQVcsRUFBRSxDQUFDQyxDQUFDLEVBQUUsQ0FBQ0MsSUFBSSxFQUFFNUMsUUFBUSxFQUFFLEdBQUdBLFFBQVEsRUFBRSxHQUFHLElBQUksQ0FDdkQsRUFBRSxJQUFJLENBQUM7RUFDTixNQUFNNkMsT0FBTyxHQUFHQyxJQUFJLENBQUNDLEdBQUcsQ0FBQyxDQUFDO0VBQzFCLElBQUlDLE1BQU0sR0FBRyxLQUFLO0VBQ2xCLEtBQUssQ0FBQyxZQUFZO0lBQ2hCLElBQUk7TUFDRixNQUFNO1FBQUVDLElBQUk7UUFBRUMsV0FBVztRQUFFQztNQUFnQixDQUFDLEdBQzFDLE1BQU1wQywyQkFBMkIsQ0FDL0J3QixTQUFTLEVBQ1R0QixvQkFBb0IsRUFDcEJtQyxLQUFLLElBQUk7UUFDUCxJQUFJQSxLQUFLLEtBQUssYUFBYSxFQUN6QnJELFFBQVEsQ0FBQyxnQ0FBZ0MsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNoRGEsZUFBZSxDQUFDUixvQkFBb0IsQ0FBQyxDQUFDa0MsTUFBTSxFQUFFSSxXQUFXLEVBQUVXLENBQUMsSUFBSTtVQUM5RCxJQUFJQSxDQUFDLENBQUNDLE1BQU0sS0FBSyxTQUFTLEVBQUUsT0FBT0QsQ0FBQztVQUNwQyxNQUFNRSxJQUFJLEdBQUdILEtBQUssS0FBSyxTQUFTLEdBQUdJLFNBQVMsR0FBR0osS0FBSztVQUNwRCxPQUFPQyxDQUFDLENBQUNJLGNBQWMsS0FBS0YsSUFBSSxHQUM1QkYsQ0FBQyxHQUNEO1lBQUUsR0FBR0EsQ0FBQztZQUFFSSxjQUFjLEVBQUVGO1VBQUssQ0FBQztRQUNwQyxDQUFDLENBQUM7TUFDSixDQUFDLEVBQ0QsTUFBTWQsV0FBVyxDQUFDLENBQUMsQ0FBQ2lCLEtBQUssR0FBR3BCLE1BQU0sQ0FBQyxFQUFFZ0IsTUFBTSxLQUFLLFNBQ2xELENBQUM7TUFDSHZELFFBQVEsQ0FBQywwQkFBMEIsRUFBRTtRQUNuQzRELFdBQVcsRUFBRWIsSUFBSSxDQUFDQyxHQUFHLENBQUMsQ0FBQyxHQUFHRixPQUFPO1FBQ2pDZSxXQUFXLEVBQUVYLElBQUksQ0FBQ1ksTUFBTTtRQUN4QkMsWUFBWSxFQUFFWixXQUFXO1FBQ3pCYSxnQkFBZ0IsRUFDZFosZUFBZSxJQUFJckQ7TUFDdkIsQ0FBQyxDQUFDO01BQ0YsSUFBSXFELGVBQWUsS0FBSyxRQUFRLEVBQUU7UUFDaEM7UUFDQTtRQUNBO1FBQ0E7UUFDQTtRQUNBLE1BQU1hLElBQUksR0FBR3ZCLFdBQVcsQ0FBQyxDQUFDLENBQUNpQixLQUFLLEdBQUdwQixNQUFNLENBQUM7UUFDMUMsSUFBSTBCLElBQUksRUFBRVYsTUFBTSxLQUFLLFNBQVMsRUFBRTtRQUNoQzFDLGVBQWUsQ0FBQ1Isb0JBQW9CLENBQUMsQ0FBQ2tDLE1BQU0sRUFBRUksV0FBVyxFQUFFVyxDQUFDLElBQzFEQSxDQUFDLENBQUNDLE1BQU0sS0FBSyxTQUFTLEdBQ2xCRCxDQUFDLEdBQ0Q7VUFBRSxHQUFHQSxDQUFDO1VBQUVDLE1BQU0sRUFBRSxXQUFXO1VBQUVXLE9BQU8sRUFBRW5CLElBQUksQ0FBQ0MsR0FBRyxDQUFDO1FBQUUsQ0FDdkQsQ0FBQztRQUNETCxXQUFXLENBQUNFLElBQUksSUFDZEEsSUFBSSxDQUFDc0IsbUJBQW1CLEtBQUsxQixHQUFHLEdBQzVCO1VBQUUsR0FBR0ksSUFBSTtVQUFFc0IsbUJBQW1CLEVBQUVWO1FBQVUsQ0FBQyxHQUMzQ1osSUFDTixDQUFDO1FBQ0RsQywwQkFBMEIsQ0FBQztVQUN6QnlELEtBQUssRUFBRSxDQUNMLDhFQUE4RTNCLEdBQUcsRUFBRSxFQUNuRixFQUFFLEVBQ0Ysb0dBQW9HLENBQ3JHLENBQUNKLElBQUksQ0FBQyxJQUFJLENBQUM7VUFDWmdDLElBQUksRUFBRTtRQUNSLENBQUMsQ0FBQztNQUNKLENBQUMsTUFBTTtRQUNMO1FBQ0E7UUFDQTtRQUNBO1FBQ0ExQixXQUFXLENBQUNFLElBQUksSUFBSTtVQUNsQixNQUFNb0IsSUFBSSxHQUFHcEIsSUFBSSxDQUFDYyxLQUFLLEdBQUdwQixNQUFNLENBQUM7VUFDakMsSUFBSSxDQUFDMEIsSUFBSSxJQUFJQSxJQUFJLENBQUNWLE1BQU0sS0FBSyxTQUFTLEVBQUUsT0FBT1YsSUFBSTtVQUNuRCxPQUFPO1lBQ0wsR0FBR0EsSUFBSTtZQUNQeUIsc0JBQXNCLEVBQUU7Y0FBRXBCLElBQUk7Y0FBRVYsU0FBUztjQUFFRDtZQUFPO1VBQ3BELENBQUM7UUFDSCxDQUFDLENBQUM7TUFDSjtJQUNGLENBQUMsQ0FBQyxPQUFPZ0MsQ0FBQyxFQUFFO01BQ1Y7TUFDQTtNQUNBO01BQ0EsTUFBTU4sSUFBSSxHQUFHdkIsV0FBVyxDQUFDLENBQUMsQ0FBQ2lCLEtBQUssR0FBR3BCLE1BQU0sQ0FBQztNQUMxQyxJQUFJMEIsSUFBSSxFQUFFVixNQUFNLEtBQUssU0FBUyxFQUFFO01BQ2hDTixNQUFNLEdBQUcsSUFBSTtNQUNiakQsUUFBUSxDQUFDLHdCQUF3QixFQUFFO1FBQ2pDNEQsV0FBVyxFQUFFYixJQUFJLENBQUNDLEdBQUcsQ0FBQyxDQUFDLEdBQUdGLE9BQU87UUFDakMwQixNQUFNLEVBQUUsQ0FBQ0QsQ0FBQyxZQUFZdEQsa0JBQWtCLEdBQ3BDc0QsQ0FBQyxDQUFDQyxNQUFNLEdBQ1Isb0JBQW9CLEtBQUt6RSwwREFBMEQ7UUFDdkZnRSxZQUFZLEVBQ1ZRLENBQUMsWUFBWXRELGtCQUFrQixHQUFHc0QsQ0FBQyxDQUFDcEIsV0FBVyxHQUFHTTtNQUN0RCxDQUFDLENBQUM7TUFDRjlDLDBCQUEwQixDQUFDO1FBQ3pCeUQsS0FBSyxFQUFFLHFCQUFxQjNELFlBQVksQ0FBQzhELENBQUMsQ0FBQyxnQkFBZ0I5QixHQUFHLEVBQUU7UUFDaEU0QixJQUFJLEVBQUU7TUFDUixDQUFDLENBQUM7TUFDRjtNQUNBO01BQ0EsS0FBS3ZELG9CQUFvQixDQUFDMEIsU0FBUyxDQUFDLENBQUNpQyxLQUFLLENBQUNGLENBQUMsSUFDMUMvRCxlQUFlLENBQUMsNkJBQTZCa0UsTUFBTSxDQUFDSCxDQUFDLENBQUMsRUFBRSxDQUMxRCxDQUFDO01BQ0Q1QixXQUFXLENBQUNFLElBQUk7TUFDZDtNQUNBO01BQ0FBLElBQUksQ0FBQ3NCLG1CQUFtQixLQUFLMUIsR0FBRyxHQUM1QjtRQUFFLEdBQUdJLElBQUk7UUFBRXNCLG1CQUFtQixFQUFFVjtNQUFVLENBQUMsR0FDM0NaLElBQ04sQ0FBQztJQUNILENBQUMsU0FBUztNQUNSO01BQ0E7TUFDQTtNQUNBO01BQ0E7TUFDQTtNQUNBLElBQUlJLE1BQU0sRUFBRTtRQUNWcEMsZUFBZSxDQUFDUixvQkFBb0IsQ0FBQyxDQUFDa0MsTUFBTSxFQUFFSSxXQUFXLEVBQUVXLENBQUMsSUFDMURBLENBQUMsQ0FBQ0MsTUFBTSxLQUFLLFNBQVMsR0FDbEJELENBQUMsR0FDRDtVQUFFLEdBQUdBLENBQUM7VUFBRUMsTUFBTSxFQUFFLFFBQVE7VUFBRVcsT0FBTyxFQUFFbkIsSUFBSSxDQUFDQyxHQUFHLENBQUM7UUFBRSxDQUNwRCxDQUFDO01BQ0g7SUFDRjtFQUNGLENBQUMsRUFBRSxDQUFDO0FBQ047O0FBRUE7QUFDQTtBQUNBLFNBQVMyQixrQkFBa0JBLENBQUNDLGtCQUE0QixDQUFULEVBQUUsT0FBTyxDQUFDLEVBQUUsTUFBTSxDQUFDO0VBQ2hFLE1BQU1DLE1BQU0sR0FBR0Qsa0JBQWtCLEdBQUcsR0FBR2xGLCtCQUErQixHQUFHLEdBQUcsRUFBRTtFQUM5RSxPQUFPLEdBQUdFLFlBQVksZUFBZWlGLE1BQU0sa0NBQWtDO0FBQy9FO0FBRUEsU0FBU0Msd0JBQXdCQSxDQUFDckMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxFQUFFLE1BQU0sQ0FBQztFQUNyRCxPQUFPLEdBQUc3QyxZQUFZLDJEQUEyRDZDLEdBQUcseUNBQXlDN0MsWUFBWSxpQ0FBaUM7QUFDNUs7QUFFQSxTQUFTbUYseUJBQXlCQSxDQUFDdEMsR0FBRyxFQUFFLE1BQU0sR0FBRyxTQUFTLENBQUMsRUFBRSxNQUFNLENBQUM7RUFDbEUsT0FBT0EsR0FBRyxHQUNOLG9DQUFvQ0EsR0FBRyxzREFBc0QsR0FDN0YscUVBQXFFO0FBQzNFOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTyxlQUFldUMsYUFBYUEsQ0FDakN6QyxNQUFNLEVBQUUsTUFBTSxFQUNkQyxTQUFTLEVBQUUsTUFBTSxFQUNqQkcsV0FBVyxFQUFFLENBQUNDLENBQUMsRUFBRSxDQUFDQyxJQUFJLEVBQUU1QyxRQUFRLEVBQUUsR0FBR0EsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUN2RCxFQUFFZ0YsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0VBQ2Y7RUFDQTtFQUNBLE1BQU03RSxlQUFlLENBQUM4RSxJQUFJLENBQUMzQyxNQUFNLEVBQUVJLFdBQVcsQ0FBQztFQUMvQ0EsV0FBVyxDQUFDRSxJQUFJLElBQ2RBLElBQUksQ0FBQ3NCLG1CQUFtQixJQUN4QnRCLElBQUksQ0FBQ3lCLHNCQUFzQixJQUMzQnpCLElBQUksQ0FBQ3NDLGtCQUFrQixHQUNuQjtJQUNFLEdBQUd0QyxJQUFJO0lBQ1BzQixtQkFBbUIsRUFBRVYsU0FBUztJQUM5QmEsc0JBQXNCLEVBQUViLFNBQVM7SUFDakMwQixrQkFBa0IsRUFBRTFCO0VBQ3RCLENBQUMsR0FDRFosSUFDTixDQUFDO0VBQ0QsTUFBTUosR0FBRyxHQUFHNUMsbUJBQW1CLENBQUMyQyxTQUFTLEVBQUVYLE9BQU8sQ0FBQ0MsR0FBRyxDQUFDc0QsbUJBQW1CLENBQUM7RUFDM0V6RSwwQkFBMEIsQ0FBQztJQUN6QnlELEtBQUssRUFBRSxrQ0FBa0MzQixHQUFHLEVBQUU7SUFDOUM0QixJQUFJLEVBQUU7RUFDUixDQUFDLENBQUM7RUFDRjFELDBCQUEwQixDQUFDO0lBQ3pCeUQsS0FBSyxFQUNILHNIQUFzSDtJQUN4SEMsSUFBSSxFQUFFLG1CQUFtQjtJQUN6QmdCLE1BQU0sRUFBRTtFQUNWLENBQUMsQ0FBQztBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU8sZUFBZUMsZUFBZUEsQ0FBQ0MsSUFBSSxFQUFFO0VBQzFDdEQsS0FBSyxFQUFFLE1BQU07RUFDYkMsUUFBUSxDQUFDLEVBQUUsTUFBTTtFQUNqQlEsV0FBVyxFQUFFLEdBQUcsR0FBR3pDLFFBQVE7RUFDM0IwQyxXQUFXLEVBQUUsQ0FBQ0MsQ0FBQyxFQUFFLENBQUNDLElBQUksRUFBRTVDLFFBQVEsRUFBRSxHQUFHQSxRQUFRLEVBQUUsR0FBRyxJQUFJO0VBQ3REdUYsTUFBTSxFQUFFQyxXQUFXO0VBQ25CO0VBQ0FiLGtCQUFrQixDQUFDLEVBQUUsT0FBTztFQUM1QjtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNFYyxjQUFjLENBQUMsRUFBRSxDQUFDQyxHQUFHLEVBQUUsTUFBTSxFQUFFLEdBQUcsSUFBSTtBQUN4QyxDQUFDLENBQUMsRUFBRVYsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0VBQ2xCLE1BQU07SUFDSmhELEtBQUs7SUFDTEMsUUFBUTtJQUNSUSxXQUFXO0lBQ1hDLFdBQVc7SUFDWDZDLE1BQU07SUFDTlosa0JBQWtCO0lBQ2xCYztFQUNGLENBQUMsR0FBR0gsSUFBSTtFQUVSLE1BQU07SUFBRXBCLG1CQUFtQixFQUFFeUIsTUFBTTtJQUFFVDtFQUFtQixDQUFDLEdBQUd6QyxXQUFXLENBQUMsQ0FBQztFQUN6RSxJQUFJa0QsTUFBTSxJQUFJVCxrQkFBa0IsRUFBRTtJQUNoQ25GLFFBQVEsQ0FBQywrQkFBK0IsRUFBRTtNQUN4Q3dFLE1BQU0sRUFBRSxDQUFDb0IsTUFBTSxHQUNYLGlCQUFpQixHQUNqQixtQkFBbUIsS0FBSzdGO0lBQzlCLENBQUMsQ0FBQztJQUNGLE9BQU9nRix5QkFBeUIsQ0FBQ2EsTUFBTSxDQUFDO0VBQzFDO0VBRUEsSUFBSSxDQUFDM0QsS0FBSyxJQUFJLENBQUNDLFFBQVEsRUFBRTtJQUN2QjtJQUNBLE9BQU87SUFDTDtJQUNBO0lBQ0EsaUVBQWlFLEVBQ2pFLGdCQUFnQixFQUNoQixFQUFFLEVBQ0YsNkRBQTZELEVBQzdELGlFQUFpRSxFQUNqRSw2REFBNkQsRUFDN0QsNkNBQTZDLEVBQzdDLGtCQUFrQixFQUNsQixFQUFFLEVBQ0YsVUFBVWYsYUFBYSxFQUFFLENBQzFCLENBQUNrQixJQUFJLENBQUMsSUFBSSxDQUFDO0VBQ2Q7O0VBRUE7RUFDQTtFQUNBTSxXQUFXLENBQUNFLElBQUksSUFDZEEsSUFBSSxDQUFDc0Msa0JBQWtCLEdBQUd0QyxJQUFJLEdBQUc7SUFBRSxHQUFHQSxJQUFJO0lBQUVzQyxrQkFBa0IsRUFBRTtFQUFLLENBQ3ZFLENBQUM7RUFDRCxLQUFLVSxjQUFjLENBQUM7SUFDbEI1RCxLQUFLO0lBQ0xDLFFBQVE7SUFDUlEsV0FBVztJQUNYQyxXQUFXO0lBQ1g2QyxNQUFNO0lBQ05FO0VBQ0YsQ0FBQyxDQUFDO0VBQ0YsT0FBT2Ysa0JBQWtCLENBQUNDLGtCQUFrQixDQUFDO0FBQy9DO0FBRUEsZUFBZWlCLGNBQWNBLENBQUNOLElBQUksRUFBRTtFQUNsQ3RELEtBQUssRUFBRSxNQUFNO0VBQ2JDLFFBQVEsQ0FBQyxFQUFFLE1BQU07RUFDakJRLFdBQVcsRUFBRSxHQUFHLEdBQUd6QyxRQUFRO0VBQzNCMEMsV0FBVyxFQUFFLENBQUNDLENBQUMsRUFBRSxDQUFDQyxJQUFJLEVBQUU1QyxRQUFRLEVBQUUsR0FBR0EsUUFBUSxFQUFFLEdBQUcsSUFBSTtFQUN0RHVGLE1BQU0sRUFBRUMsV0FBVztFQUNuQkMsY0FBYyxDQUFDLEVBQUUsQ0FBQ0MsR0FBRyxFQUFFLE1BQU0sRUFBRSxHQUFHLElBQUk7QUFDeEMsQ0FBQyxDQUFDLEVBQUVWLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztFQUNoQixNQUFNO0lBQUVoRCxLQUFLO0lBQUVDLFFBQVE7SUFBRVEsV0FBVztJQUFFQyxXQUFXO0lBQUU2QyxNQUFNO0lBQUVFO0VBQWUsQ0FBQyxHQUN6RUgsSUFBSTtFQUNOO0VBQ0E7RUFDQSxJQUFJL0MsU0FBUyxFQUFFLE1BQU0sR0FBRyxTQUFTO0VBQ2pDLElBQUk7SUFDRixNQUFNc0QsS0FBSyxHQUFHMUUsaUJBQWlCLENBQUMsQ0FBQztJQUVqQyxNQUFNMkUsV0FBVyxHQUFHLE1BQU03RiwyQkFBMkIsQ0FBQyxDQUFDO0lBQ3ZELElBQUksQ0FBQzZGLFdBQVcsQ0FBQ0MsUUFBUSxFQUFFO01BQ3pCaEcsUUFBUSxDQUFDLCtCQUErQixFQUFFO1FBQ3hDd0UsTUFBTSxFQUNKLGNBQWMsSUFBSXpFLDBEQUEwRDtRQUM5RWtHLG1CQUFtQixFQUFFRixXQUFXLENBQUNHLE1BQU0sQ0FDcENDLEdBQUcsQ0FBQzVCLENBQUMsSUFBSUEsQ0FBQyxDQUFDNkIsSUFBSSxDQUFDLENBQ2hCL0QsSUFBSSxDQUNILEdBQ0YsQ0FBQyxJQUFJdEM7TUFDVCxDQUFDLENBQUM7TUFDRixNQUFNc0csT0FBTyxHQUFHTixXQUFXLENBQUNHLE1BQU0sQ0FBQ0MsR0FBRyxDQUFDaEcsdUJBQXVCLENBQUMsQ0FBQ2tDLElBQUksQ0FBQyxJQUFJLENBQUM7TUFDMUUxQiwwQkFBMEIsQ0FBQztRQUN6QnlELEtBQUssRUFBRSw4Q0FBOENpQyxPQUFPLEVBQUU7UUFDOURoQyxJQUFJLEVBQUU7TUFDUixDQUFDLENBQUM7TUFDRjtJQUNGO0lBRUEsTUFBTWlDLE1BQU0sR0FBR3RFLG9CQUFvQixDQUFDQyxLQUFLLEVBQUVDLFFBQVEsQ0FBQztJQUNwRCxJQUFJcUUsYUFBYSxFQUFFLE1BQU0sR0FBRyxTQUFTO0lBQ3JDLE1BQU1DLE9BQU8sR0FBRyxNQUFNekYsZ0JBQWdCLENBQUM7TUFDckMwRixjQUFjLEVBQUVILE1BQU07TUFDdEJJLFdBQVcsRUFBRXpFLEtBQUssSUFBSSxtQkFBbUI7TUFDekM2RCxLQUFLO01BQ0xhLGNBQWMsRUFBRSxNQUFNO01BQ3RCQyxTQUFTLEVBQUUsSUFBSTtNQUNmcEIsTUFBTTtNQUNOcUIscUJBQXFCLEVBQUUsSUFBSTtNQUMzQkMsWUFBWSxFQUFFbkIsR0FBRyxJQUFJO1FBQ25CWSxhQUFhLEdBQUdaLEdBQUc7TUFDckI7SUFDRixDQUFDLENBQUM7SUFDRixJQUFJLENBQUNhLE9BQU8sRUFBRTtNQUNaeEcsUUFBUSxDQUFDLCtCQUErQixFQUFFO1FBQ3hDd0UsTUFBTSxFQUFFLENBQUMrQixhQUFhLEdBQ2xCLGFBQWEsR0FDYixlQUFlLEtBQUt4RztNQUMxQixDQUFDLENBQUM7TUFDRlksMEJBQTBCLENBQUM7UUFDekJ5RCxLQUFLLEVBQUUscUNBQXFDbUMsYUFBYSxHQUFHLE1BQU1BLGFBQWEsRUFBRSxHQUFHLEVBQUUsNEJBQTRCO1FBQ2xIbEMsSUFBSSxFQUFFO01BQ1IsQ0FBQyxDQUFDO01BQ0Y7SUFDRjtJQUNBN0IsU0FBUyxHQUFHZ0UsT0FBTyxDQUFDTyxFQUFFO0lBRXRCLE1BQU10RSxHQUFHLEdBQUc1QyxtQkFBbUIsQ0FBQzJHLE9BQU8sQ0FBQ08sRUFBRSxFQUFFbEYsT0FBTyxDQUFDQyxHQUFHLENBQUNzRCxtQkFBbUIsQ0FBQztJQUM1RXpDLFdBQVcsQ0FBQ0UsSUFBSSxLQUFLO01BQ25CLEdBQUdBLElBQUk7TUFDUHNCLG1CQUFtQixFQUFFMUIsR0FBRztNQUN4QjBDLGtCQUFrQixFQUFFMUI7SUFDdEIsQ0FBQyxDQUFDLENBQUM7SUFDSGlDLGNBQWMsR0FBR1osd0JBQXdCLENBQUNyQyxHQUFHLENBQUMsQ0FBQztJQUMvQ3pDLFFBQVEsQ0FBQywwQkFBMEIsRUFBRTtNQUNuQ2dILGFBQWEsRUFBRUMsT0FBTyxDQUFDL0UsUUFBUSxDQUFDO01BQ2hDNEQsS0FBSyxFQUNIQSxLQUFLLElBQUkvRjtJQUNiLENBQUMsQ0FBQztJQUNGO0lBQ0E7SUFDQSxNQUFNO01BQUV3QztJQUFPLENBQUMsR0FBR2pDLHVCQUF1QixDQUFDO01BQ3pDNEcsY0FBYyxFQUFFLFdBQVc7TUFDM0JWLE9BQU8sRUFBRTtRQUFFTyxFQUFFLEVBQUVQLE9BQU8sQ0FBQ08sRUFBRTtRQUFFSSxLQUFLLEVBQUVsRixLQUFLLElBQUk7TUFBWSxDQUFDO01BQ3hEbUYsT0FBTyxFQUFFbkYsS0FBSztNQUNkb0YsT0FBTyxFQUFFO1FBQ1BDLGVBQWUsRUFBRSxJQUFJQyxlQUFlLENBQUMsQ0FBQztRQUN0QzdFLFdBQVc7UUFDWEM7TUFDRixDQUFDO01BQ0Q2RSxXQUFXLEVBQUU7SUFDZixDQUFDLENBQUM7SUFDRmxGLGlCQUFpQixDQUFDQyxNQUFNLEVBQUVpRSxPQUFPLENBQUNPLEVBQUUsRUFBRXRFLEdBQUcsRUFBRUMsV0FBVyxFQUFFQyxXQUFXLENBQUM7RUFDdEUsQ0FBQyxDQUFDLE9BQU80QixDQUFDLEVBQUU7SUFDVjdELFFBQVEsQ0FBQzZELENBQUMsQ0FBQztJQUNYdkUsUUFBUSxDQUFDLCtCQUErQixFQUFFO01BQ3hDd0UsTUFBTSxFQUNKLGtCQUFrQixJQUFJekU7SUFDMUIsQ0FBQyxDQUFDO0lBQ0ZZLDBCQUEwQixDQUFDO01BQ3pCeUQsS0FBSyxFQUFFLGlDQUFpQzNELFlBQVksQ0FBQzhELENBQUMsQ0FBQyxFQUFFO01BQ3pERixJQUFJLEVBQUU7SUFDUixDQUFDLENBQUM7SUFDRixJQUFJN0IsU0FBUyxFQUFFO01BQ2I7TUFDQTtNQUNBLEtBQUsxQixvQkFBb0IsQ0FBQzBCLFNBQVMsQ0FBQyxDQUFDaUMsS0FBSyxDQUFDZ0QsR0FBRyxJQUM1Q2pILGVBQWUsQ0FBQywrQ0FBK0MsRUFBRWlILEdBQUcsQ0FDdEUsQ0FBQztNQUNEO01BQ0E7TUFDQTlFLFdBQVcsQ0FBQ0UsSUFBSSxJQUNkQSxJQUFJLENBQUNzQixtQkFBbUIsR0FDcEI7UUFBRSxHQUFHdEIsSUFBSTtRQUFFc0IsbUJBQW1CLEVBQUVWO01BQVUsQ0FBQyxHQUMzQ1osSUFDTixDQUFDO0lBQ0g7RUFDRixDQUFDLFNBQVM7SUFDUjtJQUNBRixXQUFXLENBQUNFLElBQUksSUFDZEEsSUFBSSxDQUFDc0Msa0JBQWtCLEdBQ25CO01BQUUsR0FBR3RDLElBQUk7TUFBRXNDLGtCQUFrQixFQUFFMUI7SUFBVSxDQUFDLEdBQzFDWixJQUNOLENBQUM7RUFDSDtBQUNGO0FBRUEsTUFBTTZFLElBQUksRUFBRW5ILG1CQUFtQixHQUFHLE1BQUFtSCxDQUFPQyxNQUFNLEVBQUVOLE9BQU8sRUFBRU8sSUFBSSxLQUFLO0VBQ2pFLE1BQU0zRixLQUFLLEdBQUcyRixJQUFJLENBQUNDLElBQUksQ0FBQyxDQUFDOztFQUV6QjtFQUNBLElBQUksQ0FBQzVGLEtBQUssRUFBRTtJQUNWLE1BQU0wRCxHQUFHLEdBQUcsTUFBTUwsZUFBZSxDQUFDO01BQ2hDckQsS0FBSztNQUNMUyxXQUFXLEVBQUUyRSxPQUFPLENBQUMzRSxXQUFXO01BQ2hDQyxXQUFXLEVBQUUwRSxPQUFPLENBQUMxRSxXQUFXO01BQ2hDNkMsTUFBTSxFQUFFNkIsT0FBTyxDQUFDQyxlQUFlLENBQUM5QjtJQUNsQyxDQUFDLENBQUM7SUFDRm1DLE1BQU0sQ0FBQ2hDLEdBQUcsRUFBRTtNQUFFbUMsT0FBTyxFQUFFO0lBQVMsQ0FBQyxDQUFDO0lBQ2xDLE9BQU8sSUFBSTtFQUNiOztFQUVBO0VBQ0E7RUFDQTtFQUNBLE1BQU07SUFBRTNELG1CQUFtQixFQUFFeUIsTUFBTTtJQUFFVDtFQUFtQixDQUFDLEdBQ3ZEa0MsT0FBTyxDQUFDM0UsV0FBVyxDQUFDLENBQUM7RUFDdkIsSUFBSWtELE1BQU0sSUFBSVQsa0JBQWtCLEVBQUU7SUFDaENuRixRQUFRLENBQUMsK0JBQStCLEVBQUU7TUFDeEN3RSxNQUFNLEVBQUUsQ0FBQ29CLE1BQU0sR0FDWCxpQkFBaUIsR0FDakIsbUJBQW1CLEtBQUs3RjtJQUM5QixDQUFDLENBQUM7SUFDRjRILE1BQU0sQ0FBQzVDLHlCQUF5QixDQUFDYSxNQUFNLENBQUMsRUFBRTtNQUFFa0MsT0FBTyxFQUFFO0lBQVMsQ0FBQyxDQUFDO0lBQ2hFLE9BQU8sSUFBSTtFQUNiOztFQUVBO0VBQ0E7RUFDQTtFQUNBVCxPQUFPLENBQUMxRSxXQUFXLENBQUNFLElBQUksS0FBSztJQUFFLEdBQUdBLElBQUk7SUFBRWtGLHNCQUFzQixFQUFFO01BQUU5RjtJQUFNO0VBQUUsQ0FBQyxDQUFDLENBQUM7RUFDN0U7RUFDQTtFQUNBMEYsTUFBTSxDQUFDbEUsU0FBUyxFQUFFO0lBQUVxRSxPQUFPLEVBQUU7RUFBTyxDQUFDLENBQUM7RUFDdEMsT0FBTyxJQUFJO0FBQ2IsQ0FBQztBQUVELGVBQWU7RUFDYjFCLElBQUksRUFBRSxXQUFXO0VBQ2pCNEIsSUFBSSxFQUFFLFdBQVc7RUFDakJ0QixXQUFXLEVBQUUsNkZBQTZGdkYsYUFBYSxFQUFFO0VBQ3pIOEcsWUFBWSxFQUFFLFVBQVU7RUFDeEJDLFNBQVMsRUFBRUEsQ0FBQSxLQUFNLFVBQVUsS0FBSyxLQUFLO0VBQ3JDQyxJQUFJLEVBQUVBLENBQUEsS0FBTWxELE9BQU8sQ0FBQ21ELE9BQU8sQ0FBQztJQUFFVjtFQUFLLENBQUM7QUFDdEMsQ0FBQyxXQUFXL0gsT0FBTyIsImlnbm9yZUxpc3QiOltdfQ== diff --git a/src/constants/prompts.ts b/src/constants/prompts.ts index 83653112..23e62bac 100644 --- a/src/constants/prompts.ts +++ b/src/constants/prompts.ts @@ -115,12 +115,13 @@ export const SYSTEM_PROMPT_DYNAMIC_BOUNDARY = '__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__' // @[MODEL LAUNCH]: Update the latest frontier model. -const FRONTIER_MODEL_NAME = 'Claude Opus 4.7' +const FRONTIER_MODEL_NAME = 'Claude Opus 4.8' // @[MODEL LAUNCH]: Update the model family IDs below to the latest in each tier. -const CLAUDE_4_5_OR_4_6_MODEL_IDS = { - opus: 'claude-opus-4-7', - sonnet: 'claude-sonnet-4-6', +const LATEST_CLAUDE_MODEL_IDS = { + fable: 'claude-fable-5', + opus: 'claude-opus-4-8', + sonnet: 'claude-sonnet-5', haiku: 'claude-haiku-4-5', } @@ -693,7 +694,7 @@ export async function computeSimpleEnvInfo( knowledgeCutoffMessage, process.env.USER_TYPE === 'ant' && isUndercover() ? null - : `The most recent Claude model family is Claude 4.5/4.6. Model IDs — Opus 4.7: '${CLAUDE_4_5_OR_4_6_MODEL_IDS.opus}', Sonnet 4.6: '${CLAUDE_4_5_OR_4_6_MODEL_IDS.sonnet}', Haiku 4.5: '${CLAUDE_4_5_OR_4_6_MODEL_IDS.haiku}'. When building AI applications, default to the latest and most capable Claude models.`, + : `The most recent Claude flagship models are Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5, and Claude Haiku 4.5. Model IDs — Fable 5: '${LATEST_CLAUDE_MODEL_IDS.fable}', Opus 4.8: '${LATEST_CLAUDE_MODEL_IDS.opus}', Sonnet 5: '${LATEST_CLAUDE_MODEL_IDS.sonnet}', Haiku 4.5: '${LATEST_CLAUDE_MODEL_IDS.haiku}'. When building AI applications, default to the latest and most capable Claude models.`, process.env.USER_TYPE === 'ant' && isUndercover() ? null : `Claude Code is available as a CLI in the terminal, desktop app (Mac/Windows), web app (claude.ai/code), and IDE extensions (VS Code, JetBrains).`, @@ -712,7 +713,13 @@ export async function computeSimpleEnvInfo( // @[MODEL LAUNCH]: Add a knowledge cutoff date for the new model. function getKnowledgeCutoff(modelId: string): string | null { const canonical = getCanonicalName(modelId) - if (canonical.includes('claude-sonnet-4-6')) { + if ( + canonical.includes('claude-fable-5') || + canonical.includes('claude-opus-4-8') || + canonical.includes('claude-sonnet-5') + ) { + return 'January 2026' + } else if (canonical.includes('claude-sonnet-4-6')) { return 'August 2025' } else if (canonical.includes('claude-opus-4-7')) { return 'May 2025' diff --git a/src/server/__tests__/e2e/business-flow.test.ts b/src/server/__tests__/e2e/business-flow.test.ts index adb0d593..cbd0fc97 100644 --- a/src/server/__tests__/e2e/business-flow.test.ts +++ b/src/server/__tests__/e2e/business-flow.test.ts @@ -374,27 +374,28 @@ describe('Business Flow: Models & Effort', () => { it('should return available fallback models', async () => { const { data } = await api('GET', '/api/models') - expect(data.models.length).toBe(3) + expect(data.models.length).toBe(4) const names = data.models.map((m: any) => m.name) - expect(names).toContain('Opus 4.7') - expect(names).toContain('Sonnet 4.6') + expect(names).toContain('Fable 5') + expect(names).toContain('Opus 4.8') + expect(names).toContain('Sonnet 5') expect(names).toContain('Haiku 4.5') }) it('should default to Opus model', async () => { const { data } = await api('GET', '/api/models/current') - expect(data.model.id).toBe('claude-opus-4-7') + expect(data.model.id).toBe('claude-opus-4-8') }) - it('should switch to Opus 4.7', async () => { + it('should switch to Opus 4.8', async () => { const { status } = await api('PUT', '/api/models/current', { - modelId: 'claude-opus-4-7', + modelId: 'claude-opus-4-8', }) expect(status).toBe(200) const { data } = await api('GET', '/api/models/current') - expect(data.model.id).toBe('claude-opus-4-7') - expect(data.model.name).toBe('Opus 4.7') + expect(data.model.id).toBe('claude-opus-4-8') + expect(data.model.name).toBe('Opus 4.8') }) it('should switch to Haiku 4.5', async () => { diff --git a/src/server/__tests__/e2e/full-flow.test.ts b/src/server/__tests__/e2e/full-flow.test.ts index 74d910d7..014cec62 100644 --- a/src/server/__tests__/e2e/full-flow.test.ts +++ b/src/server/__tests__/e2e/full-flow.test.ts @@ -205,8 +205,8 @@ describe('E2E: Full Flow', () => { it('should list available models', async () => { const { data } = await api('GET', '/api/models') - expect(data.models.length).toBe(3) - expect(data.models[0].name).toBe('Opus 4.7') + expect(data.models.length).toBe(4) + expect(data.models[0].name).toBe('Fable 5') }) it('should switch model', async () => { diff --git a/src/server/__tests__/provider-runtime-env.test.ts b/src/server/__tests__/provider-runtime-env.test.ts index 9002ee2a..f8101283 100644 --- a/src/server/__tests__/provider-runtime-env.test.ts +++ b/src/server/__tests__/provider-runtime-env.test.ts @@ -82,6 +82,7 @@ describe('providerRuntimeEnv', () => { apiFormat: 'anthropic', models: { main: 'active-main', + fable: 'active-fable', haiku: '', sonnet: 'active-sonnet', opus: '', @@ -98,6 +99,9 @@ describe('providerRuntimeEnv', () => { ANTHROPIC_AUTH_TOKEN: 'sk-active', ENABLE_TOOL_SEARCH: 'true', ANTHROPIC_MODEL: 'active-main', + ANTHROPIC_DEFAULT_FABLE_MODEL: 'active-fable', + ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES: + 'thinking,effort,adaptive_thinking,xhigh_effort,max_effort', ANTHROPIC_DEFAULT_HAIKU_MODEL: 'active-main', ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES: 'thinking,effort,adaptive_thinking,xhigh_effort,max_effort', diff --git a/src/server/__tests__/settings.test.ts b/src/server/__tests__/settings.test.ts index 6ad218c1..670b0df1 100644 --- a/src/server/__tests__/settings.test.ts +++ b/src/server/__tests__/settings.test.ts @@ -24,7 +24,17 @@ import { primeKeychainCacheFromPrefetch, } from '../../utils/secureStorage/macOsKeychainHelpers.js' import type { OpenAIOAuthTokens } from '../../services/openaiAuth/types.js' -import { getModelOptions } from '../../utils/model/modelOptions.js' +import { + getMaxOpus46_1MOption, + getMaxSonnet46_1MOption, + getModelOptions, + getOpus46_1MOption, + getSonnet46_1MOption, +} from '../../utils/model/modelOptions.js' +import { + getDefaultMainLoopModelSetting, + parseUserSpecifiedModel, +} from '../../utils/model/model.js' import { getSettingsForSource, updateSettingsForSource, @@ -49,6 +59,8 @@ let originalAnthropicDefaultHaikuModel: string | undefined let originalAnthropicDefaultSonnetModel: string | undefined let originalAnthropicDefaultOpusModel: string | undefined let originalAnthropicDefaultFableModel: string | undefined +let originalAnthropicDefaultFableModelName: string | undefined +let originalDisable1mContext: string | undefined async function setup() { tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'claude-test-')) @@ -68,6 +80,8 @@ async function setup() { originalAnthropicDefaultSonnetModel = process.env.ANTHROPIC_DEFAULT_SONNET_MODEL originalAnthropicDefaultOpusModel = process.env.ANTHROPIC_DEFAULT_OPUS_MODEL originalAnthropicDefaultFableModel = process.env.ANTHROPIC_DEFAULT_FABLE_MODEL + originalAnthropicDefaultFableModelName = process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_NAME + originalDisable1mContext = process.env.CLAUDE_CODE_DISABLE_1M_CONTEXT process.env.CLAUDE_CONFIG_DIR = tmpDir process.env.HOME = tmpDir process.env.USERPROFILE = tmpDir @@ -80,6 +94,8 @@ async function setup() { delete process.env.ANTHROPIC_DEFAULT_SONNET_MODEL delete process.env.ANTHROPIC_DEFAULT_OPUS_MODEL delete process.env.ANTHROPIC_DEFAULT_FABLE_MODEL + delete process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_NAME + delete process.env.CLAUDE_CODE_DISABLE_1M_CONTEXT clearKeychainCache() primeKeychainCacheFromPrefetch(null) clearOpenAIOAuthTokenCache() @@ -171,6 +187,18 @@ async function teardown() { delete process.env.ANTHROPIC_DEFAULT_FABLE_MODEL } + if (originalAnthropicDefaultFableModelName !== undefined) { + process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_NAME = originalAnthropicDefaultFableModelName + } else { + delete process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_NAME + } + + if (originalDisable1mContext !== undefined) { + process.env.CLAUDE_CODE_DISABLE_1M_CONTEXT = originalDisable1mContext + } else { + delete process.env.CLAUDE_CODE_DISABLE_1M_CONTEXT + } + await fs.rm(tmpDir, { recursive: true, force: true }) } @@ -645,9 +673,36 @@ describe('Models API', () => { expect(res.status).toBe(200) const body = await res.json() - expect(body.models).toBeArray() - expect(body.models.length).toBe(3) - expect(body.models[0].id).toContain('claude') + expect(body.models).toEqual([ + { + id: 'claude-fable-5', + name: 'Fable 5', + description: 'Highest capability for long-running tasks', + context: '1m', + }, + { + id: 'claude-opus-4-8', + name: 'Opus 4.8', + description: 'Best for complex agentic coding and enterprise work', + context: '1m', + defaultReasoningEffort: 'high', + supportedReasoningEfforts: ['low', 'medium', 'high', 'xhigh', 'max'], + }, + { + id: 'claude-sonnet-5', + name: 'Sonnet 5', + description: 'Best combination of speed and intelligence', + context: '1m', + defaultReasoningEffort: 'high', + supportedReasoningEfforts: ['low', 'medium', 'high', 'xhigh', 'max'], + }, + { + id: 'claude-haiku-4-5', + name: 'Haiku 4.5', + description: 'Fastest with near-frontier intelligence', + context: '200k', + }, + ]) }) it('GET /api/models should merge env-configured provider models with saved OpenAI OAuth models', async () => { @@ -731,7 +786,7 @@ describe('Models API', () => { expect(res.status).toBe(200) const body = await res.json() - expect(body.model.id).toBe('claude-opus-4-7') + expect(body.model.id).toBe('claude-opus-4-8') }) it('GET /api/models/current should respect env-configured default model when no provider is active', async () => { @@ -976,6 +1031,92 @@ describe('Model Options', () => { beforeEach(setup) afterEach(teardown) + it('defaults Anthropic API users to Opus 4.8 and exposes the current official options once', () => { + process.env.ANTHROPIC_API_KEY = 'test-api-key' + + expect(getDefaultMainLoopModelSetting()).toBe('claude-opus-4-8') + + const options = getModelOptions() + const values = options.map(option => option.value) + + expect(options[0]?.description).toContain('Opus 4.8') + expect(options[0]?.description).toContain('$5') + expect(values).toContain('fable') + expect(values).toContain('sonnet') + expect(values).not.toContain('opus') + expect(values).not.toContain('opus[1m]') + }) + + it('keeps Anthropic-compatible third-party URLs on lag-safe defaults', () => { + process.env.ANTHROPIC_API_KEY = 'third-party-key' + process.env.ANTHROPIC_BASE_URL = 'https://api.deepseek.com/anthropic' + + expect(getDefaultMainLoopModelSetting()).toBe('claude-sonnet-4-5-20250929') + expect(parseUserSpecifiedModel('best')).toBe('claude-opus-4-7') + expect(parseUserSpecifiedModel('fable')).toBe('claude-opus-4-7') + + const options = getModelOptions() + const values = options.map(option => option.value) + + expect(options[0]?.description).toContain('Sonnet 4.5') + expect(values).not.toContain('fable') + expect(values).not.toContain('claude-fable-5') + }) + + it('exposes a custom Fable alias only when a third-party provider configures it', () => { + process.env.ANTHROPIC_API_KEY = 'third-party-key' + process.env.ANTHROPIC_BASE_URL = 'https://api.deepseek.com/anthropic' + process.env.ANTHROPIC_DEFAULT_FABLE_MODEL = 'deepseek-v4-fable' + process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_NAME = 'DeepSeek Fable' + + expect(parseUserSpecifiedModel('fable')).toBe('deepseek-v4-fable') + expect(parseUserSpecifiedModel('best')).toBe('deepseek-v4-fable') + expect(getModelOptions()).toContainEqual(expect.objectContaining({ + value: 'fable', + label: 'DeepSeek Fable', + })) + }) + + it('labels extended-context options with current first-party and conservative third-party names', () => { + process.env.ANTHROPIC_API_KEY = 'test-api-key' + + expect(getSonnet46_1MOption().description).toContain('Sonnet 5') + expect(getOpus46_1MOption().description).toContain('Opus 4.8') + expect(getMaxSonnet46_1MOption().description).toContain('Sonnet 5') + expect(getMaxOpus46_1MOption().description).toContain('Opus 4.8') + + process.env.ANTHROPIC_BASE_URL = 'https://api.deepseek.com/anthropic' + + expect(getSonnet46_1MOption().description).toContain('Sonnet 4.6') + expect(getOpus46_1MOption().description).toContain('Opus 4.7') + }) + + it('does not offer redundant Sonnet 1M choices when extended context is disabled', () => { + process.env.ANTHROPIC_API_KEY = 'test-api-key' + process.env.CLAUDE_CODE_DISABLE_1M_CONTEXT = '1' + + expect(getModelOptions().map(option => option.value)).not.toContain('sonnet[1m]') + }) + + it('renders explicit current aliases and Fable model IDs with current marketing names', () => { + process.env.ANTHROPIC_API_KEY = 'test-api-key' + + process.env.ANTHROPIC_MODEL = 'opus' + expect(getModelOptions().find(option => option.value === 'opus')?.description) + .toContain('Opus 4.8') + + process.env.ANTHROPIC_MODEL = 'opus[1m]' + expect(getModelOptions().find(option => option.value === 'opus[1m]')?.description) + .toContain('Opus 4.8') + + process.env.ANTHROPIC_MODEL = 'claude-fable-5' + expect(getModelOptions()).toContainEqual(expect.objectContaining({ + value: 'claude-fable-5', + label: 'Fable 5', + description: 'claude-fable-5', + })) + }) + it('should keep OpenAI OAuth models visible alongside env-configured provider models', () => { process.env.ANTHROPIC_API_KEY = 'deepseek-key' process.env.ANTHROPIC_BASE_URL = 'https://api.deepseek.com/anthropic' diff --git a/src/server/api/models.ts b/src/server/api/models.ts index cc8b6ee2..04ad5930 100644 --- a/src/server/api/models.ts +++ b/src/server/api/models.ts @@ -39,28 +39,38 @@ import { hahaGrokOAuthService } from '../services/hahaGrokOAuthService.js' const DEFAULT_MODELS = [ { - id: 'claude-opus-4-7', - name: 'Opus 4.7', - description: 'Most capable for ambitious work', + id: 'claude-fable-5', + name: 'Fable 5', + description: 'Highest capability for long-running tasks', context: '1m', }, { - id: 'claude-sonnet-4-6', - name: 'Sonnet 4.6', - description: 'Most efficient for everyday tasks', - context: '200k', + id: 'claude-opus-4-8', + name: 'Opus 4.8', + description: 'Best for complex agentic coding and enterprise work', + context: '1m', + defaultReasoningEffort: 'high', + supportedReasoningEfforts: ['low', 'medium', 'high', 'xhigh', 'max'], + }, + { + id: 'claude-sonnet-5', + name: 'Sonnet 5', + description: 'Best combination of speed and intelligence', + context: '1m', + defaultReasoningEffort: 'high', + supportedReasoningEfforts: ['low', 'medium', 'high', 'xhigh', 'max'], }, { id: 'claude-haiku-4-5', name: 'Haiku 4.5', - description: 'Fastest for quick answers', + description: 'Fastest with near-frontier intelligence', context: '200k', }, ] as const const EFFORT_LEVELS = ['low', 'medium', 'high', 'max'] as const -const DEFAULT_MODEL = 'claude-opus-4-7' +const DEFAULT_MODEL = 'claude-opus-4-8' const DEFAULT_EFFORT = 'max' const settingsService = new SettingsService() diff --git a/src/server/config/providerPresets.ts b/src/server/config/providerPresets.ts index 29bc83f5..ef2d7e42 100644 --- a/src/server/config/providerPresets.ts +++ b/src/server/config/providerPresets.ts @@ -8,6 +8,7 @@ import { ApiFormatSchema, ProviderAuthStrategySchema } from '../types/provider.j const ModelMappingSchema = z.object({ main: z.string(), + fable: z.string().optional(), haiku: z.string(), sonnet: z.string(), opus: z.string(), diff --git a/src/server/services/conversationService.ts b/src/server/services/conversationService.ts index 0767824d..51c631cc 100644 --- a/src/server/services/conversationService.ts +++ b/src/server/services/conversationService.ts @@ -1336,6 +1336,10 @@ export class ConversationService { 'ANTHROPIC_AUTH_TOKEN', 'ENABLE_TOOL_SEARCH', 'ANTHROPIC_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_NAME', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_HAIKU_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_SONNET_MODEL', @@ -1600,6 +1604,10 @@ export class ConversationService { 'ANTHROPIC_AUTH_TOKEN', 'ENABLE_TOOL_SEARCH', 'ANTHROPIC_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_NAME', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_HAIKU_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_SONNET_MODEL', diff --git a/src/server/services/persistentStorageMigrations.ts b/src/server/services/persistentStorageMigrations.ts index 477877e5..0dab50b0 100644 --- a/src/server/services/persistentStorageMigrations.ts +++ b/src/server/services/persistentStorageMigrations.ts @@ -44,6 +44,7 @@ function isProviderModels(value: unknown): value is JsonObject { return ( isRecord(value) && typeof value.main === 'string' && + (value.fable === undefined || typeof value.fable === 'string') && typeof value.haiku === 'string' && typeof value.sonnet === 'string' && typeof value.opus === 'string' @@ -311,6 +312,7 @@ function buildManagedSettingsForMigratedProvider(provider: JsonObject | undefine ANTHROPIC_BASE_URL: baseUrl, ANTHROPIC_AUTH_TOKEN: apiKey, ANTHROPIC_MODEL: provider.models.main, + ...(provider.models.fable ? { ANTHROPIC_DEFAULT_FABLE_MODEL: provider.models.fable } : {}), ANTHROPIC_DEFAULT_HAIKU_MODEL: provider.models.haiku, ANTHROPIC_DEFAULT_SONNET_MODEL: provider.models.sonnet, ANTHROPIC_DEFAULT_OPUS_MODEL: provider.models.opus, diff --git a/src/server/services/providerRuntimeEnv.ts b/src/server/services/providerRuntimeEnv.ts index 7a850038..52726dda 100644 --- a/src/server/services/providerRuntimeEnv.ts +++ b/src/server/services/providerRuntimeEnv.ts @@ -36,6 +36,10 @@ export const MANAGED_PROVIDER_ENV_KEYS = [ 'ENABLE_TOOL_SEARCH', 'CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS', 'ANTHROPIC_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_NAME', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_HAIKU_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_SONNET_MODEL', @@ -67,6 +71,7 @@ function isProviderModels(value: unknown): value is SavedProvider['models'] { return ( isRecord(value) && typeof value.main === 'string' && + (value.fable === undefined || typeof value.fable === 'string') && typeof value.haiku === 'string' && typeof value.sonnet === 'string' && typeof value.opus === 'string' @@ -128,6 +133,7 @@ export function normalizeModelMapping(models: SavedProvider['models']): SavedPro const main = models.main.trim() return { main, + ...(models.fable?.trim() ? { fable: models.fable.trim() } : {}), haiku: models.haiku.trim() || main, sonnet: models.sonnet.trim() || main, opus: models.opus.trim() || main, @@ -159,6 +165,7 @@ function applyModel1mSupportMapping( ): SavedProvider['models'] { return { main: applyModel1mSupport(models.main, model1mSupport?.main), + ...(models.fable ? { fable: models.fable.trim() } : {}), haiku: applyModel1mSupport(models.haiku, model1mSupport?.haiku), sonnet: applyModel1mSupport(models.sonnet, model1mSupport?.sonnet), opus: applyModel1mSupport(models.opus, model1mSupport?.opus), @@ -309,6 +316,9 @@ function getProviderCapabilityEnv( if (provider.presetId === 'custom') { const capabilities = getCustomProviderModelCapabilities(provider, models) return { + ...(models.fable + ? { ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES: capabilities } + : {}), ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES: capabilities, ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES: capabilities, ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES: capabilities, @@ -409,6 +419,9 @@ export function buildProviderManagedEnv( ANTHROPIC_BASE_URL: baseUrl, ...buildProviderAuthEnv(provider, presetDefaultEnv, needsProxy), ANTHROPIC_MODEL: runtimeModels.main, + ...(runtimeModels.fable && { + ANTHROPIC_DEFAULT_FABLE_MODEL: runtimeModels.fable, + }), ANTHROPIC_DEFAULT_HAIKU_MODEL: runtimeModels.haiku, ANTHROPIC_DEFAULT_SONNET_MODEL: runtimeModels.sonnet, ANTHROPIC_DEFAULT_OPUS_MODEL: runtimeModels.opus, diff --git a/src/server/services/sessionService.ts b/src/server/services/sessionService.ts index 6db9ce9e..e0842a4d 100644 --- a/src/server/services/sessionService.ts +++ b/src/server/services/sessionService.ts @@ -2208,6 +2208,7 @@ export class SessionService { // (e.g. "LongCat-2.0-Preview-LongCatAI" instead of "LongCat-2.0-Preview"). const providerEnvModelKeys = [ 'ANTHROPIC_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL', 'ANTHROPIC_DEFAULT_SONNET_MODEL', 'ANTHROPIC_DEFAULT_OPUS_MODEL', @@ -2280,6 +2281,7 @@ export class SessionService { const matches: number[] = [] const providerEnvModelKeys = [ 'ANTHROPIC_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL', 'ANTHROPIC_DEFAULT_SONNET_MODEL', 'ANTHROPIC_DEFAULT_OPUS_MODEL', diff --git a/src/server/types/provider.ts b/src/server/types/provider.ts index 8b3a89a1..4b5c8ecf 100644 --- a/src/server/types/provider.ts +++ b/src/server/types/provider.ts @@ -45,6 +45,7 @@ export type ProviderRuntimeKind = z.infer export const ModelMappingSchema = z.object({ main: z.string(), + fable: z.string().optional(), haiku: z.string(), sonnet: z.string(), opus: z.string(), diff --git a/src/skills/bundled/claudeApiContent.ts b/src/skills/bundled/claudeApiContent.ts index 82078500..901cf3c8 100644 --- a/src/skills/bundled/claudeApiContent.ts +++ b/src/skills/bundled/claudeApiContent.ts @@ -34,10 +34,10 @@ import typescriptClaudeApiToolUse from './claude-api/typescript/claude-api/tool- // - claude-api/SKILL.md (Current Models pricing table) // - claude-api/shared/models.md (full model catalog with legacy versions and alias mappings) export const SKILL_MODEL_VARS = { - OPUS_ID: 'claude-opus-4-7', - OPUS_NAME: 'Claude Opus 4.7', - SONNET_ID: 'claude-sonnet-4-6', - SONNET_NAME: 'Claude Sonnet 4.6', + OPUS_ID: 'claude-opus-4-8', + OPUS_NAME: 'Claude Opus 4.8', + SONNET_ID: 'claude-sonnet-5', + SONNET_NAME: 'Claude Sonnet 5', HAIKU_ID: 'claude-haiku-4-5', HAIKU_NAME: 'Claude Haiku 4.5', // Previous Sonnet ID — used in "do not append date suffixes" example in SKILL.md. diff --git a/src/utils/__tests__/providerManagedEnvCompat.test.ts b/src/utils/__tests__/providerManagedEnvCompat.test.ts index 571e6ec2..14d5672a 100644 --- a/src/utils/__tests__/providerManagedEnvCompat.test.ts +++ b/src/utils/__tests__/providerManagedEnvCompat.test.ts @@ -13,6 +13,9 @@ describe('provider managed env compatibility', () => { expect(changed).toBe(true) expect(env.CC_HAHA_SEND_DISABLED_THINKING).toBeUndefined() + expect(env.ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES).toBe( + 'thinking,effort,adaptive_thinking,max_effort', + ) expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES).toBe( 'thinking,effort,adaptive_thinking,max_effort', ) diff --git a/src/utils/__tests__/thinking.test.ts b/src/utils/__tests__/thinking.test.ts index 8964c468..50599084 100644 --- a/src/utils/__tests__/thinking.test.ts +++ b/src/utils/__tests__/thinking.test.ts @@ -1,6 +1,15 @@ import { afterEach, beforeEach, describe, expect, test } from 'bun:test' import { get3PModelCapabilityOverride } from '../model/modelSupportOverrides.js' import { resolveSideQueryThinkingConfig } from '../sideQuery.js' +import { + getModelBetas, + modelSupportsAutoMode, + modelSupportsContextManagement, + modelSupportsISP, + modelSupportsStructuredOutputs, + shouldIncludeFirstPartyOnlyBetas, + shouldUseGlobalCacheScope, +} from '../betas.js' import { modelSupportsEffort, modelSupportsMaxEffort, @@ -15,6 +24,7 @@ import { } from '../thinking.js' describe('provider-aware thinking support', () => { + let originalApiKey: string | undefined let originalBaseUrl: string | undefined let originalFableModel: string | undefined let originalFableCapabilities: string | undefined @@ -26,6 +36,7 @@ describe('provider-aware thinking support', () => { let originalExplicitDisabledThinking: string | undefined beforeEach(() => { + originalApiKey = process.env.ANTHROPIC_API_KEY originalBaseUrl = process.env.ANTHROPIC_BASE_URL originalFableModel = process.env.ANTHROPIC_DEFAULT_FABLE_MODEL originalFableCapabilities = process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES @@ -36,12 +47,14 @@ describe('provider-aware thinking support', () => { originalFoundry = process.env.CLAUDE_CODE_USE_FOUNDRY originalExplicitDisabledThinking = process.env.CC_HAHA_SEND_DISABLED_THINKING + delete process.env.ANTHROPIC_API_KEY delete process.env.CLAUDE_CODE_USE_BEDROCK delete process.env.CLAUDE_CODE_USE_VERTEX delete process.env.CLAUDE_CODE_USE_FOUNDRY }) afterEach(() => { + restoreEnv('ANTHROPIC_API_KEY', originalApiKey) restoreEnv('ANTHROPIC_BASE_URL', originalBaseUrl) restoreEnv('ANTHROPIC_DEFAULT_FABLE_MODEL', originalFableModel) restoreEnv('ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES', originalFableCapabilities) @@ -52,9 +65,11 @@ describe('provider-aware thinking support', () => { restoreEnv('CLAUDE_CODE_USE_FOUNDRY', originalFoundry) restoreEnv('CC_HAHA_SEND_DISABLED_THINKING', originalExplicitDisabledThinking) clearCapabilityCache() + clearBetaCache() }) test('does not assume adaptive thinking for Anthropic-compatible third-party base URLs', () => { + process.env.ANTHROPIC_API_KEY = 'third-party-key' process.env.ANTHROPIC_BASE_URL = 'https://api.jiekou.ai/anthropic' delete process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES clearCapabilityCache() @@ -63,6 +78,7 @@ describe('provider-aware thinking support', () => { }) test('honors explicit provider capability overrides with no supported capabilities', () => { + process.env.ANTHROPIC_API_KEY = 'third-party-key' process.env.ANTHROPIC_BASE_URL = 'https://api.jiekou.ai/anthropic' process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'claude-sonnet-4-6' process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES = 'none' @@ -82,6 +98,23 @@ describe('provider-aware thinking support', () => { expect(modelSupportsAdaptiveThinking('claude-sonnet-4-6')).toBe(true) }) + test('recognizes current first-party flagship model capabilities', () => { + process.env.ANTHROPIC_BASE_URL = 'https://api.anthropic.com' + clearCapabilityCache() + + for (const model of ['claude-fable-5', 'claude-opus-4-8', 'claude-sonnet-5']) { + expect(modelSupportsThinking(model)).toBe(true) + expect(modelSupportsAdaptiveThinking(model)).toBe(true) + expect(modelSupportsEffort(model)).toBe(true) + expect(modelSupportsMaxEffort(model)).toBe(true) + expect(modelSupportsISP(model)).toBe(true) + expect(modelSupportsContextManagement(model)).toBe(true) + expect(modelSupportsStructuredOutputs(model)).toBe(true) + } + expect(shouldIncludeFirstPartyOnlyBetas()).toBe(true) + expect(shouldUseGlobalCacheScope()).toBe(true) + }) + test('normalizes Fable to required adaptive thinking', () => { process.env.ANTHROPIC_BASE_URL = 'https://api.anthropic.com' delete process.env.ANTHROPIC_DEFAULT_FABLE_MODEL @@ -95,6 +128,7 @@ describe('provider-aware thinking support', () => { }) test('lets an explicit third-party capability declaration disable Fable thinking', () => { + process.env.ANTHROPIC_API_KEY = 'third-party-key' process.env.ANTHROPIC_BASE_URL = 'https://provider.example.test/anthropic' process.env.ANTHROPIC_DEFAULT_FABLE_MODEL = 'claude-fable-5' process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES = 'effort' @@ -115,6 +149,7 @@ describe('provider-aware thinking support', () => { }) test('DeepSeek preset can follow the global thinking setting through capability overrides', () => { + process.env.ANTHROPIC_API_KEY = 'third-party-key' process.env.ANTHROPIC_BASE_URL = 'https://api.deepseek.com/anthropic' process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'deepseek-v4-pro' process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES = @@ -131,6 +166,7 @@ describe('provider-aware thinking support', () => { }) test('MiniMax preset models declare adaptive thinking without effort passthrough', () => { + process.env.ANTHROPIC_API_KEY = 'third-party-key' process.env.ANTHROPIC_BASE_URL = 'https://api.minimaxi.com/anthropic' process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'MiniMax-M3[1m]' process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES = @@ -145,6 +181,7 @@ describe('provider-aware thinking support', () => { }) test('Kimi K3 preset requires thinking and supports effort passthrough', () => { + process.env.ANTHROPIC_API_KEY = 'third-party-key' process.env.ANTHROPIC_BASE_URL = 'https://api.kimi.com/coding/' process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'k3' process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES = @@ -163,6 +200,7 @@ describe('provider-aware thinking support', () => { }) test('third-party base URLs do not default unknown model names to effort support', () => { + process.env.ANTHROPIC_API_KEY = 'third-party-key' process.env.ANTHROPIC_BASE_URL = 'https://api.kimi.com/coding/' delete process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES clearCapabilityCache() @@ -171,6 +209,27 @@ describe('provider-aware thinking support', () => { expect(modelSupportsMaxEffort('kimi-k2.6')).toBe(false) }) + test('does not infer first-party effort or betas from current model names on third-party URLs', () => { + process.env.ANTHROPIC_API_KEY = 'third-party-key' + process.env.ANTHROPIC_BASE_URL = 'https://api.deepseek.com/anthropic' + delete process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES + delete process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES + clearCapabilityCache() + clearBetaCache() + + for (const model of ['claude-fable-5', 'claude-opus-4-8', 'claude-sonnet-5']) { + expect(modelSupportsEffort(model)).toBe(false) + expect(modelSupportsMaxEffort(model)).toBe(false) + expect(modelSupportsISP(model)).toBe(false) + expect(modelSupportsContextManagement(model)).toBe(false) + expect(modelSupportsStructuredOutputs(model)).toBe(false) + expect(modelSupportsAutoMode(model)).toBe(false) + expect(getModelBetas(model)).not.toContain('interleaved-thinking-2025-05-14') + } + expect(shouldIncludeFirstPartyOnlyBetas()).toBe(false) + expect(shouldUseGlobalCacheScope()).toBe(false) + }) + test('side queries inherit explicit disabled thinking for opted-in providers', () => { delete process.env.CC_HAHA_SEND_DISABLED_THINKING expect(resolveSideQueryThinkingConfig(undefined, 1024)).toBeUndefined() @@ -195,3 +254,9 @@ function clearCapabilityCache() { cache?: { clear?: () => void } }).cache?.clear?.() } + +function clearBetaCache() { + ;(getModelBetas as typeof getModelBetas & { + cache?: { clear?: () => void } + }).cache?.clear?.() +} diff --git a/src/utils/attribution.ts b/src/utils/attribution.ts index d80654b0..32b20ded 100644 --- a/src/utils/attribution.ts +++ b/src/utils/attribution.ts @@ -69,13 +69,13 @@ export function getAttributionTexts(): AttributionTexts { // @[MODEL LAUNCH]: Update the hardcoded fallback model name below (guards against codename leaks). // For internal repos, use the real model name. For external repos, - // fall back to "Claude Opus 4.7" for unrecognized models to avoid leaking codenames. + // fall back to "Claude Opus 4.8" for unrecognized models to avoid leaking codenames. const model = getMainLoopModel() const isKnownPublicModel = getPublicModelDisplayName(model) !== null const modelName = isInternalModelRepoCached() || isKnownPublicModel ? getPublicModelName(model) - : 'Claude Opus 4.7' + : 'Claude Opus 4.8' const defaultAttribution = `🤖 Generated with [Claude Code](${PRODUCT_URL})` const defaultCommit = `Co-Authored-By: ${modelName} ` diff --git a/src/utils/auth.ts b/src/utils/auth.ts index e2ec4093..235a076e 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -10,7 +10,10 @@ import { logEvent, } from 'src/services/analytics/index.js' import { getModelStrings } from 'src/utils/model/modelStrings.js' -import { getAPIProvider } from 'src/utils/model/providers.js' +import { + getAPIProvider, + isFirstPartyAnthropicBaseUrl, +} from 'src/utils/model/providers.js' import { getIsNonInteractiveSession, preferThirdPartyAuthentication, @@ -129,9 +132,14 @@ export function isAnthropicAuthEnabled(): boolean { process.env.CLAUDE_CODE_API_KEY_FILE_DESCRIPTOR // Check if API key is from an external source (not managed by /login) - const { source: apiKeySource } = getAnthropicApiKeyWithSource({ - skipRetrievingKeyFromApiKeyHelper: true, - }) + let apiKeySource: ApiKeySource = 'none' + try { + ;({ source: apiKeySource } = getAnthropicApiKeyWithSource({ + skipRetrievingKeyFromApiKeyHelper: true, + })) + } catch { + apiKeySource = 'none' + } const hasExternalApiKey = apiKeySource === 'ANTHROPIC_API_KEY' || apiKeySource === 'apiKeyHelper' @@ -1585,7 +1593,14 @@ async function checkAndRefreshOAuthTokenIfNeededImpl( } export function isClaudeAISubscriber(): boolean { - if (!isAnthropicAuthEnabled()) { + let anthropicAuthEnabled = false + try { + anthropicAuthEnabled = isAnthropicAuthEnabled() + } catch { + anthropicAuthEnabled = false + } + + if (!anthropicAuthEnabled) { return false } @@ -1623,6 +1638,10 @@ export function is1PApiCustomer(): boolean { return false } + if (!isFirstPartyAnthropicBaseUrl()) { + return false + } + // Exclude Claude.ai subscribers if (isClaudeAISubscriber()) { return false diff --git a/src/utils/betas.ts b/src/utils/betas.ts index da429117..3b218b0f 100644 --- a/src/utils/betas.ts +++ b/src/utils/betas.ts @@ -89,6 +89,14 @@ export function filterAllowedSdkBetas( // Generally, foundry supports all 1P features; // however out of an abundance of caution, we do not enable any which are behind an experiment +function shouldTrustBuiltInClaudeCapabilities(): boolean { + return ( + getAPIProvider() !== 'firstParty' || + isFirstPartyAnthropicBaseUrl() || + isClaudeAISubscriber() + ) +} + export function modelSupportsISP(model: string): boolean { const supported3P = get3PModelCapabilityOverride( model, @@ -104,6 +112,9 @@ export function modelSupportsISP(model: string): boolean { return true } if (provider === 'firstParty') { + if (!shouldTrustBuiltInClaudeCapabilities()) { + return false + } return !canonical.includes('claude-3-') } return ( @@ -129,9 +140,14 @@ export function modelSupportsContextManagement(model: string): boolean { return true } if (provider === 'firstParty') { + if (!shouldTrustBuiltInClaudeCapabilities()) { + return false + } return !canonical.includes('claude-3-') } return ( + canonical.includes('claude-fable-5') || + canonical.includes('claude-sonnet-5') || canonical.includes('claude-opus-4') || canonical.includes('claude-sonnet-4') || canonical.includes('claude-haiku-4') @@ -146,11 +162,17 @@ export function modelSupportsStructuredOutputs(model: string): boolean { if (provider !== 'firstParty' && provider !== 'foundry') { return false } + if (provider === 'firstParty' && !shouldTrustBuiltInClaudeCapabilities()) { + return false + } return ( + canonical.includes('claude-fable-5') || + canonical.includes('claude-sonnet-5') || canonical.includes('claude-sonnet-4-6') || canonical.includes('claude-sonnet-4-5') || canonical.includes('claude-opus-4-1') || canonical.includes('claude-opus-4-5') || + canonical.includes('claude-opus-4-8') || canonical.includes('claude-opus-4-7') || canonical.includes('claude-haiku-4-5') ) @@ -163,7 +185,10 @@ export function modelSupportsAutoMode(model: string): boolean { // External: firstParty-only at launch (PI probes not wired for // Bedrock/Vertex/Foundry yet). Checked before allowModels so the GB // override can't enable auto mode on unsupported providers. - if (process.env.USER_TYPE !== 'ant' && getAPIProvider() !== 'firstParty') { + if ( + process.env.USER_TYPE !== 'ant' && + (getAPIProvider() !== 'firstParty' || !shouldTrustBuiltInClaudeCapabilities()) + ) { return false } // GrowthBook override: tengu_auto_mode_config.allowModels force-enables @@ -215,7 +240,11 @@ export function getToolSearchBetaHeader(): string { export function shouldIncludeFirstPartyOnlyBetas(): boolean { return ( (getAPIProvider() === 'firstParty' || getAPIProvider() === 'foundry') && - (getAPIProvider() !== 'firstParty' || isFirstPartyAnthropicBaseUrl()) && + ( + getAPIProvider() !== 'firstParty' || + isFirstPartyAnthropicBaseUrl() || + isClaudeAISubscriber() + ) && !isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS) ) } @@ -228,6 +257,7 @@ export function shouldIncludeFirstPartyOnlyBetas(): boolean { export function shouldUseGlobalCacheScope(): boolean { return ( getAPIProvider() === 'firstParty' && + (isFirstPartyAnthropicBaseUrl() || isClaudeAISubscriber()) && !isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS) ) } diff --git a/src/utils/commitAttribution.ts b/src/utils/commitAttribution.ts index 1278b359..aedbf2f6 100644 --- a/src/utils/commitAttribution.ts +++ b/src/utils/commitAttribution.ts @@ -153,10 +153,13 @@ export function sanitizeSurfaceKey(surfaceKey: string): string { */ export function sanitizeModelName(shortName: string): string { // Map internal variants to public equivalents based on model family + if (shortName.includes('fable-5')) return 'claude-fable-5' + if (shortName.includes('opus-4-8')) return 'claude-opus-4-8' if (shortName.includes('opus-4-6')) return 'claude-opus-4-7' if (shortName.includes('opus-4-5')) return 'claude-opus-4-5' if (shortName.includes('opus-4-1')) return 'claude-opus-4-1' if (shortName.includes('opus-4')) return 'claude-opus-4' + if (shortName.includes('sonnet-5')) return 'claude-sonnet-5' if (shortName.includes('sonnet-4-6')) return 'claude-sonnet-4-6' if (shortName.includes('sonnet-4-5')) return 'claude-sonnet-4-5' if (shortName.includes('sonnet-4')) return 'claude-sonnet-4' diff --git a/src/utils/context.ts b/src/utils/context.ts index 111a151a..071132ef 100644 --- a/src/utils/context.ts +++ b/src/utils/context.ts @@ -54,6 +54,9 @@ export function modelSupports1M(model: string): boolean { const canonical = getCanonicalName(model) return ( canonical.includes('claude-fable-5') || + canonical.includes('claude-sonnet-5') || + canonical.includes('claude-opus-4-8') || + canonical.includes('claude-opus-4-7') || canonical.includes('claude-sonnet-4') || canonical.includes('opus-4-6') ) @@ -232,7 +235,13 @@ export function getModelMaxOutputTokens(model: string): { const m = getCanonicalName(model) - if (m.includes('opus-4-6')) { + if ( + m.includes('fable-5') || + m.includes('opus-4-8') || + m.includes('opus-4-7') || + m.includes('opus-4-6') || + m.includes('sonnet-5') + ) { defaultTokens = 64_000 upperLimit = 128_000 } else if (m.includes('sonnet-4-6')) { diff --git a/src/utils/effort.ts b/src/utils/effort.ts index 74e49093..aff3fd72 100644 --- a/src/utils/effort.ts +++ b/src/utils/effort.ts @@ -1,9 +1,13 @@ // biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered import { isUltrathinkEnabled } from './thinking.js' import { getInitialSettings } from './settings/settings.js' -import { isProSubscriber, isMaxSubscriber, isTeamSubscriber } from './auth.js' +import { isClaudeAISubscriber, isProSubscriber, isMaxSubscriber, isTeamSubscriber } from './auth.js' import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' -import { getAPIProvider, isFirstPartyAnthropicBaseUrl } from './model/providers.js' +import { + getAPIProvider, + hasAnthropicCompatibleThirdPartyConfig, + isFirstPartyAnthropicBaseUrl, +} from './model/providers.js' import { get3PModelCapabilityOverride } from './model/modelSupportOverrides.js' import { isEnvTruthy } from './envUtils.js' import type { EffortLevel as RuntimeEffortLevel } from 'src/entrypoints/sdk/runtimeTypes.js' @@ -24,6 +28,17 @@ export const EFFORT_LEVELS = [ export type EffortValue = EffortLevel | number +function shouldTrustBuiltInClaudeCapabilityList(): boolean { + if (hasAnthropicCompatibleThirdPartyConfig()) { + return false + } + return ( + getAPIProvider() !== 'firstParty' || + isFirstPartyAnthropicBaseUrl() || + isClaudeAISubscriber() + ) +} + // @[MODEL LAUNCH]: Add the new model to the allowlist if it supports the effort parameter. export function modelSupportsEffort(model: string): boolean { const m = model.toLowerCase() @@ -38,7 +53,7 @@ export function modelSupportsEffort(model: string): boolean { return true } // Supported by a subset of Claude 4 models - if ( + if (shouldTrustBuiltInClaudeCapabilityList() && ( m.includes('opus-4-6') || m.includes('opus-4-7') || m.includes('opus-4-8') || @@ -48,7 +63,7 @@ export function modelSupportsEffort(model: string): boolean { m.includes('fable-5') || m.includes('mythos-5') || m.includes('mythos-preview') - ) { + )) { return true } // Exclude any other known legacy models (haiku, older opus/sonnet variants) @@ -63,7 +78,10 @@ export function modelSupportsEffort(model: string): boolean { // Default to true for unknown model strings on 1P. // Do not default to true for 3P as they have different formats for their // model strings (ex. anthropics/claude-code#30795) - return getAPIProvider() === 'firstParty' && isFirstPartyAnthropicBaseUrl() + return ( + getAPIProvider() === 'firstParty' && + (isFirstPartyAnthropicBaseUrl() || isClaudeAISubscriber()) + ) } // @[MODEL LAUNCH]: Add new models that expose the 'xhigh' effort level. @@ -77,7 +95,7 @@ export function modelSupportsXHighEffort(model: string): boolean { return entry?.supportedReasoningEfforts.includes('xhigh') ?? true } const m = model.toLowerCase() - return ( + return shouldTrustBuiltInClaudeCapabilityList() && ( m.includes('opus-4-7') || m.includes('opus-4-8') || m.includes('sonnet-5') || @@ -97,7 +115,7 @@ export function modelSupportsMaxEffort(model: string): boolean { return entry?.supportedReasoningEfforts.includes('max') ?? true } const m = model.toLowerCase() - if ( + if (shouldTrustBuiltInClaudeCapabilityList() && ( m.includes('opus-4-6') || m.includes('opus-4-7') || m.includes('opus-4-8') || @@ -106,7 +124,7 @@ export function modelSupportsMaxEffort(model: string): boolean { m.includes('fable-5') || m.includes('mythos-5') || m.includes('mythos-preview') - ) { + )) { return true } if (process.env.USER_TYPE === 'ant' && resolveAntModel(model)) { diff --git a/src/utils/fastMode.ts b/src/utils/fastMode.ts index 1c706f1e..dbbce6cb 100644 --- a/src/utils/fastMode.ts +++ b/src/utils/fastMode.ts @@ -140,7 +140,7 @@ export function getFastModeUnavailableReason(): string | null { } // @[MODEL LAUNCH]: Update supported Fast Mode models. -export const FAST_MODE_MODEL_DISPLAY = 'Opus 4.7' +export const FAST_MODE_MODEL_DISPLAY = 'Opus 4.8' export function getFastModeModel(): string { return 'opus' + (isOpus1mMergeEnabled() ? '[1m]' : '') diff --git a/src/utils/managedEnvConstants.ts b/src/utils/managedEnvConstants.ts index 614b0968..a69f18ff 100644 --- a/src/utils/managedEnvConstants.ts +++ b/src/utils/managedEnvConstants.ts @@ -47,6 +47,10 @@ const PROVIDER_MANAGED_ENV_VARS = new Set([ 'GROK_OAUTH_FILE', // Model defaults — often set to provider-specific ID formats 'ANTHROPIC_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_NAME', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_HAIKU_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION', 'ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME', @@ -124,6 +128,10 @@ export const SAFE_ENV_VARS = new Set([ 'ANTHROPIC_CUSTOM_MODEL_OPTION', 'ANTHROPIC_CUSTOM_MODEL_OPTION_DESCRIPTION', 'ANTHROPIC_CUSTOM_MODEL_OPTION_NAME', + 'ANTHROPIC_DEFAULT_FABLE_MODEL', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_NAME', + 'ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_HAIKU_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION', 'ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME', diff --git a/src/utils/model/configs.ts b/src/utils/model/configs.ts index aba01e08..1331d080 100644 --- a/src/utils/model/configs.ts +++ b/src/utils/model/configs.ts @@ -40,12 +40,20 @@ export const CLAUDE_HAIKU_4_5_CONFIG = { export const CLAUDE_FABLE_5_CONFIG = { firstParty: 'claude-fable-5', - bedrock: 'us.anthropic.claude-fable-5', + bedrock: 'anthropic.claude-fable-5', vertex: 'claude-fable-5', foundry: 'claude-fable-5', azureOpenAI: 'claude-fable-5', } as const satisfies ModelConfig +export const CLAUDE_SONNET_5_CONFIG = { + firstParty: 'claude-sonnet-5', + bedrock: 'anthropic.claude-sonnet-5', + vertex: 'claude-sonnet-5', + foundry: 'claude-sonnet-5', + azureOpenAI: 'claude-sonnet-5', +} as const satisfies ModelConfig + export const CLAUDE_SONNET_4_CONFIG = { firstParty: 'claude-sonnet-4-20250514', bedrock: 'us.anthropic.claude-sonnet-4-20250514-v1:0', @@ -94,6 +102,14 @@ export const CLAUDE_OPUS_4_6_CONFIG = { azureOpenAI: 'claude-opus-4-7', } as const satisfies ModelConfig +export const CLAUDE_OPUS_4_8_CONFIG = { + firstParty: 'claude-opus-4-8', + bedrock: 'anthropic.claude-opus-4-8', + vertex: 'claude-opus-4-8', + foundry: 'claude-opus-4-8', + azureOpenAI: 'claude-opus-4-8', +} as const satisfies ModelConfig + export const CLAUDE_SONNET_4_6_CONFIG = { firstParty: 'claude-sonnet-4-6', bedrock: 'us.anthropic.claude-sonnet-4-6', @@ -136,10 +152,12 @@ export const ALL_MODEL_CONFIGS = { sonnet40: CLAUDE_SONNET_4_CONFIG, sonnet45: CLAUDE_SONNET_4_5_CONFIG, sonnet46: CLAUDE_SONNET_4_6_CONFIG, + sonnet50: CLAUDE_SONNET_5_CONFIG, opus40: CLAUDE_OPUS_4_CONFIG, opus41: CLAUDE_OPUS_4_1_CONFIG, opus45: CLAUDE_OPUS_4_5_CONFIG, opus46: CLAUDE_OPUS_4_6_CONFIG, + opus48: CLAUDE_OPUS_4_8_CONFIG, gpt52codex: GPT_5_2_CODEX_CONFIG, gpt53codex: GPT_5_3_CODEX_CONFIG, gpt54codex: GPT_5_4_CODEX_CONFIG, diff --git a/src/utils/model/fable.test.ts b/src/utils/model/fable.test.ts index 6916e0c2..b6037e6f 100644 --- a/src/utils/model/fable.test.ts +++ b/src/utils/model/fable.test.ts @@ -1,23 +1,35 @@ import { afterEach, beforeEach, describe, expect, test } from 'bun:test' import { getContextWindowForModel, modelSupports1M } from '../context.js' +import { computeSimpleEnvInfo } from '../../constants/prompts.js' +import { SKILL_MODEL_VARS } from '../../skills/bundled/claudeApiContent.js' +import { sanitizeModelName } from '../commitAttribution.js' +import { getHardcodedTeammateModelFallback } from '../swarm/teammateModel.js' import { getAgentModel, getAgentModelOptions } from './agent.js' import { isModelAlias, isModelFamilyAlias } from './aliases.js' -import { CLAUDE_FABLE_5_CONFIG } from './configs.js' +import { + CLAUDE_FABLE_5_CONFIG, + CLAUDE_OPUS_4_6_CONFIG, + CLAUDE_OPUS_4_8_CONFIG, + CLAUDE_SONNET_5_CONFIG, +} from './configs.js' import { firstPartyNameToCanonical, getDefaultFableModel, getMarketingNameForModel, getPublicModelDisplayName, parseUserSpecifiedModel, + renderDefaultModelSetting, } from './model.js' import { getModelStrings } from './modelStrings.js' import { get3PModelCapabilityOverride } from './modelSupportOverrides.js' const ENV_KEYS = [ 'ANTHROPIC_BASE_URL', + 'ANTHROPIC_API_KEY', 'ANTHROPIC_DEFAULT_FABLE_MODEL', 'ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES', 'CLAUDE_CODE_DISABLE_1M_CONTEXT', + 'CLAUDE_CODE_USE_BEDROCK', 'CLAUDE_CODE_SUBAGENT_MODEL', ] as const @@ -40,11 +52,25 @@ describe('Fable model configuration', () => { test('uses the official provider IDs', () => { expect(CLAUDE_FABLE_5_CONFIG).toEqual({ firstParty: 'claude-fable-5', - bedrock: 'us.anthropic.claude-fable-5', + bedrock: 'anthropic.claude-fable-5', vertex: 'claude-fable-5', foundry: 'claude-fable-5', azureOpenAI: 'claude-fable-5', }) + expect(CLAUDE_OPUS_4_8_CONFIG).toEqual({ + firstParty: 'claude-opus-4-8', + bedrock: 'anthropic.claude-opus-4-8', + vertex: 'claude-opus-4-8', + foundry: 'claude-opus-4-8', + azureOpenAI: 'claude-opus-4-8', + }) + expect(CLAUDE_SONNET_5_CONFIG).toEqual({ + firstParty: 'claude-sonnet-5', + bedrock: 'anthropic.claude-sonnet-5', + vertex: 'claude-sonnet-5', + foundry: 'claude-sonnet-5', + azureOpenAI: 'claude-sonnet-5', + }) }) test('recognizes fable as an alias and model family', () => { @@ -74,12 +100,63 @@ describe('Fable model configuration', () => { expect(getMarketingNameForModel('claude-fable-5[1m]')).toBe( 'Fable 5 (with 1M context)', ) + expect(firstPartyNameToCanonical('anthropic.claude-opus-4-8')).toBe( + 'claude-opus-4-8', + ) + expect(firstPartyNameToCanonical('claude-sonnet-5')).toBe( + 'claude-sonnet-5', + ) + expect(getPublicModelDisplayName(getModelStrings().opus48)).toBe('Opus 4.8') + expect(getPublicModelDisplayName(`${getModelStrings().opus48}[1m]`)).toBe( + 'Opus 4.8 (1M context)', + ) + expect(getPublicModelDisplayName(getModelStrings().sonnet50)).toBe('Sonnet 5') + expect(getPublicModelDisplayName(`${getModelStrings().sonnet50}[1m]`)).toBe( + 'Sonnet 5 (1M context)', + ) + expect(getMarketingNameForModel('claude-opus-4-8')).toBe('Opus 4.8') + expect(getMarketingNameForModel('claude-sonnet-5')).toBe('Sonnet 5') + expect(renderDefaultModelSetting('opusplan')).toBe( + 'Opus 4.8 in plan mode, else Sonnet 5', + ) + }) + + test('publishes current model IDs and knowledge cutoffs in environment context', async () => { + expect(SKILL_MODEL_VARS).toMatchObject({ + OPUS_ID: 'claude-opus-4-8', + OPUS_NAME: 'Claude Opus 4.8', + SONNET_ID: 'claude-sonnet-5', + SONNET_NAME: 'Claude Sonnet 5', + }) + + for (const model of ['claude-fable-5', 'claude-opus-4-8', 'claude-sonnet-5']) { + const info = await computeSimpleEnvInfo(model) + expect(info).toContain('Assistant knowledge cutoff is January 2026.') + expect(info).toContain("Fable 5: 'claude-fable-5'") + expect(info).toContain("Opus 4.8: 'claude-opus-4-8'") + expect(info).toContain("Sonnet 5: 'claude-sonnet-5'") + expect(info).toContain('same Claude Opus 4.8 model') + } + }) + + test('sanitizes new model trailers and keeps teammate fallbacks provider-safe', () => { + expect(sanitizeModelName('claude-fable-5-experimental')).toBe('claude-fable-5') + expect(sanitizeModelName('claude-opus-4-8-experimental')).toBe('claude-opus-4-8') + expect(sanitizeModelName('claude-sonnet-5-experimental')).toBe('claude-sonnet-5') + expect(getHardcodedTeammateModelFallback()).toBe('claude-opus-4-8') + + process.env.CLAUDE_CODE_USE_BEDROCK = '1' + expect(getHardcodedTeammateModelFallback()).toBe( + CLAUDE_OPUS_4_6_CONFIG.bedrock, + ) }) test('exposes the native 1M context window', () => { expect(modelSupports1M('claude-fable-5')).toBe(true) expect(getContextWindowForModel('claude-fable-5')).toBe(1_000_000) expect(getContextWindowForModel('anthropic/claude-fable-5')).toBe(1_000_000) + expect(getContextWindowForModel('claude-opus-4-8')).toBe(1_000_000) + expect(getContextWindowForModel('claude-sonnet-5')).toBe(1_000_000) }) }) diff --git a/src/utils/model/model.ts b/src/utils/model/model.ts index 8eed6440..3ebdb1d4 100644 --- a/src/utils/model/model.ts +++ b/src/utils/model/model.ts @@ -8,6 +8,7 @@ import { getMainLoopModelOverride } from '../../bootstrap/state.js' import { getSubscriptionType, + is1PApiCustomer, isClaudeAISubscriber, isMaxSubscriber, isOpenAIAuthActive, @@ -24,7 +25,10 @@ import { getModelStrings, resolveOverriddenModel } from './modelStrings.js' import { formatModelPricing, getOpus46CostTier } from '../modelCost.js' import { getSettings_DEPRECATED } from '../settings/settings.js' import type { PermissionMode } from '../permissions/PermissionMode.js' -import { getAPIProvider } from './providers.js' +import { + getAPIProvider, + hasAnthropicCompatibleThirdPartyConfig, +} from './providers.js' import { LIGHTNING_BOLT } from '../../constants/figures.js' import { isModelAllowed } from './modelAllowlist.js' import { type ModelAlias, isModelAlias } from './aliases.js' @@ -47,7 +51,8 @@ export function isNonCustomOpusModel(model: ModelName): boolean { model === getModelStrings().opus40 || model === getModelStrings().opus41 || model === getModelStrings().opus45 || - model === getModelStrings().opus46 + model === getModelStrings().opus46 || + model === getModelStrings().opus48 ) } @@ -103,7 +108,11 @@ export function getMainLoopModel(): ModelName { } export function getBestModel(): ModelName { - return getDefaultOpusModel() + return getDefaultFableModel() +} + +function shouldUseThirdPartyAnthropicModelDefaults(): boolean { + return !isClaudeAISubscriber() && hasAnthropicCompatibleThirdPartyConfig() } export function getDefaultFableModel(): ModelName { @@ -113,6 +122,9 @@ export function getDefaultFableModel(): ModelName { if (process.env.ANTHROPIC_DEFAULT_FABLE_MODEL) { return process.env.ANTHROPIC_DEFAULT_FABLE_MODEL } + if (shouldUseThirdPartyAnthropicModelDefaults()) { + return getDefaultOpusModel() + } return getModelStrings().fable5 } @@ -127,10 +139,10 @@ export function getDefaultOpusModel(): ModelName { // 3P providers (Bedrock, Vertex, Foundry) — kept as a separate branch // even when values match, since 3P availability lags firstParty and // these will diverge again at the next model launch. - if (getAPIProvider() !== 'firstParty') { + if (shouldUseThirdPartyAnthropicModelDefaults()) { return getModelStrings().opus46 } - return getModelStrings().opus46 + return getModelStrings().opus48 } // @[MODEL LAUNCH]: Update the default Sonnet model (3P providers may lag so keep defaults unchanged). @@ -142,10 +154,10 @@ export function getDefaultSonnetModel(): ModelName { return process.env.ANTHROPIC_DEFAULT_SONNET_MODEL } // Default to Sonnet 4.5 for 3P since they may not have 4.6 yet - if (getAPIProvider() !== 'firstParty') { + if (shouldUseThirdPartyAnthropicModelDefaults()) { return getModelStrings().sonnet45 } - return getModelStrings().sonnet46 + return getModelStrings().sonnet50 } // @[MODEL LAUNCH]: Update the default Haiku model (3P providers may lag so keep defaults unchanged). @@ -194,8 +206,9 @@ export function getRuntimeMainLoopModel(params: { * Get the default main loop model setting. * * This handles the built-in default: - * - Opus for Max and Team Premium users - * - Sonnet 4.6 for all other users (including Team Standard, Pro, Enterprise) + * - Opus for Anthropic API/PAYG, Max, and Team Premium users + * - Sonnet for Pro, Team Standard, and Enterprise subscription users + * - Sonnet for third-party providers, where built-in aliases may lag * * @returns The default model setting to use */ @@ -216,6 +229,10 @@ export function getDefaultMainLoopModelSetting(): ModelName | ModelAlias { return resolveOpenAICodexModel('opus') } + if (is1PApiCustomer()) { + return getDefaultOpusModel() + } + // Max users get Opus as default if (isMaxSubscriber()) { return getDefaultOpusModel() + (isOpus1mMergeEnabled() ? '[1m]' : '') @@ -226,8 +243,8 @@ export function getDefaultMainLoopModelSetting(): ModelName | ModelAlias { return getDefaultOpusModel() + (isOpus1mMergeEnabled() ? '[1m]' : '') } - // PAYG (1P and 3P), Enterprise, Team Standard, and Pro get Sonnet as default - // Note that PAYG (3P) may default to an older Sonnet model + // Third-party provider defaults and subscription tiers that are not + // Opus-defaulted above use Sonnet. Third-party provider aliases may lag. return getDefaultSonnetModel() } @@ -253,6 +270,9 @@ export function firstPartyNameToCanonical(name: ModelName): ModelShortName { if (name.includes('claude-fable-5')) { return 'claude-fable-5' } + if (name.includes('claude-opus-4-8')) { + return 'claude-opus-4-8' + } if (name.includes('claude-opus-4-7')) { return 'claude-opus-4-7' } @@ -265,6 +285,9 @@ export function firstPartyNameToCanonical(name: ModelName): ModelShortName { if (name.includes('claude-opus-4')) { return 'claude-opus-4' } + if (name.includes('claude-sonnet-5')) { + return 'claude-sonnet-5' + } if (name.includes('claude-sonnet-4-6')) { return 'claude-sonnet-4-6' } @@ -329,18 +352,18 @@ export function getClaudeAiUserDefaultModelDescription( } if (isMaxSubscriber() || isTeamPremiumSubscriber()) { if (isOpus1mMergeEnabled()) { - return `Opus 4.7 with 1M context · Most capable for complex work${fastMode ? getOpus46PricingSuffix(true) : ''}` + return `Opus 4.8 with 1M context · Most capable for complex work${fastMode ? getOpus46PricingSuffix(true) : ''}` } - return `Opus 4.7 · Most capable for complex work${fastMode ? getOpus46PricingSuffix(true) : ''}` + return `Opus 4.8 · Most capable for complex work${fastMode ? getOpus46PricingSuffix(true) : ''}` } - return 'Sonnet 4.6 · Best for everyday tasks' + return 'Sonnet 5 · Best for everyday tasks' } export function renderDefaultModelSetting( setting: ModelName | ModelAlias, ): string { if (setting === 'opusplan') { - return 'Opus 4.7 in plan mode, else Sonnet 4.6' + return `${renderModelName(getDefaultOpusModel())} in plan mode, else ${renderModelName(getDefaultSonnetModel())}` } return renderModelName(parseUserSpecifiedModel(setting)) } @@ -397,6 +420,10 @@ export function getPublicModelDisplayName(model: ModelName): string | null { return 'Fable 5' case getModelStrings().fable5 + '[1m]': return 'Fable 5 (1M context)' + case getModelStrings().opus48: + return 'Opus 4.8' + case getModelStrings().opus48 + '[1m]': + return 'Opus 4.8 (1M context)' case getModelStrings().opus46: return 'Opus 4.7' case getModelStrings().opus46 + '[1m]': @@ -411,6 +438,10 @@ export function getPublicModelDisplayName(model: ModelName): string | null { return 'Sonnet 4.6 (1M context)' case getModelStrings().sonnet46: return 'Sonnet 4.6' + case getModelStrings().sonnet50 + '[1m]': + return 'Sonnet 5 (1M context)' + case getModelStrings().sonnet50: + return 'Sonnet 5' case getModelStrings().sonnet45 + '[1m]': return 'Sonnet 4.5 (1M context)' case getModelStrings().sonnet45: @@ -634,6 +665,9 @@ export function getMarketingNameForModel(modelId: string): string | undefined { if (canonical.includes('claude-fable-5')) { return has1m ? 'Fable 5 (with 1M context)' : 'Fable 5' } + if (canonical.includes('claude-opus-4-8')) { + return has1m ? 'Opus 4.8 (with 1M context)' : 'Opus 4.8' + } if (canonical.includes('claude-opus-4-7')) { return has1m ? 'Opus 4.7 (with 1M context)' : 'Opus 4.7' } @@ -646,6 +680,9 @@ export function getMarketingNameForModel(modelId: string): string | undefined { if (canonical.includes('claude-opus-4')) { return 'Opus 4' } + if (canonical.includes('claude-sonnet-5')) { + return has1m ? 'Sonnet 5 (with 1M context)' : 'Sonnet 5' + } if (canonical.includes('claude-sonnet-4-6')) { return has1m ? 'Sonnet 4.6 (with 1M context)' : 'Sonnet 4.6' } diff --git a/src/utils/model/modelContextWindows.ts b/src/utils/model/modelContextWindows.ts index 479f0dea..544f5f14 100644 --- a/src/utils/model/modelContextWindows.ts +++ b/src/utils/model/modelContextWindows.ts @@ -4,7 +4,9 @@ export const MODEL_CONTEXT_WINDOW_MAX = 10_000_000 const DIRECT_MODEL_CONTEXT_WINDOWS: Record = { 'claude-fable-5': 1_000_000, + 'claude-opus-4-8': 1_000_000, 'claude-opus-4-7': 1_000_000, + 'claude-sonnet-5': 1_000_000, 'claude-sonnet-4-6': 200_000, 'claude-haiku-4-5': 200_000, 'deepseek-v4-pro': 1_000_000, @@ -39,6 +41,8 @@ const DIRECT_MODEL_CONTEXT_WINDOWS: Record = { const PATTERN_MODEL_CONTEXT_WINDOWS: Array<[RegExp, number]> = [ [/^anthropic\/claude-fable-5\b/i, 1_000_000], + [/^anthropic\/claude-opus-4\.8\b/i, 1_000_000], + [/^anthropic\/claude-sonnet-5\b/i, 1_000_000], [/^anthropic\/claude-opus-4\.7\b/i, 1_000_000], [/^anthropic\/claude-sonnet-4\.6\b/i, 200_000], [/^anthropic\/claude-haiku-4\.5\b/i, 200_000], diff --git a/src/utils/model/modelOptions.ts b/src/utils/model/modelOptions.ts index fbcd2cc9..9ab9d366 100644 --- a/src/utils/model/modelOptions.ts +++ b/src/utils/model/modelOptions.ts @@ -9,6 +9,7 @@ import { } from '../auth.js' import { getModelStrings } from './modelStrings.js' import { + COST_TIER_10_50, COST_TIER_3_15, COST_HAIKU_35, COST_HAIKU_45, @@ -16,11 +17,15 @@ import { } from '../modelCost.js' import { getSettings_DEPRECATED } from '../settings/settings.js' import { checkOpus1mAccess, checkSonnet1mAccess } from './check1mAccess.js' -import { getAPIProvider, isFirstPartyAnthropicBaseUrl } from './providers.js' +import { + getAPIProvider, + hasAnthropicCompatibleThirdPartyConfig, +} from './providers.js' import { isModelAllowed } from './modelAllowlist.js' import { getCanonicalName, getClaudeAiUserDefaultModelDescription, + getDefaultFableModel, getDefaultSonnetModel, getDefaultOpusModel, getDefaultHaikuModel, @@ -45,10 +50,6 @@ export type ModelOption = { descriptionForModel?: string } -function hasAnthropicCompatibleThirdPartyConfig(): boolean { - return getAPIProvider() !== 'firstParty' || !isFirstPartyAnthropicBaseUrl() -} - function pushUniqueOption( options: ModelOption[], option: ModelOption | undefined, @@ -64,6 +65,21 @@ function pushUniqueOption( options.push(option) } +function shouldOfferSonnet1mOption(): boolean { + if (!checkSonnet1mAccess()) { + return false + } + + return ( + shouldUseThirdPartyAnthropicOptions() || + !getDefaultSonnetModel().toLowerCase().includes('sonnet-5') + ) +} + +function shouldUseThirdPartyAnthropicOptions(): boolean { + return !isClaudeAISubscriber() && hasAnthropicCompatibleThirdPartyConfig() +} + export function getDefaultOptionForUser(fastMode = false): ModelOption { if (process.env.USER_TYPE === 'ant') { const currentModel = renderDefaultModelSetting( @@ -99,16 +115,23 @@ export function getDefaultOptionForUser(fastMode = false): ModelOption { } // PAYG - const is3P = hasAnthropicCompatibleThirdPartyConfig() + const is3P = shouldUseThirdPartyAnthropicOptions() + const currentModel = renderDefaultModelSetting(getDefaultMainLoopModelSetting()) + const pricingSuffix = + is3P + ? '' + : currentModel.includes('Opus') + ? getOpus46PricingSuffix(fastMode) + : ` · ${formatModelPricing(COST_TIER_3_15)}` return { value: null, label: 'Default (recommended)', - description: `Use the default model (currently ${renderDefaultModelSetting(getDefaultMainLoopModelSetting())})${is3P ? '' : ` · ${formatModelPricing(COST_TIER_3_15)}`}`, + description: `Use the default model (currently ${currentModel})${pricingSuffix}`, } } function getCustomSonnetOption(): ModelOption | undefined { - const is3P = hasAnthropicCompatibleThirdPartyConfig() + const is3P = shouldUseThirdPartyAnthropicOptions() const customSonnetModel = process.env.ANTHROPIC_DEFAULT_SONNET_MODEL // When a 3P user has a custom sonnet model string, show it directly if (is3P && customSonnetModel) { @@ -127,19 +150,50 @@ function getCustomSonnetOption(): ModelOption | undefined { // @[MODEL LAUNCH]: Update or add model option functions (getSonnetXXOption, getOpusXXOption, etc.) // with the new model's label and description. These appear in the /model picker. +function getCustomFableOption(): ModelOption | undefined { + const is3P = shouldUseThirdPartyAnthropicOptions() + const customFableModel = process.env.ANTHROPIC_DEFAULT_FABLE_MODEL + if (is3P && customFableModel) { + const is1m = has1mContext(customFableModel) + return { + value: 'fable', + label: + process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_NAME ?? customFableModel, + description: + process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION ?? + `Custom Fable model${is1m ? ' (1M context)' : ''}`, + descriptionForModel: `${process.env.ANTHROPIC_DEFAULT_FABLE_MODEL_DESCRIPTION ?? `Custom Fable model${is1m ? ' with 1M context' : ''}`} (${customFableModel})`, + } + } +} + +function getFable5Option(): ModelOption | undefined { + if (shouldUseThirdPartyAnthropicOptions()) { + return undefined + } + return { + value: 'fable', + label: 'Fable', + description: `Fable 5 · Highest capability for long-running tasks · ${formatModelPricing(COST_TIER_10_50)}`, + descriptionForModel: + 'Fable 5 - highest capability for hard, long-running tasks', + } +} + function getSonnet46Option(): ModelOption { - const is3P = hasAnthropicCompatibleThirdPartyConfig() + const is3P = shouldUseThirdPartyAnthropicOptions() + const modelName = is3P ? 'Sonnet 4.6' : 'Sonnet 5' return { value: is3P ? getModelStrings().sonnet46 : 'sonnet', label: 'Sonnet', - description: `Sonnet 4.6 · Best for everyday tasks${is3P ? '' : ` · ${formatModelPricing(COST_TIER_3_15)}`}`, + description: `${modelName} · Best for everyday tasks${is3P ? '' : ` · ${formatModelPricing(COST_TIER_3_15)}`}`, descriptionForModel: - 'Sonnet 4.6 - best for everyday tasks. Generally recommended for most coding tasks', + `${modelName} - best for everyday tasks. Generally recommended for most coding tasks`, } } function getCustomOpusOption(): ModelOption | undefined { - const is3P = hasAnthropicCompatibleThirdPartyConfig() + const is3P = shouldUseThirdPartyAnthropicOptions() const customOpusModel = process.env.ANTHROPIC_DEFAULT_OPUS_MODEL // When a 3P user has a custom opus model string, show it directly if (is3P && customOpusModel) { @@ -165,39 +219,41 @@ function getOpus41Option(): ModelOption { } function getOpus46Option(fastMode = false): ModelOption { - const is3P = getAPIProvider() !== 'firstParty' + const is3P = shouldUseThirdPartyAnthropicOptions() return { value: is3P ? getModelStrings().opus46 : 'opus', label: 'Opus', - description: `Opus 4.7 · Most capable for complex work${getOpus46PricingSuffix(fastMode)}`, - descriptionForModel: 'Opus 4.7 - most capable for complex work', + description: `${is3P ? 'Opus 4.7' : 'Opus 4.8'} · Most capable for complex work${getOpus46PricingSuffix(fastMode)}`, + descriptionForModel: `${is3P ? 'Opus 4.7' : 'Opus 4.8'} - most capable for complex work`, } } export function getSonnet46_1MOption(): ModelOption { - const is3P = hasAnthropicCompatibleThirdPartyConfig() + const is3P = shouldUseThirdPartyAnthropicOptions() + const modelName = is3P ? 'Sonnet 4.6' : 'Sonnet 5' return { value: is3P ? getModelStrings().sonnet46 + '[1m]' : 'sonnet[1m]', label: 'Sonnet (1M context)', - description: `Sonnet 4.6 for long sessions${is3P ? '' : ` · ${formatModelPricing(COST_TIER_3_15)}`}`, + description: `${modelName} for long sessions${is3P ? '' : ` · ${formatModelPricing(COST_TIER_3_15)}`}`, descriptionForModel: - 'Sonnet 4.6 with 1M context window - for long sessions with large codebases', + `${modelName} with 1M context window - for long sessions with large codebases`, } } export function getOpus46_1MOption(fastMode = false): ModelOption { - const is3P = hasAnthropicCompatibleThirdPartyConfig() + const is3P = shouldUseThirdPartyAnthropicOptions() + const modelName = is3P ? 'Opus 4.7' : 'Opus 4.8' return { value: is3P ? getModelStrings().opus46 + '[1m]' : 'opus[1m]', label: 'Opus (1M context)', - description: `Opus 4.7 for long sessions${getOpus46PricingSuffix(fastMode)}`, + description: `${modelName} for long sessions${getOpus46PricingSuffix(fastMode)}`, descriptionForModel: - 'Opus 4.7 with 1M context window - for long sessions with large codebases', + `${modelName} with 1M context window - for long sessions with large codebases`, } } function getCustomHaikuOption(): ModelOption | undefined { - const is3P = hasAnthropicCompatibleThirdPartyConfig() + const is3P = shouldUseThirdPartyAnthropicOptions() const customHaikuModel = process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL // When a 3P user has a custom haiku model string, show it directly if (is3P && customHaikuModel) { @@ -213,7 +269,7 @@ function getCustomHaikuOption(): ModelOption | undefined { } function getHaiku45Option(): ModelOption { - const is3P = hasAnthropicCompatibleThirdPartyConfig() + const is3P = shouldUseThirdPartyAnthropicOptions() return { value: 'haiku', label: 'Haiku', @@ -224,7 +280,7 @@ function getHaiku45Option(): ModelOption { } function getHaiku35Option(): ModelOption { - const is3P = getAPIProvider() !== 'firstParty' + const is3P = shouldUseThirdPartyAnthropicOptions() return { value: 'haiku', label: 'Haiku', @@ -246,17 +302,17 @@ function getMaxOpusOption(fastMode = false): ModelOption { return { value: 'opus', label: 'Opus', - description: `Opus 4.7 · Most capable for complex work${fastMode ? getOpus46PricingSuffix(true) : ''}`, + description: `Opus 4.8 · Most capable for complex work${fastMode ? getOpus46PricingSuffix(true) : ''}`, } } export function getMaxSonnet46_1MOption(): ModelOption { - const is3P = hasAnthropicCompatibleThirdPartyConfig() + const is3P = shouldUseThirdPartyAnthropicOptions() const billingInfo = isClaudeAISubscriber() ? ' · Billed as extra usage' : '' return { value: 'sonnet[1m]', label: 'Sonnet (1M context)', - description: `Sonnet 4.6 with 1M context${billingInfo}${is3P ? '' : ` · ${formatModelPricing(COST_TIER_3_15)}`}`, + description: `Sonnet 5 with 1M context${billingInfo}${is3P ? '' : ` · ${formatModelPricing(COST_TIER_3_15)}`}`, } } @@ -265,25 +321,25 @@ export function getMaxOpus46_1MOption(fastMode = false): ModelOption { return { value: 'opus[1m]', label: 'Opus (1M context)', - description: `Opus 4.7 with 1M context${billingInfo}${getOpus46PricingSuffix(fastMode)}`, + description: `Opus 4.8 with 1M context${billingInfo}${getOpus46PricingSuffix(fastMode)}`, } } function getMergedOpus1MOption(fastMode = false): ModelOption { - const is3P = hasAnthropicCompatibleThirdPartyConfig() + const is3P = shouldUseThirdPartyAnthropicOptions() return { value: is3P ? getModelStrings().opus46 + '[1m]' : 'opus[1m]', label: 'Opus (1M context)', - description: `Opus 4.7 with 1M context · Most capable for complex work${!is3P && fastMode ? getOpus46PricingSuffix(fastMode) : ''}`, + description: `${is3P ? 'Opus 4.7' : 'Opus 4.8'} with 1M context · Most capable for complex work${!is3P && fastMode ? getOpus46PricingSuffix(fastMode) : ''}`, descriptionForModel: - 'Opus 4.7 with 1M context - most capable for complex work', + `${is3P ? 'Opus 4.7' : 'Opus 4.8'} with 1M context - most capable for complex work`, } } const MaxSonnet46Option: ModelOption = { value: 'sonnet', label: 'Sonnet', - description: 'Sonnet 4.6 · Best for everyday tasks', + description: 'Sonnet 5 · Best for everyday tasks', } const MaxHaiku45Option: ModelOption = { @@ -296,7 +352,7 @@ function getOpusPlanOption(): ModelOption { return { value: 'opusplan', label: 'Opus Plan Mode', - description: 'Use Opus 4.7 in plan mode, Sonnet 4.6 otherwise', + description: 'Use Opus in plan mode, Sonnet otherwise', } } @@ -340,11 +396,12 @@ function getOpenAIModelOptions(): ModelOption[] { })), ] - if (!hasAnthropicCompatibleThirdPartyConfig()) { + if (!shouldUseThirdPartyAnthropicOptions()) { return options } pushUniqueOption(options, getCustomSonnetOption()) + pushUniqueOption(options, getCustomFableOption()) pushUniqueOption(options, getCustomOpusOption()) pushUniqueOption(options, getCustomHaikuOption()) @@ -365,8 +422,10 @@ function getModelOptionsBase(fastMode = false): ModelOption[] { description: m.description ?? `[ANT-ONLY] ${m.label} (${m.model})`, })) + const fableOption = getFable5Option() return [ getDefaultOptionForUser(), + ...(fableOption ? [fableOption] : []), ...antModelOptions, getMergedOpus1MOption(fastMode), getSonnet46Option(), @@ -383,12 +442,13 @@ function getModelOptionsBase(fastMode = false): ModelOption[] { if (isMaxSubscriber() || isTeamPremiumSubscriber()) { // Max and Team Premium users: Opus is default, show Sonnet as alternative const premiumOptions = [getDefaultOptionForUser(fastMode)] + pushUniqueOption(premiumOptions, getFable5Option()) if (!isOpus1mMergeEnabled() && checkOpus1mAccess()) { premiumOptions.push(getMaxOpus46_1MOption(fastMode)) } premiumOptions.push(MaxSonnet46Option) - if (checkSonnet1mAccess()) { + if (shouldOfferSonnet1mOption()) { premiumOptions.push(getMaxSonnet46_1MOption()) } @@ -398,7 +458,8 @@ function getModelOptionsBase(fastMode = false): ModelOption[] { // Pro/Team Standard/Enterprise users: Sonnet is default, show Opus as alternative const standardOptions = [getDefaultOptionForUser(fastMode)] - if (checkSonnet1mAccess()) { + pushUniqueOption(standardOptions, getFable5Option()) + if (shouldOfferSonnet1mOption()) { standardOptions.push(getMaxSonnet46_1MOption()) } @@ -415,34 +476,31 @@ function getModelOptionsBase(fastMode = false): ModelOption[] { return standardOptions } - // PAYG 1P API: Default (Sonnet) + Sonnet 1M + Opus 4.7 + Opus 1M + Haiku - if (!hasAnthropicCompatibleThirdPartyConfig()) { + // PAYG 1P API: Default (Opus 4.8) + Fable + Sonnet + Haiku. + // Opus 4.8 and Sonnet 5 already have native 1M context windows. + if (!shouldUseThirdPartyAnthropicOptions()) { const payg1POptions = [getDefaultOptionForUser(fastMode)] - if (checkSonnet1mAccess()) { + pushUniqueOption(payg1POptions, getFable5Option()) + payg1POptions.push(getSonnet46Option()) + if (shouldOfferSonnet1mOption()) { payg1POptions.push(getSonnet46_1MOption()) } - if (isOpus1mMergeEnabled()) { - payg1POptions.push(getMergedOpus1MOption(fastMode)) - } else { - payg1POptions.push(getOpus46Option(fastMode)) - if (checkOpus1mAccess()) { - payg1POptions.push(getOpus46_1MOption(fastMode)) - } - } payg1POptions.push(getHaiku45Option()) return payg1POptions } - // PAYG 3P: Default (Sonnet 4.5) + Sonnet (3P custom) or Sonnet 4.6/1M + Opus (3P custom) or Opus 4.1/Opus 4.7/Opus1M + Haiku + Opus 4.1 + // PAYG 3P: Default (Sonnet 4.5) + optional custom Fable + Sonnet + Opus + Haiku const payg3pOptions = [getDefaultOptionForUser(fastMode)] + pushUniqueOption(payg3pOptions, getCustomFableOption()) + const customSonnet = getCustomSonnetOption() if (customSonnet !== undefined) { pushUniqueOption(payg3pOptions, customSonnet) } else { - // Add Sonnet 4.6 since Sonnet 4.5 is the default + // Add Sonnet 4.6 since Sonnet 4.5 is the third-party default payg3pOptions.push(getSonnet46Option()) - if (checkSonnet1mAccess()) { + if (shouldOfferSonnet1mOption()) { payg3pOptions.push(getSonnet46_1MOption()) } } @@ -479,8 +537,17 @@ function getModelFamilyInfo( ): { alias: string; currentVersionName: string } | null { const canonical = getCanonicalName(model) + // Fable family + if (canonical.includes('claude-fable-5')) { + const currentName = getMarketingNameForModel(getDefaultFableModel()) + if (currentName) { + return { alias: 'Fable', currentVersionName: currentName } + } + } + // Sonnet family if ( + canonical.includes('claude-sonnet-5') || canonical.includes('claude-sonnet-4-6') || canonical.includes('claude-sonnet-4-5') || canonical.includes('claude-sonnet-4-') || diff --git a/src/utils/model/providers.ts b/src/utils/model/providers.ts index 16f7eb28..d7a09209 100644 --- a/src/utils/model/providers.ts +++ b/src/utils/model/providers.ts @@ -45,3 +45,7 @@ export function isFirstPartyAnthropicBaseUrl(): boolean { return false } } + +export function hasAnthropicCompatibleThirdPartyConfig(): boolean { + return getAPIProvider() !== 'firstParty' || !isFirstPartyAnthropicBaseUrl() +} diff --git a/src/utils/modelCost.ts b/src/utils/modelCost.ts index c71d22ed..c395c9ca 100644 --- a/src/utils/modelCost.ts +++ b/src/utils/modelCost.ts @@ -7,14 +7,17 @@ import { CLAUDE_3_5_HAIKU_CONFIG, CLAUDE_3_5_V2_SONNET_CONFIG, CLAUDE_3_7_SONNET_CONFIG, + CLAUDE_FABLE_5_CONFIG, CLAUDE_HAIKU_4_5_CONFIG, CLAUDE_OPUS_4_1_CONFIG, CLAUDE_OPUS_4_5_CONFIG, CLAUDE_OPUS_4_6_CONFIG, + CLAUDE_OPUS_4_8_CONFIG, CLAUDE_OPUS_4_CONFIG, CLAUDE_SONNET_4_5_CONFIG, CLAUDE_SONNET_4_6_CONFIG, CLAUDE_SONNET_4_CONFIG, + CLAUDE_SONNET_5_CONFIG, } from './model/configs.js' import { firstPartyNameToCanonical, @@ -59,6 +62,15 @@ export const COST_TIER_5_25 = { webSearchRequests: 0.01, } as const satisfies ModelCosts +// Pricing tier for Fable 5: $10 input / $50 output per Mtok +export const COST_TIER_10_50 = { + inputTokens: 10, + outputTokens: 50, + promptCacheWriteTokens: 12.5, + promptCacheReadTokens: 1, + webSearchRequests: 0.01, +} as const satisfies ModelCosts + // Fast mode pricing for Opus 4.7: $30 input / $150 output per Mtok export const COST_TIER_30_150 = { inputTokens: 30, @@ -102,6 +114,8 @@ export function getOpus46CostTier(fastMode: boolean): ModelCosts { // Costs from https://platform.claude.com/docs/en/about-claude/pricing // Web search cost: $10 per 1000 requests = $0.01 per request export const MODEL_COSTS: Record = { + [firstPartyNameToCanonical(CLAUDE_FABLE_5_CONFIG.firstParty)]: + COST_TIER_10_50, [firstPartyNameToCanonical(CLAUDE_3_5_HAIKU_CONFIG.firstParty)]: COST_HAIKU_35, [firstPartyNameToCanonical(CLAUDE_HAIKU_4_5_CONFIG.firstParty)]: @@ -116,6 +130,8 @@ export const MODEL_COSTS: Record = { COST_TIER_3_15, [firstPartyNameToCanonical(CLAUDE_SONNET_4_6_CONFIG.firstParty)]: COST_TIER_3_15, + [firstPartyNameToCanonical(CLAUDE_SONNET_5_CONFIG.firstParty)]: + COST_TIER_3_15, [firstPartyNameToCanonical(CLAUDE_OPUS_4_CONFIG.firstParty)]: COST_TIER_15_75, [firstPartyNameToCanonical(CLAUDE_OPUS_4_1_CONFIG.firstParty)]: COST_TIER_15_75, @@ -123,6 +139,8 @@ export const MODEL_COSTS: Record = { COST_TIER_5_25, [firstPartyNameToCanonical(CLAUDE_OPUS_4_6_CONFIG.firstParty)]: COST_TIER_5_25, + [firstPartyNameToCanonical(CLAUDE_OPUS_4_8_CONFIG.firstParty)]: + COST_TIER_5_25, } /** diff --git a/src/utils/providerManagedEnvCompat.ts b/src/utils/providerManagedEnvCompat.ts index b250fc30..d6556420 100644 --- a/src/utils/providerManagedEnvCompat.ts +++ b/src/utils/providerManagedEnvCompat.ts @@ -1,6 +1,7 @@ const DEEPSEEK_THINKING_CAPABILITIES = 'thinking,effort,adaptive_thinking,max_effort' const DEEPSEEK_CAPABILITY_ENV_KEYS = [ + 'ANTHROPIC_DEFAULT_FABLE_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES', 'ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES', @@ -10,6 +11,7 @@ function looksLikeDeepSeekManagedEnv(env: Record): boolean { const baseUrl = env.ANTHROPIC_BASE_URL ?? '' const modelIds = [ env.ANTHROPIC_MODEL, + env.ANTHROPIC_DEFAULT_FABLE_MODEL, env.ANTHROPIC_DEFAULT_HAIKU_MODEL, env.ANTHROPIC_DEFAULT_SONNET_MODEL, env.ANTHROPIC_DEFAULT_OPUS_MODEL, diff --git a/src/utils/swarm/teammateModel.ts b/src/utils/swarm/teammateModel.ts index c5c0da47..648badbb 100644 --- a/src/utils/swarm/teammateModel.ts +++ b/src/utils/swarm/teammateModel.ts @@ -1,10 +1,13 @@ -import { CLAUDE_OPUS_4_6_CONFIG } from '../model/configs.js' +import { CLAUDE_OPUS_4_6_CONFIG, CLAUDE_OPUS_4_8_CONFIG } from '../model/configs.js' import { getAPIProvider } from '../model/providers.js' // @[MODEL LAUNCH]: Update the fallback model below. // When the user has never set teammateDefaultModel in /config, new teammates -// use Opus 4.7. Must be provider-aware so Bedrock/Vertex/Foundry customers get -// the correct model ID. +// use the current Opus default. Must be provider-aware so Bedrock/Vertex/Foundry +// customers get a conservative provider ID. export function getHardcodedTeammateModelFallback(): string { - return CLAUDE_OPUS_4_6_CONFIG[getAPIProvider()] + const provider = getAPIProvider() + return provider === 'firstParty' + ? CLAUDE_OPUS_4_8_CONFIG.firstParty + : CLAUDE_OPUS_4_6_CONFIG[provider] } diff --git a/src/utils/thinking.ts b/src/utils/thinking.ts index dc742eea..f2abe816 100644 --- a/src/utils/thinking.ts +++ b/src/utils/thinking.ts @@ -161,8 +161,14 @@ export function modelSupportsAdaptiveThinking(model: string): boolean { return false } - // Supported by a subset of Claude 4 models - if (canonical.includes('opus-4-6') || canonical.includes('sonnet-4-6')) { + // Supported by current Claude Code flagship models. + if ( + canonical.includes('sonnet-5') || + canonical.includes('opus-4-8') || + canonical.includes('opus-4-7') || + canonical.includes('opus-4-6') || + canonical.includes('sonnet-4-6') + ) { return true } // Exclude any other known legacy models (allowlist above catches 4-6 variants first)