Filehigh importancesource

UserToolSuccessMessage.tsx

components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx

104
Lines
16409
Bytes
1
Exports
12
Imports
10
Keywords

What this is

This page documents one file from the repository and includes its full source so you can read it without leaving the docs site.

Beginner explanation

This file is one piece of the larger system. Its name, directory, imports, and exports show where it fits. Start by reading the exports and related files first.

How it is used

Start from the exports list and related files. Those are the easiest clues for where this file fits into the system.

Expert explanation

Architecturally, this file intersects with tool-system, ui-flow. It contains 104 lines, 12 detected imports, and 1 detected exports.

Important relationships

Detected exports

  • UserToolSuccessMessage

Keywords

tooltooluseidtextfeaturemessagereacttoolsmessageresponselookupsverbose

Detected imports

  • bun:bundle
  • figures
  • react
  • src/components/SentryErrorBoundary.js
  • ../../../ink.js
  • ../../../state/AppState.js
  • ../../../Tool.js
  • ../../../types/message.js
  • ../../../utils/classifierApprovals.js
  • ../../../utils/messages.js
  • ../../MessageResponse.js
  • ../HookProgressMessage.js

Source notes

This page embeds the full file contents. Small or leaf files are still indexed honestly instead of being over-explained.

Open parent directory

Full source

import { feature } from 'bun:bundle';
import figures from 'figures';
import * as React from 'react';
import { SentryErrorBoundary } from 'src/components/SentryErrorBoundary.js';
import { Box, Text, useTheme } from '../../../ink.js';
import { useAppState } from '../../../state/AppState.js';
import { filterToolProgressMessages, type Tool, type Tools } from '../../../Tool.js';
import type { NormalizedUserMessage, ProgressMessage } from '../../../types/message.js';
import { deleteClassifierApproval, getClassifierApproval, getYoloClassifierApproval } from '../../../utils/classifierApprovals.js';
import type { buildMessageLookups } from '../../../utils/messages.js';
import { MessageResponse } from '../../MessageResponse.js';
import { HookProgressMessage } from '../HookProgressMessage.js';
type Props = {
  message: NormalizedUserMessage;
  lookups: ReturnType<typeof buildMessageLookups>;
  toolUseID: string;
  progressMessagesForMessage: ProgressMessage[];
  style?: 'condensed';
  tool?: Tool;
  tools: Tools;
  verbose: boolean;
  width: number | string;
  isTranscriptMode?: boolean;
};
export function UserToolSuccessMessage({
  message,
  lookups,
  toolUseID,
  progressMessagesForMessage,
  style,
  tool,
  tools,
  verbose,
  width,
  isTranscriptMode
}: Props): React.ReactNode {
  const [theme] = useTheme();
  // Hook stays inside feature() ternary so external builds don't pay a
  // per-scrollback-message store subscription — same pattern as
  // UserPromptMessage.tsx.
  const isBriefOnly = feature('KAIROS') || feature('KAIROS_BRIEF') ?
  // biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
  useAppState(s => s.isBriefOnly) : false;

  // Capture classifier approval once on mount, then delete from Map to prevent linear growth.
  // useState lazy initializer ensures the value persists across re-renders.
  const [classifierRule] = React.useState(() => getClassifierApproval(toolUseID));
  const [yoloReason] = React.useState(() => getYoloClassifierApproval(toolUseID));
  React.useEffect(() => {
    deleteClassifierApproval(toolUseID);
  }, [toolUseID]);
  if (!message.toolUseResult || !tool) {
    return null;
  }

  // Resumed transcripts deserialize toolUseResult via raw JSON.parse with no
  // validation (parseJSONL). A partial/corrupt/old-format result crashes
  // renderToolResultMessage on first field access (anthropics/claude-code#39817).
  // Validate against outputSchema before rendering — mirrors CollapsedReadSearchContent.
  const parsedOutput = tool.outputSchema?.safeParse(message.toolUseResult);
  if (parsedOutput && !parsedOutput.success) {
    return null;
  }
  const toolResult = parsedOutput?.data ?? message.toolUseResult;
  const renderedMessage = tool.renderToolResultMessage?.(toolResult as never, filterToolProgressMessages(progressMessagesForMessage), {
    style,
    theme,
    tools,
    verbose,
    isTranscriptMode,
    isBriefOnly,
    input: lookups.toolUseByToolUseID.get(toolUseID)?.input
  }) ?? null;

  // Don't render anything if the tool result message is null
  if (renderedMessage === null) {
    return null;
  }

  // Tools that return '' from userFacingName opt out of tool chrome and
  // render like plain assistant text. Skip the tool-result width constraint
  // so MarkdownTable's SAFETY_MARGIN=4 (tuned for the assistant-text 2-col
  // dot gutter) holds — otherwise tables wrap their box-drawing chars.
  const rendersAsAssistantText = tool.userFacingName(undefined) === '';
  return <Box flexDirection="column">
      <Box flexDirection="column" width={rendersAsAssistantText ? undefined : width}>
        {renderedMessage}
        {feature('BASH_CLASSIFIER') ? classifierRule && <MessageResponse height={1}>
                <Text dimColor>
                  <Text color="success">{figures.tick}</Text>
                  {' Auto-approved \u00b7 matched '}
                  {`"${classifierRule}"`}
                </Text>
              </MessageResponse> : null}
        {feature('TRANSCRIPT_CLASSIFIER') ? yoloReason && <MessageResponse height={1}>
                <Text dimColor>Allowed by auto mode classifier</Text>
              </MessageResponse> : null}
      </Box>
      <SentryErrorBoundary>
        <HookProgressMessage hookEvent="PostToolUse" lookups={lookups} toolUseID={toolUseID} verbose={verbose} isTranscriptMode={isTranscriptMode} />
      </SentryErrorBoundary>
    </Box>;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmZWF0dXJlIiwiZmlndXJlcyIsIlJlYWN0IiwiU2VudHJ5RXJyb3JCb3VuZGFyeSIsIkJveCIsIlRleHQiLCJ1c2VUaGVtZSIsInVzZUFwcFN0YXRlIiwiZmlsdGVyVG9vbFByb2dyZXNzTWVzc2FnZXMiLCJUb29sIiwiVG9vbHMiLCJOb3JtYWxpemVkVXNlck1lc3NhZ2UiLCJQcm9ncmVzc01lc3NhZ2UiLCJkZWxldGVDbGFzc2lmaWVyQXBwcm92YWwiLCJnZXRDbGFzc2lmaWVyQXBwcm92YWwiLCJnZXRZb2xvQ2xhc3NpZmllckFwcHJvdmFsIiwiYnVpbGRNZXNzYWdlTG9va3VwcyIsIk1lc3NhZ2VSZXNwb25zZSIsIkhvb2tQcm9ncmVzc01lc3NhZ2UiLCJQcm9wcyIsIm1lc3NhZ2UiLCJsb29rdXBzIiwiUmV0dXJuVHlwZSIsInRvb2xVc2VJRCIsInByb2dyZXNzTWVzc2FnZXNGb3JNZXNzYWdlIiwic3R5bGUiLCJ0b29sIiwidG9vbHMiLCJ2ZXJib3NlIiwid2lkdGgiLCJpc1RyYW5zY3JpcHRNb2RlIiwiVXNlclRvb2xTdWNjZXNzTWVzc2FnZSIsIlJlYWN0Tm9kZSIsInRoZW1lIiwiaXNCcmllZk9ubHkiLCJzIiwiY2xhc3NpZmllclJ1bGUiLCJ1c2VTdGF0ZSIsInlvbG9SZWFzb24iLCJ1c2VFZmZlY3QiLCJ0b29sVXNlUmVzdWx0IiwicGFyc2VkT3V0cHV0Iiwib3V0cHV0U2NoZW1hIiwic2FmZVBhcnNlIiwic3VjY2VzcyIsInRvb2xSZXN1bHQiLCJkYXRhIiwicmVuZGVyZWRNZXNzYWdlIiwicmVuZGVyVG9vbFJlc3VsdE1lc3NhZ2UiLCJpbnB1dCIsInRvb2xVc2VCeVRvb2xVc2VJRCIsImdldCIsInJlbmRlcnNBc0Fzc2lzdGFudFRleHQiLCJ1c2VyRmFjaW5nTmFtZSIsInVuZGVmaW5lZCIsInRpY2siXSwic291cmNlcyI6WyJVc2VyVG9vbFN1Y2Nlc3NNZXNzYWdlLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmZWF0dXJlIH0gZnJvbSAnYnVuOmJ1bmRsZSdcbmltcG9ydCBmaWd1cmVzIGZyb20gJ2ZpZ3VyZXMnXG5pbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IFNlbnRyeUVycm9yQm91bmRhcnkgfSBmcm9tICdzcmMvY29tcG9uZW50cy9TZW50cnlFcnJvckJvdW5kYXJ5LmpzJ1xuaW1wb3J0IHsgQm94LCBUZXh0LCB1c2VUaGVtZSB9IGZyb20gJy4uLy4uLy4uL2luay5qcydcbmltcG9ydCB7IHVzZUFwcFN0YXRlIH0gZnJvbSAnLi4vLi4vLi4vc3RhdGUvQXBwU3RhdGUuanMnXG5pbXBvcnQge1xuICBmaWx0ZXJUb29sUHJvZ3Jlc3NNZXNzYWdlcyxcbiAgdHlwZSBUb29sLFxuICB0eXBlIFRvb2xzLFxufSBmcm9tICcuLi8uLi8uLi9Ub29sLmpzJ1xuaW1wb3J0IHR5cGUge1xuICBOb3JtYWxpemVkVXNlck1lc3NhZ2UsXG4gIFByb2dyZXNzTWVzc2FnZSxcbn0gZnJvbSAnLi4vLi4vLi4vdHlwZXMvbWVzc2FnZS5qcydcbmltcG9ydCB7XG4gIGRlbGV0ZUNsYXNzaWZpZXJBcHByb3ZhbCxcbiAgZ2V0Q2xhc3NpZmllckFwcHJvdmFsLFxuICBnZXRZb2xvQ2xhc3NpZmllckFwcHJvdmFsLFxufSBmcm9tICcuLi8uLi8uLi91dGlscy9jbGFzc2lmaWVyQXBwcm92YWxzLmpzJ1xuaW1wb3J0IHR5cGUgeyBidWlsZE1lc3NhZ2VMb29rdXBzIH0gZnJvbSAnLi4vLi4vLi4vdXRpbHMvbWVzc2FnZXMuanMnXG5pbXBvcnQgeyBNZXNzYWdlUmVzcG9uc2UgfSBmcm9tICcuLi8uLi9NZXNzYWdlUmVzcG9uc2UuanMnXG5pbXBvcnQgeyBIb29rUHJvZ3Jlc3NNZXNzYWdlIH0gZnJvbSAnLi4vSG9va1Byb2dyZXNzTWVzc2FnZS5qcydcblxudHlwZSBQcm9wcyA9IHtcbiAgbWVzc2FnZTogTm9ybWFsaXplZFVzZXJNZXNzYWdlXG4gIGxvb2t1cHM6IFJldHVyblR5cGU8dHlwZW9mIGJ1aWxkTWVzc2FnZUxvb2t1cHM+XG4gIHRvb2xVc2VJRDogc3RyaW5nXG4gIHByb2dyZXNzTWVzc2FnZXNGb3JNZXNzYWdlOiBQcm9ncmVzc01lc3NhZ2VbXVxuICBzdHlsZT86ICdjb25kZW5zZWQnXG4gIHRvb2w/OiBUb29sXG4gIHRvb2xzOiBUb29sc1xuICB2ZXJib3NlOiBib29sZWFuXG4gIHdpZHRoOiBudW1iZXIgfCBzdHJpbmdcbiAgaXNUcmFuc2NyaXB0TW9kZT86IGJvb2xlYW5cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIFVzZXJUb29sU3VjY2Vzc01lc3NhZ2Uoe1xuICBtZXNzYWdlLFxuICBsb29rdXBzLFxuICB0b29sVXNlSUQsXG4gIHByb2dyZXNzTWVzc2FnZXNGb3JNZXNzYWdlLFxuICBzdHlsZSxcbiAgdG9vbCxcbiAgdG9vbHMsXG4gIHZlcmJvc2UsXG4gIHdpZHRoLFxuICBpc1RyYW5zY3JpcHRNb2RlLFxufTogUHJvcHMpOiBSZWFjdC5SZWFjdE5vZGUge1xuICBjb25zdCBbdGhlbWVdID0gdXNlVGhlbWUoKVxuICAvLyBIb29rIHN0YXlzIGluc2lkZSBmZWF0dXJlKCkgdGVybmFyeSBzbyBleHRlcm5hbCBidWlsZHMgZG9uJ3QgcGF5IGFcbiAgLy8gcGVyLXNjcm9sbGJhY2stbWVzc2FnZSBzdG9yZSBzdWJzY3JpcHRpb24g4oCUIHNhbWUgcGF0dGVybiBhc1xuICAvLyBVc2VyUHJvbXB0TWVzc2FnZS50c3guXG4gIGNvbnN0IGlzQnJpZWZPbmx5ID1cbiAgICBmZWF0dXJlKCdLQUlST1MnKSB8fCBmZWF0dXJlKCdLQUlST1NfQlJJRUYnKVxuICAgICAgPyAvLyBiaW9tZS1pZ25vcmUgbGludC9jb3JyZWN0bmVzcy91c2VIb29rQXRUb3BMZXZlbDogZmVhdHVyZSgpIGlzIGEgY29tcGlsZS10aW1lIGNvbnN0YW50XG4gICAgICAgIHVzZUFwcFN0YXRlKHMgPT4gcy5pc0JyaWVmT25seSlcbiAgICAgIDogZmFsc2VcblxuICAvLyBDYXB0dXJlIGNsYXNzaWZpZXIgYXBwcm92YWwgb25jZSBvbiBtb3VudCwgdGhlbiBkZWxldGUgZnJvbSBNYXAgdG8gcHJldmVudCBsaW5lYXIgZ3Jvd3RoLlxuICAvLyB1c2VTdGF0ZSBsYXp5IGluaXRpYWxpemVyIGVuc3VyZXMgdGhlIHZhbHVlIHBlcnNpc3RzIGFjcm9zcyByZS1yZW5kZXJzLlxuICBjb25zdCBbY2xhc3NpZmllclJ1bGVdID0gUmVhY3QudXNlU3RhdGUoKCkgPT5cbiAgICBnZXRDbGFzc2lmaWVyQXBwcm92YWwodG9vbFVzZUlEKSxcbiAgKVxuICBjb25zdCBbeW9sb1JlYXNvbl0gPSBSZWFjdC51c2VTdGF0ZSgoKSA9PlxuICAgIGdldFlvbG9DbGFzc2lmaWVyQXBwcm92YWwodG9vbFVzZUlEKSxcbiAgKVxuICBSZWFjdC51c2VFZmZlY3QoKCkgPT4ge1xuICAgIGRlbGV0ZUNsYXNzaWZpZXJBcHByb3ZhbCh0b29sVXNlSUQpXG4gIH0sIFt0b29sVXNlSURdKVxuXG4gIGlmICghbWVzc2FnZS50b29sVXNlUmVzdWx0IHx8ICF0b29sKSB7XG4gICAgcmV0dXJuIG51bGxcbiAgfVxuXG4gIC8vIFJlc3VtZWQgdHJhbnNjcmlwdHMgZGVzZXJpYWxpemUgdG9vbFVzZVJlc3VsdCB2aWEgcmF3IEpTT04ucGFyc2Ugd2l0aCBub1xuICAvLyB2YWxpZGF0aW9uIChwYXJzZUpTT05MKS4gQSBwYXJ0aWFsL2NvcnJ1cHQvb2xkLWZvcm1hdCByZXN1bHQgY3Jhc2hlc1xuICAvLyByZW5kZXJUb29sUmVzdWx0TWVzc2FnZSBvbiBmaXJzdCBmaWVsZCBhY2Nlc3MgKGFudGhyb3BpY3MvY2xhdWRlLWNvZGUjMzk4MTcpLlxuICAvLyBWYWxpZGF0ZSBhZ2FpbnN0IG91dHB1dFNjaGVtYSBiZWZvcmUgcmVuZGVyaW5nIOKAlCBtaXJyb3JzIENvbGxhcHNlZFJlYWRTZWFyY2hDb250ZW50LlxuICBjb25zdCBwYXJzZWRPdXRwdXQgPSB0b29sLm91dHB1dFNjaGVtYT8uc2FmZVBhcnNlKG1lc3NhZ2UudG9vbFVzZVJlc3VsdClcbiAgaWYgKHBhcnNlZE91dHB1dCAmJiAhcGFyc2VkT3V0cHV0LnN1Y2Nlc3MpIHtcbiAgICByZXR1cm4gbnVsbFxuICB9XG4gIGNvbnN0IHRvb2xSZXN1bHQgPSBwYXJzZWRPdXRwdXQ/LmRhdGEgPz8gbWVzc2FnZS50b29sVXNlUmVzdWx0XG5cbiAgY29uc3QgcmVuZGVyZWRNZXNzYWdlID1cbiAgICB0b29sLnJlbmRlclRvb2xSZXN1bHRNZXNzYWdlPy4oXG4gICAgICB0b29sUmVzdWx0IGFzIG5ldmVyLFxuICAgICAgZmlsdGVyVG9vbFByb2dyZXNzTWVzc2FnZXMocHJvZ3Jlc3NNZXNzYWdlc0Zvck1lc3NhZ2UpLFxuICAgICAge1xuICAgICAgICBzdHlsZSxcbiAgICAgICAgdGhlbWUsXG4gICAgICAgIHRvb2xzLFxuICAgICAgICB2ZXJib3NlLFxuICAgICAgICBpc1RyYW5zY3JpcHRNb2RlLFxuICAgICAgICBpc0JyaWVmT25seSxcbiAgICAgICAgaW5wdXQ6IGxvb2t1cHMudG9vbFVzZUJ5VG9vbFVzZUlELmdldCh0b29sVXNlSUQpPy5pbnB1dCxcbiAgICAgIH0sXG4gICAgKSA/PyBudWxsXG5cbiAgLy8gRG9uJ3QgcmVuZGVyIGFueXRoaW5nIGlmIHRoZSB0b29sIHJlc3VsdCBtZXNzYWdlIGlzIG51bGxcbiAgaWYgKHJlbmRlcmVkTWVzc2FnZSA9PT0gbnVsbCkge1xuICAgIHJldHVybiBudWxsXG4gIH1cblxuICAvLyBUb29scyB0aGF0IHJldHVybiAnJyBmcm9tIHVzZXJGYWNpbmdOYW1lIG9wdCBvdXQgb2YgdG9vbCBjaHJvbWUgYW5kXG4gIC8vIHJlbmRlciBsaWtlIHBsYWluIGFzc2lzdGFudCB0ZXh0LiBTa2lwIHRoZSB0b29sLXJlc3VsdCB3aWR0aCBjb25zdHJhaW50XG4gIC8vIHNvIE1hcmtkb3duVGFibGUncyBTQUZFVFlfTUFSR0lOPTQgKHR1bmVkIGZvciB0aGUgYXNzaXN0YW50LXRleHQgMi1jb2xcbiAgLy8gZG90IGd1dHRlcikgaG9sZHMg4oCUIG90aGVyd2lzZSB0YWJsZXMgd3JhcCB0aGVpciBib3gtZHJhd2luZyBjaGFycy5cbiAgY29uc3QgcmVuZGVyc0FzQXNzaXN0YW50VGV4dCA9IHRvb2wudXNlckZhY2luZ05hbWUodW5kZWZpbmVkKSA9PT0gJydcblxuICByZXR1cm4gKFxuICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHVtblwiPlxuICAgICAgPEJveFxuICAgICAgICBmbGV4RGlyZWN0aW9uPVwiY29sdW1uXCJcbiAgICAgICAgd2lkdGg9e3JlbmRlcnNBc0Fzc2lzdGFudFRleHQgPyB1bmRlZmluZWQgOiB3aWR0aH1cbiAgICAgID5cbiAgICAgICAge3JlbmRlcmVkTWVzc2FnZX1cbiAgICAgICAge2ZlYXR1cmUoJ0JBU0hfQ0xBU1NJRklFUicpXG4gICAgICAgICAgPyBjbGFzc2lmaWVyUnVsZSAmJiAoXG4gICAgICAgICAgICAgIDxNZXNzYWdlUmVzcG9uc2UgaGVpZ2h0PXsxfT5cbiAgICAgICAgICAgICAgICA8VGV4dCBkaW1Db2xvcj5cbiAgICAgICAgICAgICAgICAgIDxUZXh0IGNvbG9yPVwic3VjY2Vzc1wiPntmaWd1cmVzLnRpY2t9PC9UZXh0PlxuICAgICAgICAgICAgICAgICAgeycgQXV0by1hcHByb3ZlZCBcXHUwMGI3IG1hdGNoZWQgJ31cbiAgICAgICAgICAgICAgICAgIHtgXCIke2NsYXNzaWZpZXJSdWxlfVwiYH1cbiAgICAgICAgICAgICAgICA8L1RleHQ+XG4gICAgICAgICAgICAgIDwvTWVzc2FnZVJlc3BvbnNlPlxuICAgICAgICAgICAgKVxuICAgICAgICAgIDogbnVsbH1cbiAgICAgICAge2ZlYXR1cmUoJ1RSQU5TQ1JJUFRfQ0xBU1NJRklFUicpXG4gICAgICAgICAgPyB5b2xvUmVhc29uICYmIChcbiAgICAgICAgICAgICAgPE1lc3NhZ2VSZXNwb25zZSBoZWlnaHQ9ezF9PlxuICAgICAgICAgICAgICAgIDxUZXh0IGRpbUNvbG9yPkFsbG93ZWQgYnkgYXV0byBtb2RlIGNsYXNzaWZpZXI8L1RleHQ+XG4gICAgICAgICAgICAgIDwvTWVzc2FnZVJlc3BvbnNlPlxuICAgICAgICAgICAgKVxuICAgICAgICAgIDogbnVsbH1cbiAgICAgIDwvQm94PlxuICAgICAgPFNlbnRyeUVycm9yQm91bmRhcnk+XG4gICAgICAgIDxIb29rUHJvZ3Jlc3NNZXNzYWdlXG4gICAgICAgICAgaG9va0V2ZW50PVwiUG9zdFRvb2xVc2VcIlxuICAgICAgICAgIGxvb2t1cHM9e2xvb2t1cHN9XG4gICAgICAgICAgdG9vbFVzZUlEPXt0b29sVXNlSUR9XG4gICAgICAgICAgdmVyYm9zZT17dmVyYm9zZX1cbiAgICAgICAgICBpc1RyYW5zY3JpcHRNb2RlPXtpc1RyYW5zY3JpcHRNb2RlfVxuICAgICAgICAvPlxuICAgICAgPC9TZW50cnlFcnJvckJvdW5kYXJ5PlxuICAgIDwvQm94PlxuICApXG59XG4iXSwibWFwcGluZ3MiOiJBQUFBLFNBQVNBLE9BQU8sUUFBUSxZQUFZO0FBQ3BDLE9BQU9DLE9BQU8sTUFBTSxTQUFTO0FBQzdCLE9BQU8sS0FBS0MsS0FBSyxNQUFNLE9BQU87QUFDOUIsU0FBU0MsbUJBQW1CLFFBQVEsdUNBQXVDO0FBQzNFLFNBQVNDLEdBQUcsRUFBRUMsSUFBSSxFQUFFQyxRQUFRLFFBQVEsaUJBQWlCO0FBQ3JELFNBQVNDLFdBQVcsUUFBUSw0QkFBNEI7QUFDeEQsU0FDRUMsMEJBQTBCLEVBQzFCLEtBQUtDLElBQUksRUFDVCxLQUFLQyxLQUFLLFFBQ0wsa0JBQWtCO0FBQ3pCLGNBQ0VDLHFCQUFxQixFQUNyQkMsZUFBZSxRQUNWLDJCQUEyQjtBQUNsQyxTQUNFQyx3QkFBd0IsRUFDeEJDLHFCQUFxQixFQUNyQkMseUJBQXlCLFFBQ3BCLHVDQUF1QztBQUM5QyxjQUFjQyxtQkFBbUIsUUFBUSw0QkFBNEI7QUFDckUsU0FBU0MsZUFBZSxRQUFRLDBCQUEwQjtBQUMxRCxTQUFTQyxtQkFBbUIsUUFBUSwyQkFBMkI7QUFFL0QsS0FBS0MsS0FBSyxHQUFHO0VBQ1hDLE9BQU8sRUFBRVQscUJBQXFCO0VBQzlCVSxPQUFPLEVBQUVDLFVBQVUsQ0FBQyxPQUFPTixt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