mirror of
http://10.0.2.1:3031/sauer/claude-code.git
synced 2026-06-30 20:36:57 +10:00
270 lines
30 KiB
TypeScript
270 lines
30 KiB
TypeScript
|
|
import { c as _c } from "react/compiler-runtime";
|
||
|
|
import type { TextBlockParam } from '@anthropic-ai/sdk/resources/index.mjs';
|
||
|
|
import React, { useContext } from 'react';
|
||
|
|
import { ERROR_MESSAGE_USER_ABORT } from 'src/services/compact/compact.js';
|
||
|
|
import { isRateLimitErrorMessage } from 'src/services/rateLimitMessages.js';
|
||
|
|
import { BLACK_CIRCLE } from '../../constants/figures.js';
|
||
|
|
import { Box, NoSelect, Text } from '../../ink.js';
|
||
|
|
import { API_ERROR_MESSAGE_PREFIX, API_TIMEOUT_ERROR_MESSAGE, CREDIT_BALANCE_TOO_LOW_ERROR_MESSAGE, CUSTOM_OFF_SWITCH_MESSAGE, INVALID_API_KEY_ERROR_MESSAGE, INVALID_API_KEY_ERROR_MESSAGE_EXTERNAL, ORG_DISABLED_ERROR_MESSAGE_ENV_KEY, ORG_DISABLED_ERROR_MESSAGE_ENV_KEY_WITH_OAUTH, PROMPT_TOO_LONG_ERROR_MESSAGE, startsWithApiErrorPrefix, TOKEN_REVOKED_ERROR_MESSAGE } from '../../services/api/errors.js';
|
||
|
|
import { isEmptyMessageText, NO_RESPONSE_REQUESTED } from '../../utils/messages.js';
|
||
|
|
import { getUpgradeMessage } from '../../utils/model/contextWindowUpgradeCheck.js';
|
||
|
|
import { getDefaultSonnetModel, renderModelName } from '../../utils/model/model.js';
|
||
|
|
import { isMacOsKeychainLocked } from '../../utils/secureStorage/macOsKeychainStorage.js';
|
||
|
|
import { CtrlOToExpand } from '../CtrlOToExpand.js';
|
||
|
|
import { InterruptedByUser } from '../InterruptedByUser.js';
|
||
|
|
import { Markdown } from '../Markdown.js';
|
||
|
|
import { MessageResponse } from '../MessageResponse.js';
|
||
|
|
import { MessageActionsSelectedContext } from '../messageActions.js';
|
||
|
|
import { RateLimitMessage } from './RateLimitMessage.js';
|
||
|
|
const MAX_API_ERROR_CHARS = 1000;
|
||
|
|
type Props = {
|
||
|
|
param: TextBlockParam;
|
||
|
|
addMargin: boolean;
|
||
|
|
shouldShowDot: boolean;
|
||
|
|
verbose: boolean;
|
||
|
|
width?: number | string;
|
||
|
|
onOpenRateLimitOptions?: () => void;
|
||
|
|
};
|
||
|
|
function InvalidApiKeyMessage() {
|
||
|
|
const $ = _c(2);
|
||
|
|
let t0;
|
||
|
|
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t0 = isMacOsKeychainLocked();
|
||
|
|
$[0] = t0;
|
||
|
|
} else {
|
||
|
|
t0 = $[0];
|
||
|
|
}
|
||
|
|
const isKeychainLocked = t0;
|
||
|
|
let t1;
|
||
|
|
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t1 = <MessageResponse><Box flexDirection="column"><Text color="error">{INVALID_API_KEY_ERROR_MESSAGE}</Text>{isKeychainLocked && <Text dimColor={true}>· Run in another terminal: security unlock-keychain</Text>}</Box></MessageResponse>;
|
||
|
|
$[1] = t1;
|
||
|
|
} else {
|
||
|
|
t1 = $[1];
|
||
|
|
}
|
||
|
|
return t1;
|
||
|
|
}
|
||
|
|
export function AssistantTextMessage(t0) {
|
||
|
|
const $ = _c(34);
|
||
|
|
const {
|
||
|
|
param: t1,
|
||
|
|
addMargin,
|
||
|
|
shouldShowDot,
|
||
|
|
verbose,
|
||
|
|
onOpenRateLimitOptions
|
||
|
|
} = t0;
|
||
|
|
const {
|
||
|
|
text
|
||
|
|
} = t1;
|
||
|
|
const isSelected = useContext(MessageActionsSelectedContext);
|
||
|
|
if (isEmptyMessageText(text)) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
if (isRateLimitErrorMessage(text)) {
|
||
|
|
let t2;
|
||
|
|
if ($[0] !== onOpenRateLimitOptions || $[1] !== text) {
|
||
|
|
t2 = <RateLimitMessage text={text} onOpenRateLimitOptions={onOpenRateLimitOptions} />;
|
||
|
|
$[0] = onOpenRateLimitOptions;
|
||
|
|
$[1] = text;
|
||
|
|
$[2] = t2;
|
||
|
|
} else {
|
||
|
|
t2 = $[2];
|
||
|
|
}
|
||
|
|
return t2;
|
||
|
|
}
|
||
|
|
switch (text) {
|
||
|
|
case NO_RESPONSE_REQUESTED:
|
||
|
|
{
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
case PROMPT_TOO_LONG_ERROR_MESSAGE:
|
||
|
|
{
|
||
|
|
let t2;
|
||
|
|
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t2 = getUpgradeMessage("warning");
|
||
|
|
$[3] = t2;
|
||
|
|
} else {
|
||
|
|
t2 = $[3];
|
||
|
|
}
|
||
|
|
const upgradeHint = t2;
|
||
|
|
let t3;
|
||
|
|
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t3 = <MessageResponse height={1}><Text color="error">Context limit reached · /compact or /clear to continue{upgradeHint ? ` · ${upgradeHint}` : ""}</Text></MessageResponse>;
|
||
|
|
$[4] = t3;
|
||
|
|
} else {
|
||
|
|
t3 = $[4];
|
||
|
|
}
|
||
|
|
return t3;
|
||
|
|
}
|
||
|
|
case CREDIT_BALANCE_TOO_LOW_ERROR_MESSAGE:
|
||
|
|
{
|
||
|
|
let t2;
|
||
|
|
if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t2 = <MessageResponse height={1}><Text color="error">Credit balance too low · Add funds: https://platform.claude.com/settings/billing</Text></MessageResponse>;
|
||
|
|
$[5] = t2;
|
||
|
|
} else {
|
||
|
|
t2 = $[5];
|
||
|
|
}
|
||
|
|
return t2;
|
||
|
|
}
|
||
|
|
case INVALID_API_KEY_ERROR_MESSAGE:
|
||
|
|
{
|
||
|
|
let t2;
|
||
|
|
if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t2 = <InvalidApiKeyMessage />;
|
||
|
|
$[6] = t2;
|
||
|
|
} else {
|
||
|
|
t2 = $[6];
|
||
|
|
}
|
||
|
|
return t2;
|
||
|
|
}
|
||
|
|
case INVALID_API_KEY_ERROR_MESSAGE_EXTERNAL:
|
||
|
|
{
|
||
|
|
let t2;
|
||
|
|
if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t2 = <MessageResponse height={1}><Text color="error">{INVALID_API_KEY_ERROR_MESSAGE_EXTERNAL}</Text></MessageResponse>;
|
||
|
|
$[7] = t2;
|
||
|
|
} else {
|
||
|
|
t2 = $[7];
|
||
|
|
}
|
||
|
|
return t2;
|
||
|
|
}
|
||
|
|
case ORG_DISABLED_ERROR_MESSAGE_ENV_KEY:
|
||
|
|
case ORG_DISABLED_ERROR_MESSAGE_ENV_KEY_WITH_OAUTH:
|
||
|
|
{
|
||
|
|
let t2;
|
||
|
|
if ($[8] !== text) {
|
||
|
|
t2 = <MessageResponse><Text color="error">{text}</Text></MessageResponse>;
|
||
|
|
$[8] = text;
|
||
|
|
$[9] = t2;
|
||
|
|
} else {
|
||
|
|
t2 = $[9];
|
||
|
|
}
|
||
|
|
return t2;
|
||
|
|
}
|
||
|
|
case TOKEN_REVOKED_ERROR_MESSAGE:
|
||
|
|
{
|
||
|
|
let t2;
|
||
|
|
if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t2 = <MessageResponse height={1}><Text color="error">{TOKEN_REVOKED_ERROR_MESSAGE}</Text></MessageResponse>;
|
||
|
|
$[10] = t2;
|
||
|
|
} else {
|
||
|
|
t2 = $[10];
|
||
|
|
}
|
||
|
|
return t2;
|
||
|
|
}
|
||
|
|
case API_TIMEOUT_ERROR_MESSAGE:
|
||
|
|
{
|
||
|
|
let t2;
|
||
|
|
if ($[11] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t2 = <MessageResponse height={1}><Text color="error">{API_TIMEOUT_ERROR_MESSAGE}{process.env.API_TIMEOUT_MS && <>{" "}(API_TIMEOUT_MS={process.env.API_TIMEOUT_MS}ms, try increasing it)</>}</Text></MessageResponse>;
|
||
|
|
$[11] = t2;
|
||
|
|
} else {
|
||
|
|
t2 = $[11];
|
||
|
|
}
|
||
|
|
return t2;
|
||
|
|
}
|
||
|
|
case CUSTOM_OFF_SWITCH_MESSAGE:
|
||
|
|
{
|
||
|
|
let t2;
|
||
|
|
if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t2 = <Text color="error">We are experiencing high demand for Opus 4.</Text>;
|
||
|
|
$[12] = t2;
|
||
|
|
} else {
|
||
|
|
t2 = $[12];
|
||
|
|
}
|
||
|
|
let t3;
|
||
|
|
if ($[13] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t3 = <MessageResponse><Box flexDirection="column" gap={1}>{t2}<Text>To continue immediately, use /model to switch to{" "}{renderModelName(getDefaultSonnetModel())} and continue coding.</Text></Box></MessageResponse>;
|
||
|
|
$[13] = t3;
|
||
|
|
} else {
|
||
|
|
t3 = $[13];
|
||
|
|
}
|
||
|
|
return t3;
|
||
|
|
}
|
||
|
|
case ERROR_MESSAGE_USER_ABORT:
|
||
|
|
{
|
||
|
|
let t2;
|
||
|
|
if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t2 = <MessageResponse height={1}><InterruptedByUser /></MessageResponse>;
|
||
|
|
$[14] = t2;
|
||
|
|
} else {
|
||
|
|
t2 = $[14];
|
||
|
|
}
|
||
|
|
return t2;
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
{
|
||
|
|
if (startsWithApiErrorPrefix(text)) {
|
||
|
|
const truncated = !verbose && text.length > MAX_API_ERROR_CHARS;
|
||
|
|
const t2 = text === API_ERROR_MESSAGE_PREFIX ? `${API_ERROR_MESSAGE_PREFIX}: Please wait a moment and try again.` : truncated ? text.slice(0, MAX_API_ERROR_CHARS) + "\u2026" : text;
|
||
|
|
let t3;
|
||
|
|
if ($[15] !== t2) {
|
||
|
|
t3 = <Text color="error">{t2}</Text>;
|
||
|
|
$[15] = t2;
|
||
|
|
$[16] = t3;
|
||
|
|
} else {
|
||
|
|
t3 = $[16];
|
||
|
|
}
|
||
|
|
let t4;
|
||
|
|
if ($[17] !== truncated) {
|
||
|
|
t4 = truncated && <CtrlOToExpand />;
|
||
|
|
$[17] = truncated;
|
||
|
|
$[18] = t4;
|
||
|
|
} else {
|
||
|
|
t4 = $[18];
|
||
|
|
}
|
||
|
|
let t5;
|
||
|
|
if ($[19] !== t3 || $[20] !== t4) {
|
||
|
|
t5 = <MessageResponse><Box flexDirection="column">{t3}{t4}</Box></MessageResponse>;
|
||
|
|
$[19] = t3;
|
||
|
|
$[20] = t4;
|
||
|
|
$[21] = t5;
|
||
|
|
} else {
|
||
|
|
t5 = $[21];
|
||
|
|
}
|
||
|
|
return t5;
|
||
|
|
}
|
||
|
|
const t2 = addMargin ? 1 : 0;
|
||
|
|
const t3 = isSelected ? "messageActionsBackground" : undefined;
|
||
|
|
let t4;
|
||
|
|
if ($[22] !== isSelected || $[23] !== shouldShowDot) {
|
||
|
|
t4 = shouldShowDot && <NoSelect fromLeftEdge={true} minWidth={2}><Text color={isSelected ? "suggestion" : "text"}>{BLACK_CIRCLE}</Text></NoSelect>;
|
||
|
|
$[22] = isSelected;
|
||
|
|
$[23] = shouldShowDot;
|
||
|
|
$[24] = t4;
|
||
|
|
} else {
|
||
|
|
t4 = $[24];
|
||
|
|
}
|
||
|
|
let t5;
|
||
|
|
if ($[25] !== text) {
|
||
|
|
t5 = <Box flexDirection="column"><Markdown>{text}</Markdown></Box>;
|
||
|
|
$[25] = text;
|
||
|
|
$[26] = t5;
|
||
|
|
} else {
|
||
|
|
t5 = $[26];
|
||
|
|
}
|
||
|
|
let t6;
|
||
|
|
if ($[27] !== t4 || $[28] !== t5) {
|
||
|
|
t6 = <Box flexDirection="row">{t4}{t5}</Box>;
|
||
|
|
$[27] = t4;
|
||
|
|
$[28] = t5;
|
||
|
|
$[29] = t6;
|
||
|
|
} else {
|
||
|
|
t6 = $[29];
|
||
|
|
}
|
||
|
|
let t7;
|
||
|
|
if ($[30] !== t2 || $[31] !== t3 || $[32] !== t6) {
|
||
|
|
t7 = <Box alignItems="flex-start" flexDirection="row" justifyContent="space-between" marginTop={t2} width="100%" backgroundColor={t3}>{t6}</Box>;
|
||
|
|
$[30] = t2;
|
||
|
|
$[31] = t3;
|
||
|
|
$[32] = t6;
|
||
|
|
$[33] = t7;
|
||
|
|
} else {
|
||
|
|
t7 = $[33];
|
||
|
|
}
|
||
|
|
return t7;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJUZXh0QmxvY2tQYXJhbSIsIlJlYWN0IiwidXNlQ29udGV4dCIsIkVSUk9SX01FU1NBR0VfVVNFUl9BQk9SVCIsImlzUmF0ZUxpbWl0RXJyb3JNZXNzYWdlIiwiQkxBQ0tfQ0lSQ0xFIiwiQm94IiwiTm9TZWxlY3QiLCJUZXh0IiwiQVBJX0VSUk9SX01FU1NBR0VfUFJFRklYIiwiQVBJX1RJTUVPVVRfRVJST1JfTUVTU0FHRSIsIkNSRURJVF9CQUxBTkNFX1RPT19MT1dfRVJST1JfTUVTU0FHRSIsIkNVU1RPTV9PRkZfU1dJVENIX01FU1NBR0UiLCJJTlZBTElEX0FQSV9LRVlfRVJST1JfTUVTU0FHRSIsIklOVkFMSURfQVBJX0tFWV9FUlJPUl9NRVNTQUdFX0VYVEVSTkFMIiwiT1JHX0RJU0FCTEVEX0VSUk9SX01FU1NBR0VfRU5WX0tFWSIsIk9SR19ESVNBQkxFRF9FUlJPUl9NRVNTQUdFX0VOVl9LRVlfV0lUSF9PQVVUSCIsIlBST01QVF9UT09fTE9OR19FUlJPUl9NRVNTQUdFIiwic3RhcnRzV2l0aEFwaUVycm9yUHJlZml4IiwiVE9LRU5fUkVWT0tFRF9FUlJPUl9NRVNTQUdFIiwiaXNFbXB0eU1lc3NhZ2VUZXh0IiwiTk9fUkVTUE9OU0VfUkVRVUVTVEVEIiwiZ2V0VXBncmFkZU1lc3NhZ2UiLCJnZXREZWZhdWx0U29ubmV0TW9kZWwiLCJyZW5kZXJNb2RlbE5hbWUiLCJpc01hY09zS2V5Y2hhaW5Mb2NrZWQiLCJDdHJsT1RvRXhwYW5kIiwiSW50ZXJydXB0ZWRCeVVzZXIiLCJNYXJrZG93biIsIk1lc3NhZ2VSZXNwb25zZSIsIk1lc3NhZ2VBY3Rpb25zU2VsZWN0ZWRDb250ZXh0IiwiUmF0ZUxpbWl0TWVzc2FnZSIsIk1BWF9BUElfRVJST1JfQ0hBUlMiLCJQcm9wcyIsInBhcmFtIiwiYWRkTWFyZ2luIiwic2hvdWxkU2hvd0RvdCIsInZlcmJvc2UiLCJ3aWR0aCIsIm9uT3BlblJhdGVMaW1pdE9wdGlvbnMiLCJJbnZhbGlkQXBpS2V5TWVzc2FnZSIsIiQiLCJfYyIsInQwIiwiU3ltYm9sIiwiZm9yIiwiaXNLZXljaGFpbkxvY2tlZCIsInQxIiwiQXNzaXN0YW50VGV4dE1lc3NhZ2UiLCJ0ZXh0IiwiaXNTZWxlY3RlZCIsInQyIiwidXBncmFkZUhpbnQiLCJ0MyIsInByb2Nlc3MiLCJlbnYiLCJBUElfVElNRU9VVF9NUyIsInRydW5jYXRlZCIsImxlbmd0aCIsInNsaWNlIiwidDQiLCJ0NSIsInVuZGVmaW5lZCIsInQ2IiwidDciXSwic291cmNlcyI6WyJBc3Npc3RhbnRUZXh0TWVzc2FnZS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBUZXh0QmxvY2tQYXJhbSB9IGZyb20gJ0BhbnRocm9waWMtYWkvc2RrL3Jlc291cmNlcy9pbmRleC5tanMnXG5pbXBvcnQgUmVhY3QsIHsgdXNlQ29udGV4dCB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgRVJST1JfTUVTU0FHRV9VU0VSX0FCT1JUIH0gZnJvbSAnc3JjL3NlcnZpY2VzL2NvbXBhY3QvY29tcGFjdC5qcydcbmltcG9ydCB7IGlzUmF0ZUxpbWl0RXJyb3JNZXNzYWdlIH0gZnJvbSAnc3JjL3NlcnZpY2VzL3JhdGVMaW1pdE1lc3NhZ2VzLmpzJ1xuaW1wb3J0IHsgQkxBQ0tfQ0lSQ0xFIH0gZnJvbSAnLi4vLi4vY29uc3RhbnRzL2ZpZ3VyZXMuanMnXG5pbXBvcnQgeyBCb3gsIE5vU2VsZWN0LCBUZXh0IH0gZnJvbSAnLi4vLi4vaW5rLmpzJ1xuaW1wb3J0IHtcbiAgQVBJX0VSUk9SX01FU1NBR0VfUFJFRklYLFxuICBBUElfVElNRU9VVF9FUlJPUl9NRVNTQUdFLFxuICBDUkVESVRfQkFMQU5DRV9UT09fTE9XX0VSUk9SX01FU1NBR0UsXG4gIENVU1RPTV9PRkZfU1dJVENIX01FU1NBR0UsXG4gIElOVkFMSURfQVBJX0tFWV9FUlJPUl9NRVNTQUdFLFxuICBJTlZBTElEX0FQSV9LRVlfRVJST1JfTUVTU0FHRV9FWFRFUk5BTCxcbiAgT1JHX0RJU0FCTEVEX0VSUk9SX01FU1NBR0VfRU5WX0tFWSxcbiAgT1JHX0RJU0FCTEVEX0VSUk9SX01FU1NBR0VfRU5WX0tFWV9XSVRIX09BVVRILFxuICBQUk9NUFRfVE9PX0xPTkdfRVJST1JfTUVTU0FHRSxcbiAgc3RhcnRzV2l0aEFwaUVycm9yUHJlZml4LFxuICBUT0tFTl9SRVZPS0VEX0VSUk9SX01FU1NBR0UsXG59IGZyb20gJy4uLy4uL3NlcnZpY2VzL2FwaS9lcnJvcnMuanMnXG5pbXBvcnQge1xuICBpc0VtcHR5TWVzc2FnZVRleHQsXG4gIE5PX1JFU1BPTlNFX1JFUVVFU1RFRCxcbn0gZnJvbSAnLi4vLi4vdXRpbHMvbWVzc2FnZXMuanMnXG5pbXBvcnQgeyBnZXRVcGdyYWRlTWVzc2FnZSB9IGZyb20gJy4uLy4uL3V0aWxzL21vZGVsL2NvbnRleHRXaW5kb3dVcGdyYWRlQ2hlY2suanMnXG5pbXBvcnQge1xuICBnZXREZWZhdWx0U29ubmV0TW9kZWwsXG4gIHJlbmRlck1vZGVsTmFtZSxcbn0gZnJvbSAnLi4vLi4vdXRpbHMvbW9kZWwvbW9kZWwuanMnXG5pbXBvcnQgeyBpc01hY09zS2V5Y2hhaW5Mb2NrZWQgfSBmcm9tICcuLi8uLi91dGlscy9zZWN1cmVTdG9yYWdlL21hY09zS2V5Y2hhaW5TdG9yYWdlLmpzJ1xuaW1wb3J0IHsgQ3RybE9Ub0V4cGFuZCB9IGZyb20gJy4uL0N0cmxPVG9FeHBhbmQuanMnXG5pbXBvcnQgeyBJbnRlcnJ1cHRlZEJ5VXNlciB9IGZyb20gJy4uL0ludGVycnVwdGVkQnlVc2VyLmpzJ1xuaW1wb3J0IHsgTWFya2Rvd24gfSBmcm9tICcuLi9NYXJrZG93bi5qcydcbmltcG9ydCB7IE1lc3NhZ2VSZXNwb25zZSB9IGZyb20gJy4uL01lc3NhZ2VSZXNwb25zZS5qcydcbmltcG9ydCB7IE1lc3NhZ2VBY3Rpb25zU2VsZWN0ZWRDb250ZXh0IH0gZnJvbSAnLi4vbWVzc2FnZUFjdGlvbnMuanMnXG5pbXBvcnQgeyBSYXRlTGltaXRNZXNzYWdlIH0gZnJvbSAnLi9SYXRlTGltaXRNZXNzYWdlLmpzJ1xuXG5jb25zdCBNQVhfQVBJX0VSUk9SX0NIQVJTID0gMTAwMFxuXG50eXBlIFByb3BzID0ge1xuICBwYXJhbTogVGV4dEJsb2NrUGFyYW1cbiAgYWRkTWFyZ2luOiBib29sZWFuXG4gIHNob3VsZFNob3dEb3Q6IGJvb2xlYW5cbiAgdmVyYm9zZTogYm9vbGVhblxuICB3aWR0aD86IG51bWJlciB8IHN0cmluZ1xuICBvbk9wZW5SYXRlTGltaXRPcHRpb25zPzogKCkgPT4gdm9pZFxufVxuXG5mdW5jdGlvbiBJbnZhbGlkQXBpS2V5TWVzc2FnZSgpOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBpc0tleWNoYWluTG9ja2VkID0gaXNNYWNPc0tleWNoYWluTG9ja2VkKClcblx
|