/ components / permissions / BashPermissionRequest / bashToolUseOptions.tsx
bashToolUseOptions.tsx
  1  import { BASH_TOOL_NAME } from '../../../tools/BashTool/toolName.js';
  2  import { extractOutputRedirections } from '../../../utils/bash/commands.js';
  3  import { isClassifierPermissionsEnabled } from '../../../utils/permissions/bashClassifier.js';
  4  import type { PermissionDecisionReason } from '../../../utils/permissions/PermissionResult.js';
  5  import type { PermissionUpdate } from '../../../utils/permissions/PermissionUpdateSchema.js';
  6  import { shouldShowAlwaysAllowOptions } from '../../../utils/permissions/permissionsLoader.js';
  7  import type { OptionWithDescription } from '../../CustomSelect/select.js';
  8  import { generateShellSuggestionsLabel } from '../shellPermissionHelpers.js';
  9  export type BashToolUseOption = 'yes' | 'yes-apply-suggestions' | 'yes-prefix-edited' | 'yes-classifier-reviewed' | 'no';
 10  
 11  /**
 12   * Check if a description already exists in the allow list.
 13   * Compares lowercase and trailing-whitespace-trimmed versions.
 14   */
 15  function descriptionAlreadyExists(description: string, existingDescriptions: string[]): boolean {
 16    const normalized = description.toLowerCase().trimEnd();
 17    return existingDescriptions.some(existing => existing.toLowerCase().trimEnd() === normalized);
 18  }
 19  
 20  /**
 21   * Strip output redirections so filenames don't show as commands in the label.
 22   */
 23  function stripBashRedirections(command: string): string {
 24    const {
 25      commandWithoutRedirections,
 26      redirections
 27    } = extractOutputRedirections(command);
 28    // Only use stripped version if there were actual redirections
 29    return redirections.length > 0 ? commandWithoutRedirections : command;
 30  }
 31  export function bashToolUseOptions({
 32    suggestions = [],
 33    decisionReason,
 34    onRejectFeedbackChange,
 35    onAcceptFeedbackChange,
 36    onClassifierDescriptionChange,
 37    classifierDescription,
 38    initialClassifierDescriptionEmpty = false,
 39    existingAllowDescriptions = [],
 40    yesInputMode = false,
 41    noInputMode = false,
 42    editablePrefix,
 43    onEditablePrefixChange
 44  }: {
 45    suggestions?: PermissionUpdate[];
 46    decisionReason?: PermissionDecisionReason;
 47    onRejectFeedbackChange: (value: string) => void;
 48    onAcceptFeedbackChange: (value: string) => void;
 49    onClassifierDescriptionChange?: (value: string) => void;
 50    classifierDescription?: string;
 51    /** Whether the initial classifier description was empty. When true, hides the option. */
 52    initialClassifierDescriptionEmpty?: boolean;
 53    existingAllowDescriptions?: string[];
 54    yesInputMode?: boolean;
 55    noInputMode?: boolean;
 56    /** Editable prefix rule content (e.g., "npm run:*"). When set, replaces Haiku-based suggestions. */
 57    editablePrefix?: string;
 58    /** Callback when the user edits the prefix value. */
 59    onEditablePrefixChange?: (value: string) => void;
 60  }): OptionWithDescription<BashToolUseOption>[] {
 61    const options: OptionWithDescription<BashToolUseOption>[] = [];
 62    if (yesInputMode) {
 63      options.push({
 64        type: 'input',
 65        label: 'Yes',
 66        value: 'yes',
 67        placeholder: 'and tell Claude what to do next',
 68        onChange: onAcceptFeedbackChange,
 69        allowEmptySubmitToCancel: true
 70      });
 71    } else {
 72      options.push({
 73        label: 'Yes',
 74        value: 'yes'
 75      });
 76    }
 77  
 78    // Only show "always allow" options when not restricted by allowManagedPermissionRulesOnly
 79    if (shouldShowAlwaysAllowOptions()) {
 80      // Show an editable input for the prefix rule instead of the
 81      // Haiku-generated suggestion label — but only when the suggestions
 82      // don't contain non-Bash items (addDirectories, Read rules) that
 83      // the editable prefix can't represent.
 84      const hasNonBashSuggestions = suggestions.some(s => s.type === 'addDirectories' || s.type === 'addRules' && s.rules?.some(r => r.toolName !== BASH_TOOL_NAME));
 85      if (editablePrefix !== undefined && onEditablePrefixChange && !hasNonBashSuggestions && suggestions.length > 0) {
 86        options.push({
 87          type: 'input',
 88          label: 'Yes, and don\u2019t ask again for',
 89          value: 'yes-prefix-edited',
 90          placeholder: 'command prefix (e.g., npm run:*)',
 91          initialValue: editablePrefix,
 92          onChange: onEditablePrefixChange,
 93          allowEmptySubmitToCancel: true,
 94          showLabelWithValue: true,
 95          labelValueSeparator: ': ',
 96          resetCursorOnUpdate: true
 97        });
 98      } else if (suggestions.length > 0) {
 99        const label = generateShellSuggestionsLabel(suggestions, BASH_TOOL_NAME, stripBashRedirections);
100        if (label) {
101          options.push({
102            label,
103            value: 'yes-apply-suggestions'
104          });
105        }
106      }
107  
108      // Add classifier-reviewed option if enabled, the initial description was
109      // non-empty, the description doesn't already exist in the allow list,
110      // and the decision reason is NOT a server-side classifier block
111      // (prompt-based rules don't help when the server-side classifier triggers first).
112      // Skip when the editable prefix option is already shown — they serve the
113      // same role and having two identical-looking "don't ask again" inputs is confusing.
114      const editablePrefixShown = options.some(o => o.value === 'yes-prefix-edited');
115      if ("external" === 'ant' && !editablePrefixShown && isClassifierPermissionsEnabled() && onClassifierDescriptionChange && !initialClassifierDescriptionEmpty && !descriptionAlreadyExists(classifierDescription ?? '', existingAllowDescriptions) && decisionReason?.type !== 'classifier') {
116        options.push({
117          type: 'input',
118          label: 'Yes, and don\u2019t ask again for',
119          value: 'yes-classifier-reviewed',
120          placeholder: 'describe what to allow...',
121          initialValue: classifierDescription ?? '',
122          onChange: onClassifierDescriptionChange,
123          allowEmptySubmitToCancel: true,
124          showLabelWithValue: true,
125          labelValueSeparator: ': ',
126          resetCursorOnUpdate: true
127        });
128      }
129    }
130    if (noInputMode) {
131      options.push({
132        type: 'input',
133        label: 'No',
134        value: 'no',
135        placeholder: 'and tell Claude what to do differently',
136        onChange: onRejectFeedbackChange,
137        allowEmptySubmitToCancel: true
138      });
139    } else {
140      options.push({
141        label: 'No',
142        value: 'no'
143      });
144    }
145    return options;
146  }
147  //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJCQVNIX1RPT0xfTkFNRSIsImV4dHJhY3RPdXRwdXRSZWRpcmVjdGlvbnMiLCJpc0NsYXNzaWZpZXJQZXJtaXNzaW9uc0VuYWJsZWQiLCJQZXJtaXNzaW9uRGVjaXNpb25SZWFzb24iLCJQZXJtaXNzaW9uVXBkYXRlIiwic2hvdWxkU2hvd0Fsd2F5c0FsbG93T3B0aW9ucyIsIk9wdGlvbldpdGhEZXNjcmlwdGlvbiIsImdlbmVyYXRlU2hlbGxTdWdnZXN0aW9uc0xhYmVsIiwiQmFzaFRvb2xVc2VPcHRpb24iLCJkZXNjcmlwdGlvbkFscmVhZHlFeGlzdHMiLCJkZXNjcmlwdGlvbiIsImV4aXN0aW5nRGVzY3JpcHRpb25zIiwibm9ybWFsaXplZCIsInRvTG93ZXJDYXNlIiwidHJpbUVuZCIsInNvbWUiLCJleGlzdGluZyIsInN0cmlwQmFzaFJlZGlyZWN0aW9ucyIsImNvbW1hbmQiLCJjb21tYW5kV2l0aG91dFJlZGlyZWN0aW9ucyIsInJlZGlyZWN0aW9ucyIsImxlbmd0aCIsImJhc2hUb29sVXNlT3B0aW9ucyIsInN1Z2dlc3Rpb25zIiwiZGVjaXNpb25SZWFzb24iLCJvblJlamVjdEZlZWRiYWNrQ2hhbmdlIiwib25BY2NlcHRGZWVkYmFja0NoYW5nZSIsIm9uQ2xhc3NpZmllckRlc2NyaXB0aW9uQ2hhbmdlIiwiY2xhc3NpZmllckRlc2NyaXB0aW9uIiwiaW5pdGlhbENsYXNzaWZpZXJEZXNjcmlwdGlvbkVtcHR5IiwiZXhpc3RpbmdBbGxvd0Rlc2NyaXB0aW9ucyIsInllc0lucHV0TW9kZSIsIm5vSW5wdXRNb2RlIiwiZWRpdGFibGVQcmVmaXgiLCJvbkVkaXRhYmxlUHJlZml4Q2hhbmdlIiwidmFsdWUiLCJvcHRpb25zIiwicHVzaCIsInR5cGUiLCJsYWJlbCIsInBsYWNlaG9sZGVyIiwib25DaGFuZ2UiLCJhbGxvd0VtcHR5U3VibWl0VG9DYW5jZWwiLCJoYXNOb25CYXNoU3VnZ2VzdGlvbnMiLCJzIiwicnVsZXMiLCJyIiwidG9vbE5hbWUiLCJ1bmRlZmluZWQiLCJpbml0aWFsVmFsdWUiLCJzaG93TGFiZWxXaXRoVmFsdWUiLCJsYWJlbFZhbHVlU2VwYXJhdG9yIiwicmVzZXRDdXJzb3JPblVwZGF0ZSIsImVkaXRhYmxlUHJlZml4U2hvd24iLCJvIl0sInNvdXJjZXMiOlsiYmFzaFRvb2xVc2VPcHRpb25zLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBCQVNIX1RPT0xfTkFNRSB9IGZyb20gJy4uLy4uLy4uL3Rvb2xzL0Jhc2hUb29sL3Rvb2xOYW1lLmpzJ1xuaW1wb3J0IHsgZXh0cmFjdE91dHB1dFJlZGlyZWN0aW9ucyB9IGZyb20gJy4uLy4uLy4uL3V0aWxzL2Jhc2gvY29tbWFuZHMuanMnXG5pbXBvcnQgeyBpc0NsYXNzaWZpZXJQZXJtaXNzaW9uc0VuYWJsZWQgfSBmcm9tICcuLi8uLi8uLi91dGlscy9wZXJtaXNzaW9ucy9iYXNoQ2xhc3NpZmllci5qcydcbmltcG9ydCB0eXBlIHsgUGVybWlzc2lvbkRlY2lzaW9uUmVhc29uIH0gZnJvbSAnLi4vLi4vLi4vdXRpbHMvcGVybWlzc2lvbnMvUGVybWlzc2lvblJlc3VsdC5qcydcbmltcG9ydCB0eXBlIHsgUGVybWlzc2lvblVwZGF0ZSB9IGZyb20gJy4uLy4uLy4uL3V0aWxzL3Blcm1pc3Npb25zL1Blcm1pc3Npb25VcGRhdGVTY2hlbWEuanMnXG5pbXBvcnQgeyBzaG91bGRTaG93QWx3YXlzQWxsb3dPcHRpb25zIH0gZnJvbSAnLi4vLi4vLi4vdXRpbHMvcGVybWlzc2lvbnMvcGVybWlzc2lvbnNMb2FkZXIuanMnXG5pbXBvcnQgdHlwZSB7IE9wdGlvbldpdGhEZXNjcmlwdGlvbiB9IGZyb20gJy4uLy4uL0N1c3RvbVNlbGVjdC9zZWxlY3QuanMnXG5pbXBvcnQgeyBnZW5lcmF0ZVNoZWxsU3VnZ2VzdGlvbnNMYWJlbCB9IGZyb20gJy4uL3NoZWxsUGVybWlzc2lvbkhlbHBlcnMuanMnXG5cbmV4cG9ydCB0eXBlIEJhc2hUb29sVXNlT3B0aW9uID1cbiAgfCAneWVzJ1xuICB8ICd5ZXMtYXBwbHktc3VnZ2VzdGlvbnMnXG4gIHwgJ3llcy1wcmVmaXgtZWRpdGVkJ1xuICB8ICd5ZXMtY2xhc3NpZmllci1yZXZpZXdlZCdcbiAgfCAnbm8nXG5cbi8qKlxuICogQ2hlY2sgaWYgYSBkZXNjcmlwdGlvbiBhbHJlYWR5IGV4aXN0cyBpbiB0aGUgYWxsb3cgbGlzdC5cbiAqIENvbXBhcmVzIGxvd2VyY2FzZSBhbmQgdHJhaWxpbmctd2hpdGVzcGFjZS10cmltbWVkIHZlcnNpb25zLlxuICovXG5mdW5jdGlvbiBkZXNjcmlwdGlvbkFscmVhZHlFeGlzdHMoXG4gIGRlc2NyaXB0aW9uOiBzdHJpbmcsXG4gIGV4aXN0aW5nRGVzY3JpcHRpb25zOiBzdHJpbmdbXSxcbik6IGJvb2xlYW4ge1xuICBjb25zdCBub3JtYWxpemVkID0gZGVzY3JpcHRpb24udG9Mb3dlckNhc2UoKS50cmltRW5kKClcbiAgcmV0dXJuIGV4aXN0aW5nRGVzY3JpcHRpb25zLnNvbWUoXG4gICAgZXhpc3RpbmcgPT4gZXhpc3RpbmcudG9Mb3dlckNhc2UoKS50cmltRW5kKCkgPT09IG5vcm1hbGl6ZWQsXG4gIClcbn1cblxuLyoqXG4gKiBTdHJpcCBvdXRwdXQgcmVkaXJlY3Rpb25zIHNvIGZpbGVuYW1lcyBkb24ndCBzaG93IGFzIGNvbW1hbmRzIGluIHRoZSBsYWJlbC5cbiAqL1xuZnVuY3Rpb24gc3RyaXBCYXNoUmVkaXJlY3Rpb25zKGNvbW1hbmQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHsgY29tbWFuZFdpdGhvdXRSZWRpcmVjdGlvbnMsIHJlZGlyZWN0aW9ucyB9ID1cbiAgICBleHRyYWN0T3V0cHV0UmVkaXJlY3Rpb25zKGNvbW1hbmQpXG4gIC8vIE9ubHkgdXNlIHN0cmlwcGVkIHZlcnNpb24gaWYgdGhlcmUgd2VyZSBhY3R1YWwgcmVkaXJlY3Rpb25zXG4gIHJldHVybiByZWRpcmVjdGlvbnMubGVuZ3RoID4gMCA/IGNvbW1hbmRXaXRob3V0UmVkaXJlY3Rpb25zIDogY29tbWFuZFxufVxuXG5leHBvcnQgZnVuY3Rpb24gYmFzaFRvb2xVc2VPcHRpb25zKHtcbiAgc3VnZ2VzdGlvbnMgPSBbXSxcbiAgZGVjaXNpb25SZWFzb24sXG4gIG9uUmVqZWN0RmVlZGJhY2tDaGFuZ2UsXG4gIG9uQWNjZXB0RmVlZGJhY2tDaGFuZ2UsXG4gIG9uQ2xhc3NpZmllckRlc2NyaXB0aW9uQ2hhbmdlLFxuICBjbGFzc2lmaWVyRGVzY3JpcHRpb24sXG4gIGluaXRpYWxDbGFzc2lmaWVyRGVzY3JpcHRpb25FbXB0eSA9IGZhbHNlLFxuICBleGlzdGluZ0FsbG93RGVzY3JpcHRpb25zID0gW10sXG4gIHllc0lucHV0TW9kZSA9IGZhbHNlLFxuICBub0lucHV0TW9kZSA9IGZhbHNlLFxuICBlZGl0YWJsZVByZWZpeCxcbiAgb25FZGl0YWJsZVByZWZpeENoYW5nZSxcbn06IHtcbiAgc3VnZ2VzdGlvbnM/OiBQZXJtaXNzaW9uVXBkYXRlW11cbiAgZGVjaXNpb25SZWFzb24/OiBQZXJtaXNzaW9uRGVjaXNpb25SZWFzb25cbiAgb25SZWplY3RGZWVkYmFja0NoYW5nZTogKHZhbHVlOiBzdHJpbmcpID0+IHZvaWRcbiAgb25BY2NlcHRGZWVkYmFja0NoYW5nZTogKHZhbHVlOiBzdHJpbmcpID0+IHZvaWRcbiAgb25DbGFzc2lmaWVyRGVzY3JpcHRpb25DaGFuZ2U/OiAodmFsdWU6IHN0cmluZykgPT4gdm9pZFxuICBjbGFzc2lmaWVyRGVzY3JpcHRpb24/OiBzdHJpbmdcbiAgLyoqIFdoZXRoZXIgdGhlIGluaXRpYWwgY2xhc3NpZmllciBkZXNjcmlwdGlvbiB3YXMgZW1wdHkuIFdoZW4gdHJ1ZSwgaGlkZXMgdGhlIG9wdGlvbi4gKi9cbiAgaW5pdGlhbENsYXNzaWZpZXJEZXNjcmlwdGlvbkVtcHR5PzogYm9vbGVhblxuICBleGlzdGluZ0FsbG93RGVzY3JpcHRpb25zPzogc3RyaW5nW11cbiAgeWVzSW5wdXRNb2RlPzogYm9vbGVhblxuICBub0lucHV0TW9kZT86IGJvb2xlYW5cbiAgLyoqIEVkaXRhYmxlIHByZWZpeCBydWxlIGNvbnRlbnQgKGUuZy4sIFwibnBtIHJ1bjoqXCIpLiBXaGVuIHNldCwgcmVwbGFjZXMgSGFpa3UtYmFzZWQgc3VnZ2VzdGlvbnMuICovXG4gIGVkaXRhYmxlUHJlZml4Pzogc3RyaW5nXG4gIC8qKiBDYWxsYmFjayB3aGVuIHRoZSB1c2VyIGVkaXRzIHRoZSBwcmVmaXggdmFsdWUuICovXG4gIG9uRWRpdGFibGVQcmVmaXhDaGFuZ2U/OiAodmFsdWU6IHN0cmluZykgPT4gdm9pZFxufSk6IE9wdGlvbldpdGhEZXNjcmlwdGlvbjxCYXNoVG9vbFVzZU9wdGlvbj5bXSB7XG4gIGNvbnN0IG9wdGlvbnM6IE9wdGlvbldpdGhEZXNjcmlwdGlvbjxCYXNoVG9vbFVzZU9wdGlvbj5bXSA9IFtdXG5cbiAgaWYgKHllc0lucHV0TW9kZSkge1xuICAgIG9wdGlvbnMucHVzaCh7XG4gICAgICB0eXBlOiAnaW5wdXQnLFxuICAgICAgbGFiZWw6ICdZZXMnLFxuICAgICAgdmFsdWU6ICd5ZXMnLFxuICAgICAgcGxhY2Vob2xkZXI6ICdhbmQgdGVsbCBDbGF1ZGUgd2hhdCB0byBkbyBuZXh0JyxcbiAgICAgIG9uQ2hhbmdlOiBvbkFjY2VwdEZlZWRiYWNrQ2hhbmdlLFxuICAgICAgYWxsb3dFbXB0eVN1Ym1pdFRvQ2FuY2VsOiB0cnVlLFxuICAgIH0pXG4gIH0gZWxzZSB7XG4gICAgb3B0aW9ucy5wdXNoKHtcbiAgICAgIGxhYmVsOiAnWWVzJyxcbiAgICAgIHZhbHVlOiAneWVzJyxcbiAgICB9KVxuICB9XG5cbiAgLy8gT25seSBzaG93IFwiYWx3YXlzIGFsbG93XCIgb3B0aW9ucyB3aGVuIG5vdCByZXN0cmljdGVkIGJ5IGFsbG93TWFuYWdlZFBlcm1pc3Npb25SdWxlc09ubHlcbiAgaWYgKHNob3VsZFNob3dBbHdheXNBbGxvd09wdGlvbnMoKSkge1xuICAgIC8vIFNob3cgYW4gZWRpdGFibGUgaW5wdXQgZm9yIHRoZSBwcmVmaXggcnVsZSBpbnN0ZWFkIG9mIHRoZVxuICAgIC8vIEhhaWt1LWdlbmVyYXRlZCBzdWdnZXN0aW9uIGxhYmVsIOKAlCBidXQgb25seSB3aGVuIHRoZSBzdWdnZXN0aW9uc1xuICAgIC8vIGRvbid0IGNvbnRhaW4gbm9uLUJhc2ggaXRlbXMgKGFkZERpcmVjdG9yaWVzLCBSZWFkIHJ1bGVzKSB0aGF0XG4gICAgLy8gdGhlIGVkaXRhYmxlIHByZWZpeCBjYW4ndCByZXByZXNlbnQuXG4gICAgY29uc3QgaGFzTm9uQmFzaFN1Z2dlc3Rpb25zID0gc3VnZ2VzdGlvbnMuc29tZShcbiAgICAgIHMgPT5cbiAgICAgICAgcy50eXBlID09PSAnYWRkRGlyZWN0b3JpZXMnIHx8XG4gICAgICAgIChzLnR5cGUgPT09ICdhZGRSdWxlcycgJiZcbiAgICAgICAgICBzLnJ1bGVzPy5zb21lKHIgPT4gci50b29sTmFtZSAhPT0gQkFTSF9UT09MX05BTUUpKSxcbiAgICApXG4gICAgaWYgKFxuICAgICAgZWRpdGFibGVQcmVmaXggIT09IHVuZGVmaW5lZCAmJlxuICAgICAgb25FZGl0YWJsZVByZWZpeENoYW5nZSAmJlxuICAgICAgIWhhc05vbkJhc2hTdWdnZXN0aW9ucyAmJlxuICAgICAgc3VnZ2VzdGlvbnMubGVuZ3RoID4gMFxuICAgICkge1xuICAgICAgb3B0aW9ucy5wdXNoKHtcbiAgICAgICAgdHlwZTogJ2lucHV0JyxcbiAgICAgICAgbGFiZWw6ICdZZXMsIGFuZCBkb25cXHUyMDE5dCBhc2sgYWdhaW4gZm9yJyxcbiAgICAgICAgdmFsdWU6ICd5ZXMtcHJlZml4LWVkaXRlZCcsXG4gICAgICAgIHBsYWNlaG9sZGVyOiAnY29tbWFuZCBwcmVmaXggKGUuZy4sIG5wbSBydW46KiknLFxuICAgICAgICBpbml0aWFsVmFsdWU6IGVkaXRhYmxlUHJlZml4LFxuICAgICAgICBvbkNoYW5nZTogb25FZGl0YWJsZVByZWZpeENoYW5nZSxcbiAgICAgICAgYWxsb3dFbXB0eVN1Ym1pdFRvQ2FuY2VsOiB0cnVlLFxuICAgICAgICBzaG93TGFiZWxXaXRoVmFsdWU6IHRydWUsXG4gICAgICAgIGxhYmVsVmFsdWVTZXBhcmF0b3I6ICc6ICcsXG4gICAgICAgIHJlc2V0Q3Vyc29yT25VcGRhdGU6IHRydWUsXG4gICAgICB9KVxuICAgIH0gZWxzZSBpZiAoc3VnZ2VzdGlvbnMubGVuZ3RoID4gMCkge1xuICAgICAgY29uc3QgbGFiZWwgPSBnZW5lcmF0ZVNoZWxsU3VnZ2VzdGlvbnNMYWJlbChcbiAgICAgICAgc3VnZ2VzdGlvbnMsXG4gICAgICAgIEJBU0hfVE9PTF9OQU1FLFxuICAgICAgICBzdHJpcEJhc2hSZWRpcmVjdGlvbnMsXG4gICAgICApXG5cbiAgICAgIGlmIChsYWJlbCkge1xuICAgICAgICBvcHRpb25zLnB1c2goe1xuICAgICAgICAgIGxhYmVsLFxuICAgICAgICAgIHZhbHVlOiAneWVzLWFwcGx5LXN1Z2dlc3Rpb25zJyxcbiAgICAgICAgfSlcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBBZGQgY2xhc3NpZmllci1yZXZpZXdlZCBvcHRpb24gaWYgZW5hYmxlZCwgdGhlIGluaXRpYWwgZGVzY3JpcHRpb24gd2FzXG4gICAgLy8gbm9uLWVtcHR5LCB0aGUgZGVzY3JpcHRpb24gZG9lc24ndCBhbHJlYWR5IGV4aXN0IGluIHRoZSBhbGxvdyBsaXN0LFxuICAgIC8vIGFuZCB0aGUgZGVjaXNpb24gcmVhc29uIGlzIE5PVCBhIHNlcnZlci1zaWRlIGNsYXNzaWZpZXIgYmxvY2tcbiAgICAvLyAocHJvbXB0LWJhc2VkIHJ1bGVzIGRvbid0IGhlbHAgd2hlbiB0aGUgc2VydmVyLXNpZGUgY2xhc3NpZmllciB0cmlnZ2VycyBmaXJzdCkuXG4gICAgLy8gU2tpcCB3aGVuIHRoZSBlZGl0YWJsZSBwcmVmaXggb3B0aW9uIGlzIGFscmVhZHkgc2hvd24g4oCUIHRoZXkgc2VydmUgdGhlXG4gICAgLy8gc2FtZSByb2xlIGFuZCBoYXZpbmcgdHdvIGlkZW50aWNhbC1sb29raW5nIFwiZG9uJ3QgYXNrIGFnYWluXCIgaW5wdXRzIGlzIGNvbmZ1c2luZy5cbiAgICBjb25zdCBlZGl0YWJsZVByZWZpeFNob3duID0gb3B0aW9ucy5zb21lKFxuICAgICAgbyA9PiBvLnZhbHVlID09PSAneWVzLXByZWZpeC1lZGl0ZWQnLFxuICAgIClcbiAgICBpZiAoXG4gICAgICBcImV4dGVybmFsXCIgPT09ICdhbnQnICYmXG4gICAgICAhZWRpdGFibGVQcmVmaXhTaG93biAmJlxuICAgICAgaXNDbGFzc2lmaWVyUGVybWlzc2lvbnNFbmFibGVkKCkgJiZcbiAgICAgIG9uQ2xhc3NpZmllckRlc2NyaXB0aW9uQ2hhbmdlICYmXG4gICAgICAhaW5pdGlhbENsYXNzaWZpZXJEZXNjcmlwdGlvbkVtcHR5ICYmXG4gICAgICAhZGVzY3JpcHRpb25BbHJlYWR5RXhpc3RzKFxuICAgICAgICBjbGFzc2lmaWVyRGVzY3JpcHRpb24gPz8gJycsXG4gICAgICAgIGV4aXN0aW5nQWxsb3dEZXNjcmlwdGlvbnMsXG4gICAgICApICYmXG4gICAgICBkZWNpc2lvblJlYXNvbj8udHlwZSAhPT0gJ2NsYXNzaWZpZXInXG4gICAgKSB7XG4gICAgICBvcHRpb25zLnB1c2goe1xuICAgICAgICB0eXBlOiAnaW5wdXQnLFxuICAgICAgICBsYWJlbDogJ1llcywgYW5kIGRvblxcdTIwMTl0IGFzayBhZ2FpbiBmb3InLFxuICAgICAgICB2YWx1ZTogJ3llcy1jbGFzc2lmaWVyLXJldmlld2VkJyxcbiAgICAgICAgcGxhY2Vob2xkZXI6ICdkZXNjcmliZSB3aGF0IHRvIGFsbG93Li4uJyxcbiAgICAgICAgaW5pdGlhbFZhbHVlOiBjbGFzc2lmaWVyRGVzY3JpcHRpb24gPz8gJycsXG4gICAgICAgIG9uQ2hhbmdlOiBvbkNsYXNzaWZpZXJEZXNjcmlwdGlvbkNoYW5nZSxcbiAgICAgICAgYWxsb3dFbXB0eVN1Ym1pdFRvQ2FuY2VsOiB0cnVlLFxuICAgICAgICBzaG93TGFiZWxXaXRoVmFsdWU6IHRydWUsXG4gICAgICAgIGxhYmVsVmFsdWVTZXBhcmF0b3I6ICc6ICcsXG4gICAgICAgIHJlc2V0Q3Vyc29yT25VcGRhdGU6IHRydWUsXG4gICAgICB9KVxuICAgIH1cbiAgfVxuXG4gIGlmIChub0lucHV0TW9kZSkge1xuICAgIG9wdGlvbnMucHVzaCh7XG4gICAgICB0eXBlOiAnaW5wdXQnLFxuICAgICAgbGFiZWw6ICdObycsXG4gICAgICB2YWx1ZTogJ25vJyxcbiAgICAgIHBsYWNlaG9sZGVyOiAnYW5kIHRlbGwgQ2xhdWRlIHdoYXQgdG8gZG8gZGlmZmVyZW50bHknLFxuICAgICAgb25DaGFuZ2U6IG9uUmVqZWN0RmVlZGJhY2tDaGFuZ2UsXG4gICAgICBhbGxvd0VtcHR5U3VibWl0VG9DYW5jZWw6IHRydWUsXG4gICAgfSlcbiAgfSBlbHNlIHtcbiAgICBvcHRpb25zLnB1c2goe1xuICAgICAgbGFiZWw6ICdObycsXG4gICAgICB2YWx1ZTogJ25vJyxcbiAgICB9KVxuICB9XG5cbiAgcmV0dXJuIG9wdGlvbnNcbn1cbiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsY0FBYyxRQUFRLHFDQUFxQztBQUNwRSxTQUFTQyx5QkFBeUIsUUFBUSxpQ0FBaUM7QUFDM0UsU0FBU0MsOEJBQThCLFFBQVEsOENBQThDO0FBQzdGLGNBQWNDLHdCQUF3QixRQUFRLGdEQUFnRDtBQUM5RixjQUFjQyxnQkFBZ0IsUUFBUSxzREFBc0Q7QUFDNUYsU0FBU0MsNEJBQTRCLFFBQVEsaURBQWlEO0FBQzlGLGNBQWNDLHFCQUFxQixRQUFRLDhCQUE4QjtBQUN6RSxTQUFTQyw2QkFBNkIsUUFBUSw4QkFBOEI7QUFFNUUsT0FBTyxLQUFLQyxpQkFBaUIsR0FDekIsS0FBSyxHQUNMLHVCQUF1QixHQUN2QixtQkFBbUIsR0FDbkIseUJBQXlCLEdBQ3pCLElBQUk7O0FBRVI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTQyx3QkFBd0JBLENBQy9CQyxXQUFXLEVBQUUsTUFBTSxFQUNuQkMsb0JBQW9CLEVBQUUsTUFBTSxFQUFFLENBQy9CLEVBQUUsT0FBTyxDQUFDO0VBQ1QsTUFBTUMsVUFBVSxHQUFHRixXQUFXLENBQUNHLFdBQVcsQ0FBQyxDQUFDLENBQUNDLE9BQU8sQ0FB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