/ tools / LSPTool / UI.tsx
UI.tsx
  1  import { c as _c } from "react/compiler-runtime";
  2  import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs';
  3  import React from 'react';
  4  import { CtrlOToExpand } from '../../components/CtrlOToExpand.js';
  5  import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js';
  6  import { MessageResponse } from '../../components/MessageResponse.js';
  7  import { Box, Text } from '../../ink.js';
  8  import { getDisplayPath } from '../../utils/file.js';
  9  import { extractTag } from '../../utils/messages.js';
 10  import type { Input, Output } from './LSPTool.js';
 11  import { getSymbolAtPosition } from './symbolContext.js';
 12  
 13  // Lookup map for operation-specific labels
 14  const OPERATION_LABELS: Record<Input['operation'], {
 15    singular: string;
 16    plural: string;
 17    special?: string;
 18  }> = {
 19    goToDefinition: {
 20      singular: 'definition',
 21      plural: 'definitions'
 22    },
 23    findReferences: {
 24      singular: 'reference',
 25      plural: 'references'
 26    },
 27    documentSymbol: {
 28      singular: 'symbol',
 29      plural: 'symbols'
 30    },
 31    workspaceSymbol: {
 32      singular: 'symbol',
 33      plural: 'symbols'
 34    },
 35    hover: {
 36      singular: 'hover info',
 37      plural: 'hover info',
 38      special: 'available'
 39    },
 40    goToImplementation: {
 41      singular: 'implementation',
 42      plural: 'implementations'
 43    },
 44    prepareCallHierarchy: {
 45      singular: 'call item',
 46      plural: 'call items'
 47    },
 48    incomingCalls: {
 49      singular: 'caller',
 50      plural: 'callers'
 51    },
 52    outgoingCalls: {
 53      singular: 'callee',
 54      plural: 'callees'
 55    }
 56  };
 57  
 58  /**
 59   * Reusable component for LSP result summaries with collapsed/expanded views
 60   */
 61  function LSPResultSummary(t0) {
 62    const $ = _c(24);
 63    const {
 64      operation,
 65      resultCount,
 66      fileCount,
 67      content,
 68      verbose
 69    } = t0;
 70    let t1;
 71    if ($[0] !== operation) {
 72      t1 = OPERATION_LABELS[operation] || {
 73        singular: "result",
 74        plural: "results"
 75      };
 76      $[0] = operation;
 77      $[1] = t1;
 78    } else {
 79      t1 = $[1];
 80    }
 81    const labelConfig = t1;
 82    const countLabel = resultCount === 1 ? labelConfig.singular : labelConfig.plural;
 83    let t2;
 84    if ($[2] !== countLabel || $[3] !== labelConfig.special || $[4] !== operation || $[5] !== resultCount) {
 85      t2 = operation === "hover" && resultCount > 0 && labelConfig.special ? <Text>Hover info {labelConfig.special}</Text> : <Text>Found <Text bold={true}>{resultCount} </Text>{countLabel}</Text>;
 86      $[2] = countLabel;
 87      $[3] = labelConfig.special;
 88      $[4] = operation;
 89      $[5] = resultCount;
 90      $[6] = t2;
 91    } else {
 92      t2 = $[6];
 93    }
 94    const primaryText = t2;
 95    let t3;
 96    if ($[7] !== fileCount) {
 97      t3 = fileCount > 1 ? <Text>{" "}across <Text bold={true}>{fileCount} </Text>files</Text> : null;
 98      $[7] = fileCount;
 99      $[8] = t3;
100    } else {
101      t3 = $[8];
102    }
103    const secondaryText = t3;
104    if (verbose) {
105      let t4;
106      if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
107        t4 = <Text dimColor={true}>  ⎿  </Text>;
108        $[9] = t4;
109      } else {
110        t4 = $[9];
111      }
112      let t5;
113      if ($[10] !== primaryText || $[11] !== secondaryText) {
114        t5 = <Box flexDirection="row"><Text>{t4}{primaryText}{secondaryText}</Text></Box>;
115        $[10] = primaryText;
116        $[11] = secondaryText;
117        $[12] = t5;
118      } else {
119        t5 = $[12];
120      }
121      let t6;
122      if ($[13] !== content) {
123        t6 = <Box marginLeft={5}><Text>{content}</Text></Box>;
124        $[13] = content;
125        $[14] = t6;
126      } else {
127        t6 = $[14];
128      }
129      let t7;
130      if ($[15] !== t5 || $[16] !== t6) {
131        t7 = <Box flexDirection="column">{t5}{t6}</Box>;
132        $[15] = t5;
133        $[16] = t6;
134        $[17] = t7;
135      } else {
136        t7 = $[17];
137      }
138      return t7;
139    }
140    let t4;
141    if ($[18] !== resultCount) {
142      t4 = resultCount > 0 && <CtrlOToExpand />;
143      $[18] = resultCount;
144      $[19] = t4;
145    } else {
146      t4 = $[19];
147    }
148    let t5;
149    if ($[20] !== primaryText || $[21] !== secondaryText || $[22] !== t4) {
150      t5 = <MessageResponse height={1}><Text>{primaryText}{secondaryText} {t4}</Text></MessageResponse>;
151      $[20] = primaryText;
152      $[21] = secondaryText;
153      $[22] = t4;
154      $[23] = t5;
155    } else {
156      t5 = $[23];
157    }
158    return t5;
159  }
160  export function userFacingName(): string {
161    return 'LSP';
162  }
163  export function renderToolUseMessage(input: Partial<Input>, {
164    verbose
165  }: {
166    verbose: boolean;
167  }): React.ReactNode {
168    if (!input.operation) {
169      return null;
170    }
171    const parts: string[] = [];
172  
173    // For position-based operations (goToDefinition, findReferences, hover, goToImplementation),
174    // show the symbol at the position for better context
175    if ((input.operation === 'goToDefinition' || input.operation === 'findReferences' || input.operation === 'hover' || input.operation === 'goToImplementation') && input.filePath && input.line !== undefined && input.character !== undefined) {
176      // Convert from 1-based (user input) to 0-based (internal file reading)
177      const symbol = getSymbolAtPosition(input.filePath, input.line - 1, input.character - 1);
178      const displayPath = verbose ? input.filePath : getDisplayPath(input.filePath);
179      if (symbol) {
180        parts.push(`operation: "${input.operation}"`);
181        parts.push(`symbol: "${symbol}"`);
182        parts.push(`in: "${displayPath}"`);
183      } else {
184        parts.push(`operation: "${input.operation}"`);
185        parts.push(`file: "${displayPath}"`);
186        parts.push(`position: ${input.line}:${input.character}`);
187      }
188      return parts.join(', ');
189    }
190  
191    // For other operations (documentSymbol, workspaceSymbol),
192    // show operation and file without position details
193    parts.push(`operation: "${input.operation}"`);
194    if (input.filePath) {
195      const displayPath = verbose ? input.filePath : getDisplayPath(input.filePath);
196      parts.push(`file: "${displayPath}"`);
197    }
198    return parts.join(', ');
199  }
200  export function renderToolUseErrorMessage(result: ToolResultBlockParam['content'], {
201    verbose
202  }: {
203    verbose: boolean;
204  }): React.ReactNode {
205    if (!verbose && typeof result === 'string' && extractTag(result, 'tool_use_error')) {
206      return <MessageResponse>
207          <Text color="error">LSP operation failed</Text>
208        </MessageResponse>;
209    }
210    return <FallbackToolUseErrorMessage result={result} verbose={verbose} />;
211  }
212  export function renderToolResultMessage(output: Output, _progressMessages: unknown[], {
213    verbose
214  }: {
215    verbose: boolean;
216  }): React.ReactNode {
217    // Use collapsed/expanded view if we have count information
218    if (output.resultCount !== undefined && output.fileCount !== undefined) {
219      return <LSPResultSummary operation={output.operation} resultCount={output.resultCount} fileCount={output.fileCount} content={output.result} verbose={verbose} />;
220    }
221  
222    // Fallback for error cases where counts aren't available
223    // (e.g., LSP server initialization failures, request errors)
224    return <MessageResponse>
225        <Text>{output.result}</Text>
226      </MessageResponse>;
227  }
228  //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJUb29sUmVzdWx0QmxvY2tQYXJhbSIsIlJlYWN0IiwiQ3RybE9Ub0V4cGFuZCIsIkZhbGxiYWNrVG9vbFVzZUVycm9yTWVzc2FnZSIsIk1lc3NhZ2VSZXNwb25zZSIsIkJveCIsIlRleHQiLCJnZXREaXNwbGF5UGF0aCIsImV4dHJhY3RUYWciLCJJbnB1dCIsIk91dHB1dCIsImdldFN5bWJvbEF0UG9zaXRpb24iLCJPUEVSQVRJT05fTEFCRUxTIiwiUmVjb3JkIiwic2luZ3VsYXIiLCJwbHVyYWwiLCJzcGVjaWFsIiwiZ29Ub0RlZmluaXRpb24iLCJmaW5kUmVmZXJlbmNlcyIsImRvY3VtZW50U3ltYm9sIiwid29ya3NwYWNlU3ltYm9sIiwiaG92ZXIiLCJnb1RvSW1wbGVtZW50YXRpb24iLCJwcmVwYXJlQ2FsbEhpZXJhcmNoeSIsImluY29taW5nQ2FsbHMiLCJvdXRnb2luZ0NhbGxzIiwiTFNQUmVzdWx0U3VtbWFyeSIsInQwIiwiJCIsIl9jIiwib3BlcmF0aW9uIiwicmVzdWx0Q291bnQiLCJmaWxlQ291bnQiLCJjb250ZW50IiwidmVyYm9zZSIsInQxIiwibGFiZWxDb25maWciLCJjb3VudExhYmVsIiwidDIiLCJwcmltYXJ5VGV4dCIsInQzIiwic2Vjb25kYXJ5VGV4dCIsInQ0IiwiU3ltYm9sIiwiZm9yIiwidDUiLCJ0NiIsInQ3IiwidXNlckZhY2luZ05hbWUiLCJyZW5kZXJUb29sVXNlTWVzc2FnZSIsImlucHV0IiwiUGFydGlhbCIsIlJlYWN0Tm9kZSIsInBhcnRzIiwiZmlsZVBhdGgiLCJsaW5lIiwidW5kZWZpbmVkIiwiY2hhcmFjdGVyIiwic3ltYm9sIiwiZGlzcGxheVBhdGgiLCJwdXNoIiwiam9pbiIsInJlbmRlclRvb2xVc2VFcnJvck1lc3NhZ2UiLCJyZXN1bHQiLCJyZW5kZXJUb29sUmVzdWx0TWVzc2FnZSIsIm91dHB1dCIsIl9wcm9ncmVzc01lc3NhZ2VzIl0sInNvdXJjZXMiOlsiVUkudHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgVG9vbFJlc3VsdEJsb2NrUGFyYW0gfSBmcm9tICdAYW50aHJvcGljLWFpL3Nkay9yZXNvdXJjZXMvaW5kZXgubWpzJ1xuaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgQ3RybE9Ub0V4cGFuZCB9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvQ3RybE9Ub0V4cGFuZC5qcydcbmltcG9ydCB7IEZhbGxiYWNrVG9vbFVzZUVycm9yTWVzc2FnZSB9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvRmFsbGJhY2tUb29sVXNlRXJyb3JNZXNzYWdlLmpzJ1xuaW1wb3J0IHsgTWVzc2FnZVJlc3BvbnNlIH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy9NZXNzYWdlUmVzcG9uc2UuanMnXG5pbXBvcnQgeyBCb3gsIFRleHQgfSBmcm9tICcuLi8uLi9pbmsuanMnXG5pbXBvcnQgeyBnZXREaXNwbGF5UGF0aCB9IGZyb20gJy4uLy4uL3V0aWxzL2ZpbGUuanMnXG5pbXBvcnQgeyBleHRyYWN0VGFnIH0gZnJvbSAnLi4vLi4vdXRpbHMvbWVzc2FnZXMuanMnXG5pbXBvcnQgdHlwZSB7IElucHV0LCBPdXRwdXQgfSBmcm9tICcuL0xTUFRvb2wuanMnXG5pbXBvcnQgeyBnZXRTeW1ib2xBdFBvc2l0aW9uIH0gZnJvbSAnLi9zeW1ib2xDb250ZXh0LmpzJ1xuXG4vLyBMb29rdXAgbWFwIGZvciBvcGVyYXRpb24tc3BlY2lmaWMgbGFiZWxzXG5jb25zdCBPUEVSQVRJT05fTEFCRUxTOiBSZWNvcmQ8XG4gIElucHV0WydvcGVyYXRpb24nXSxcbiAgeyBzaW5ndWxhcjogc3RyaW5nOyBwbHVyYWw6IHN0cmluZzsgc3BlY2lhbD86IHN0cmluZyB9XG4+ID0ge1xuICBnb1RvRGVmaW5pdGlvbjogeyBzaW5ndWxhcjogJ2RlZmluaXRpb24nLCBwbHVyYWw6ICdkZWZpbml0aW9ucycgfSxcbiAgZmluZFJlZmVyZW5jZXM6IHsgc2luZ3VsYXI6ICdyZWZlcmVuY2UnLCBwbHVyYWw6ICdyZWZlcmVuY2VzJyB9LFxuICBkb2N1bWVudFN5bWJvbDogeyBzaW5ndWxhcjogJ3N5bWJvbCcsIHBsdXJhbDogJ3N5bWJvbHMnIH0sXG4gIHdvcmtzcGFjZVN5bWJvbDogeyBzaW5ndWxhcjogJ3N5bWJvbCcsIHBsdXJhbDogJ3N5bWJvbHMnIH0sXG4gIGhvdmVyOiB7IHNpbmd1bGFyOiAnaG92ZXIgaW5mbycsIHBsdXJhbDogJ2hvdmVyIGluZm8nLCBzcGVjaWFsOiAnYXZhaWxhYmxlJyB9LFxuICBnb1RvSW1wbGVtZW50YXRpb246IHsgc2luZ3VsYXI6ICdpbXBsZW1lbnRhdGlvbicsIHBsdXJhbDogJ2ltcGxlbWVudGF0aW9ucycgfSxcbiAgcHJlcGFyZUNhbGxIaWVyYXJjaHk6IHsgc2luZ3VsYXI6ICdjYWxsIGl0ZW0nLCBwbHVyYWw6ICdjYWxsIGl0ZW1zJyB9LFxuICBpbmNvbWluZ0NhbGxzOiB7IHNpbmd1bGFyOiAnY2FsbGVyJywgcGx1cmFsOiAnY2FsbGVycycgfSxcbiAgb3V0Z29pbmdDYWxsczogeyBzaW5ndWxhcjogJ2NhbGxlZScsIHBsdXJhbDogJ2NhbGxlZXMnIH0sXG59XG5cbi8qKlxuICogUmV1c2FibGUgY29tcG9uZW50IGZvciBMU1AgcmVzdWx0IHN1bW1hcmllcyB3aXRoIGNvbGxhcHNlZC9leHBhbmRlZCB2aWV3c1xuICovXG5mdW5jdGlvbiBMU1BSZXN1bHRTdW1tYXJ5KHtcbiAgb3BlcmF0aW9uLFxuICByZXN1bHRDb3VudCxcbiAgZmlsZUNvdW50LFxuICBjb250ZW50LFxuICB2ZXJib3NlLFxufToge1xuICBvcGVyYXRpb246IElucHV0WydvcGVyYXRpb24nXVxuICByZXN1bHRDb3VudDogbnVtYmVyXG4gIGZpbGVDb3VudDogbnVtYmVyXG4gIGNvbnRlbnQ6IHN0cmluZ1xuICB2ZXJib3NlOiBib29sZWFuXG59KTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgLy8gR2V0IGxhYmVsIGNvbmZpZ3VyYXRpb24gZm9yIHRoaXMgb3BlcmF0aW9uXG4gIGNvbnN0IGxhYmVsQ29uZmlnID0gT1BFUkFUSU9OX0xBQkVMU1tvcGVyYXRpb25dIHx8IHtcbiAgICBzaW5ndWxhcjogJ3Jlc3VsdCcsXG4gICAgcGx1cmFsOiAncmVzdWx0cycsXG4gIH1cbiAgY29uc3QgY291bnRMYWJlbCA9XG4gICAgcmVzdWx0Q291bnQgPT09IDEgPyBsYWJlbENvbmZpZy5zaW5ndWxhciA6IGxhYmVsQ29uZmlnLnBsdXJhbFxuXG4gIGNvbnN0IHByaW1hcnlUZXh0ID1cbiAgICBvcGVyYXRpb24gPT09ICdob3ZlcicgJiYgcmVzdWx0Q291bnQgPiAwICYmIGxhYmVsQ29uZmlnLnNwZWNpYWwgPyAoXG4gICAgICA8VGV4dD5Ib3ZlciBpbmZvIHtsYWJlbENvbmZpZy5zcGVjaWFsfTwvVGV4dD5cbiAgICApIDogKFxuICAgICAgPFRleHQ+XG4gICAgICAgIEZvdW5kIDxUZXh0IGJvbGQ+e3Jlc3VsdENvdW50fSA8L1RleHQ+XG4gICAgICAgIHtjb3VudExhYmVsfVxuICAgICAgPC9UZXh0PlxuICAgIClcblxuICBjb25zdCBzZWNvbmRhcnlUZXh0ID1cbiAgICBmaWxlQ291bnQgPiAxID8gKFxuICAgICAgPFRleHQ+XG4gICAgICAgIHsnICd9XG4gICAgICAgIGFjcm9zcyA8VGV4dCBib2xkPntmaWxlQ291bnR9IDwvVGV4dD5cbiAgICAgICAgZmlsZXNcbiAgICAgIDwvVGV4dD5cbiAgICApIDogbnVsbFxuXG4gIGlmICh2ZXJib3NlKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxCb3ggZmxleERpcmVjdGlvbj1cImNvbHVtblwiPlxuICAgICAgICA8Qm94IGZsZXhEaXJlY3Rpb249XCJyb3dcIj5cbiAgICAgICAgICA8VGV4dD5cbiAgICAgICAgICAgIDxUZXh0IGRpbUNvbG9yPiZuYnNwOyZuYnNwO+KOvyAmbmJzcDs8L1RleHQ+XG4gICAgICAgICAgICB7cHJpbWFyeVRleHR9XG4gICAgICAgICAgICB7c2Vjb25kYXJ5VGV4dH1cbiAgICAgICAgICA8L1RleHQ+XG4gICAgICAgIDwvQm94PlxuICAgICAgICA8Qm94IG1hcmdpbkxlZnQ9ezV9PlxuICAgICAgICAgIDxUZXh0Pntjb250ZW50fTwvVGV4dD5cbiAgICAgICAgPC9Cb3g+XG4gICAgICA8L0JveD5cbiAgICApXG4gIH1cblxuICByZXR1cm4gKFxuICAgIDxNZXNzYWdlUmVzcG9uc2UgaGVpZ2h0PXsxfT5cbiAgICAgIDxUZXh0PlxuICAgICAgICB7cHJpbWFyeVRleHR9XG4gICAgICAgIHtzZWNvbmRhcnlUZXh0fSB7cmVzdWx0Q291bnQgPiAwICYmIDxDdHJsT1RvRXhwYW5kIC8+fVxuICAgICAgPC9UZXh0PlxuICAgIDwvTWVzc2FnZVJlc3BvbnNlPlxuICApXG59XG5cbmV4cG9ydCBmdW5jdGlvbiB1c2VyRmFjaW5nTmFtZSgpOiBzdHJpbmcge1xuICByZXR1cm4gJ0xTUCdcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlbmRlclRvb2xVc2VNZXNzYWdlKFxuICBpbnB1dDogUGFydGlhbDxJbnB1dD4sXG4gIHsgdmVyYm9zZSB9OiB7IHZlcmJvc2U6IGJvb2xlYW4gfSxcbik6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gIGlmICghaW5wdXQub3BlcmF0aW9uKSB7XG4gICAgcmV0dXJuIG51bGxcbiAgfVxuXG4gIGNvbnN0IHBhcnRzOiBzdHJpbmdbXSA9IFtdXG5cbiAgLy8gRm9yIHBvc2l0aW9uLWJhc2VkIG9wZXJhdGlvbnMgKGdvVG9EZWZpbml0aW9uLCBmaW5kUmVmZXJlbmNlcywgaG92ZXIsIGdvVG9JbXBsZW1lbnRhdGlvbiksXG4gIC8vIHNob3cgdGhlIHN5bWJvbCBhdCB0aGUgcG9zaXRpb24gZm9yIGJldHRlciBjb250ZXh0XG4gIGlmIChcbiAgICAoaW5wdXQub3BlcmF0aW9uID09PSAnZ29Ub0RlZmluaXRpb24nIHx8XG4gICAgICBpbnB1dC5vcGVyYXRpb24gPT09ICdmaW5kUmVmZXJlbmNlcycgfHxcbiAgICAgIGlucHV0Lm9wZXJhdGlvbiA9PT0gJ2hvdmVyJyB8fFxuICAgICAgaW5wdXQub3BlcmF0aW9uID09PSAnZ29Ub0ltcGxlbWVudGF0aW9uJykgJiZcbiAgICBpbnB1dC5maWxlUGF0aCAmJlxuICAgIGlucHV0LmxpbmUgIT09IHVuZGVmaW5lZCAmJlxuICAgIGlucHV0LmNoYXJhY3RlciAhPT0gdW5kZWZpbmVkXG4gICkge1xuICAgIC8vIENvbnZlcnQgZnJvbSAxLWJhc2VkICh1c2VyIGlucHV0KSB0byAwLWJhc2VkIChpbnRlcm5hbCBmaWxlIHJlYWRpbmcpXG4gICAgY29uc3Qgc3ltYm9sID0gZ2V0U3ltYm9sQXRQb3NpdGlvbihcbiAgICAgIGlucHV0LmZpbGVQYXRoLFxuICAgICAgaW5wdXQubGluZSAtIDEsXG4gICAgICBpbnB1dC5jaGFyYWN0ZXIgLSAxLFxuICAgIClcbiAgICBjb25zdCBkaXNwbGF5UGF0aCA9IHZlcmJvc2VcbiAgICAgID8gaW5wdXQuZmlsZVBhdGhcbiAgICAgIDogZ2V0RGlzcGxheVBhdGgoaW5wdXQuZmlsZVBhdGgpXG5cbiAgICBpZiAoc3ltYm9sKSB7XG4gICAgICBwYXJ0cy5wdXNoKGBvcGVyYXRpb246IFwiJHtpbnB1dC5vcGVyYXRpb259XCJgKVxuICAgICAgcGFydHMucHVzaChgc3ltYm9sOiBcIiR7c3ltYm9sfVwiYClcbiAgICAgIHBhcnRzLnB1c2goYGluOiBcIiR7ZGlzcGxheVBhdGh9XCJgKVxuICAgIH0gZWxzZSB7XG4gICAgICBwYXJ0cy5wdXNoKGBvcGVyYXRpb246IFwiJHtpbnB1dC5vcGVyYXRpb259XCJgKVxuICAgICAgcGFydHMucHVzaChgZmlsZTogXCIke2Rpc3BsYXlQYXRofVwiYClcbiAgICAgIHBhcnRzLnB1c2goYHBvc2l0aW9uOiAke2lucHV0LmxpbmV9OiR7aW5wdXQuY2hhcmFjdGVyfWApXG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcnRzLmpvaW4oJywgJylcbiAgfVxuXG4gIC8vIEZvciBvdGhlciBvcGVyYXRpb25zIChkb2N1bWVudFN5bWJvbCwgd29ya3NwYWNlU3ltYm9sKSxcbiAgLy8gc2hvdyBvcGVyYXRpb24gYW5kIGZpbGUgd2l0aG91dCBwb3NpdGlvbiBkZXRhaWxzXG4gIHBhcnRzLnB1c2goYG9wZXJhdGlvbjogXCIke2lucHV0Lm9wZXJhdGlvbn1cImApXG5cbiAgaWYgKGlucHV0LmZpbGVQYXRoKSB7XG4gICAgY29uc3QgZGlzcGxheVBhdGggPSB2ZXJib3NlXG4gICAgICA/IGlucHV0LmZpbGVQYXRoXG4gICAgICA6IGdldERpc3BsYXlQYXRoKGlucHV0LmZpbGVQYXRoKVxuICAgIHBhcnRzLnB1c2goYGZpbGU6IFwiJHtkaXNwbGF5UGF0aH1cImApXG4gIH1cblxuICByZXR1cm4gcGFydHMuam9pbignLCAnKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVuZGVyVG9vbFVzZUVycm9yTWVzc2FnZShcbiAgcmVzdWx0OiBUb29sUmVzdWx0QmxvY2tQYXJhbVsnY29udGVudCddLFxuICB7IHZlcmJvc2UgfTogeyB2ZXJib3NlOiBib29sZWFuIH0sXG4pOiBSZWFjdC5SZWFjdE5vZGUge1xuICBpZiAoXG4gICAgIXZlcmJvc2UgJiZcbiAgICB0eXBlb2YgcmVzdWx0ID09PSAnc3RyaW5nJyAmJlxuICAgIGV4dHJhY3RUYWcocmVzdWx0LCAndG9vbF91c2VfZXJyb3InKVxuICApIHtcbiAgICByZXR1cm4gKFxuICAgICAgPE1lc3NhZ2VSZXNwb25zZT5cbiAgICAgICAgPFRleHQgY29sb3I9XCJlcnJvclwiPkxTUCBvcGVyYXRpb24gZmFpbGVkPC9UZXh0PlxuICAgICAgPC9NZXNzYWdlUmVzcG9uc2U+XG4gICAgKVxuICB9XG4gIHJldHVybiA8RmFsbGJhY2tUb29sVXNlRXJyb3JNZXNzYWdlIHJlc3VsdD17cmVzdWx0fSB2ZXJib3NlPXt2ZXJib3NlfSAvPlxufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVuZGVyVG9vbFJlc3VsdE1lc3NhZ2UoXG4gIG91dHB1dDogT3V0cHV0LFxuICBfcHJvZ3Jlc3NNZXNzYWdlczogdW5rbm93bltdLFxuICB7IHZlcmJvc2UgfTogeyB2ZXJib3NlOiBib29sZWFuIH0sXG4pOiBSZWFjdC5SZWFjdE5vZGUge1xuICAvLyBVc2UgY29sbGFwc2VkL2V4cGFuZGVkIHZpZXcgaWYgd2UgaGF2ZSBjb3VudCBpbmZvcm1hdGlvblxuICBpZiAob3V0cHV0LnJlc3VsdENvdW50ICE9PSB1bmRlZmluZWQgJiYgb3V0cHV0LmZpbGVDb3VudCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxMU1BSZXN1bHRTdW1tYXJ5XG4gICAgICAgIG9wZXJhdGlvbj17b3V0cHV0Lm9wZXJhdGlvbn1cbiAgICAgICAgcmVzdWx0Q291bnQ9e291dHB1dC5yZXN1bHRDb3VudH1cbiAgICAgICAgZmlsZUNvdW50PXtvdXRwdXQuZmlsZUNvdW50fVxuICAgICAgICBjb250ZW50PXtvdXRwdXQucmVzdWx0fVxuICAgICAgICB2ZXJib3NlPXt2ZXJib3NlfVxuICAgICAgLz5cbiAgICApXG4gIH1cblxuICAvLyBGYWxsYmFjayBmb3IgZXJyb3IgY2FzZXMgd2hlcmUgY291bnRzIGFyZW4ndCBhdmFpbGFibGVcbiAgLy8gKGUuZy4sIExTUCBzZXJ2ZXIgaW5pdGlhbGl6YXRpb24gZmFpbHVyZXMsIHJlcXVlc3QgZXJyb3JzKVxuICByZXR1cm4gKFxuICAgIDxNZXNzYWdlUmVzcG9uc2U+XG4gICAgICA8VGV4dD57b3V0cHV0LnJlc3VsdH08L1RleHQ+XG4gICAgPC9NZXNzYWdlUmVzcG9uc2U+XG4gIClcbn1cbiJdLCJtYXBwaW5ncyI6IjtBQUFBLGNBQWNBLG9CQUFvQixRQUFRLHVDQUF1QztBQUNqRixPQUFPQyxLQUFLLE1BQU0sT0FBTztBQUN6QixTQUFTQyxhQUFhLFFBQVEsbUNBQW1DO0FBQ2pFLFNBQVNDLDJCQUEyQixRQUFRLGlEQUFpRDtBQUM3RixTQUFTQyxlQUFlLFFBQVEscUNBQXFDO0FBQ3JFLFNBQVNDLEdBQUcsRUFBRUMsSUFBSSxRQUFRLGNBQWM7QUFDeEMsU0FBU0MsY0FBYyxRQUFRLHFCQUFxQjtBQUNwRCxTQUFTQyxVQUFVLFFBQVEseUJBQXlCO0FBQ3BELGNBQWNDLEtBQUssRUFBRUMsTUFBTSxRQUFRLGNBQWM7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