Filemedium importancesource

TagTabs.tsx

components/TagTabs.tsx

139
Lines
20853
Bytes
1
Exports
4
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 ui-flow. It contains 139 lines, 4 detected imports, and 1 detected exports.

Important relationships

Detected exports

  • TagTabs

Keywords

tabstextlengthstartindexendindexmaxwidthmathwidthtab_paddingtabwidths

Detected imports

  • react
  • ../ink/stringWidth.js
  • ../ink.js
  • ../utils/format.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 React from 'react';
import { stringWidth } from '../ink/stringWidth.js';
import { Box, Text } from '../ink.js';
import { truncateToWidth } from '../utils/format.js';

// Constants for width calculations - derived from actual rendered strings
const ALL_TAB_LABEL = 'All';
const TAB_PADDING = 2; // Space before and after tab text: " {tab} "
const HASH_PREFIX_LENGTH = 1; // "#" prefix for non-All tabs
const LEFT_ARROW_PREFIX = '← ';
const RIGHT_HINT_WITH_COUNT_PREFIX = '→';
const RIGHT_HINT_SUFFIX = ' (tab to cycle)';
const RIGHT_HINT_NO_COUNT = '(tab to cycle)';
const MAX_OVERFLOW_DIGITS = 2; // Assume max 99 hidden tabs for width calculation

// Computed widths
const LEFT_ARROW_WIDTH = LEFT_ARROW_PREFIX.length + MAX_OVERFLOW_DIGITS + 1; // "← NN " with gap
const RIGHT_HINT_WIDTH_WITH_COUNT = RIGHT_HINT_WITH_COUNT_PREFIX.length + MAX_OVERFLOW_DIGITS + RIGHT_HINT_SUFFIX.length; // "→NN (tab to cycle)"
const RIGHT_HINT_WIDTH_NO_COUNT = RIGHT_HINT_NO_COUNT.length;
type Props = {
  tabs: string[];
  selectedIndex: number;
  availableWidth: number;
  showAllProjects?: boolean;
};

/**
 * Calculate the display width of a tab
 */
function getTabWidth(tab: string, maxWidth?: number): number {
  if (tab === ALL_TAB_LABEL) {
    return ALL_TAB_LABEL.length + TAB_PADDING;
  }
  // For non-All tabs: " #{tag} " but truncate tag if needed
  const tagWidth = stringWidth(tab);
  const effectiveTagWidth = maxWidth ? Math.min(tagWidth, maxWidth - TAB_PADDING - HASH_PREFIX_LENGTH) : tagWidth;
  return Math.max(0, effectiveTagWidth) + TAB_PADDING + HASH_PREFIX_LENGTH;
}

/**
 * Truncate a tag to fit within maxWidth, accounting for padding and hash prefix
 */
function truncateTag(tag: string, maxWidth: number): string {
  // Available space for the tag text itself: maxWidth - " #" - " "
  const availableForTag = maxWidth - TAB_PADDING - HASH_PREFIX_LENGTH;
  if (stringWidth(tag) <= availableForTag) {
    return tag;
  }
  if (availableForTag <= 1) {
    return tag.charAt(0);
  }
  return truncateToWidth(tag, availableForTag);
}
export function TagTabs({
  tabs,
  selectedIndex,
  availableWidth,
  showAllProjects = false
}: Props): React.ReactNode {
  const resumeLabel = showAllProjects ? 'Resume (All Projects)' : 'Resume';
  const resumeLabelWidth = resumeLabel.length + 1; // +1 for gap

  // Calculate how much space we have for tabs (use worst-case hint width)
  const rightHintWidth = Math.max(RIGHT_HINT_WIDTH_WITH_COUNT, RIGHT_HINT_WIDTH_NO_COUNT);
  const maxTabsWidth = availableWidth - resumeLabelWidth - rightHintWidth - 2; // 2 for gaps

  // Clamp selectedIndex to valid range
  const safeSelectedIndex = Math.max(0, Math.min(selectedIndex, tabs.length - 1));

  // Calculate width of each tab, with truncation for very long tags
  const maxSingleTabWidth = Math.max(20, Math.floor(maxTabsWidth / 2)); // At least show half the space for one tab
  const tabWidths = tabs.map(tab => getTabWidth(tab, maxSingleTabWidth));

  // Find a window of tabs that fits, centered around selectedIndex
  let startIndex = 0;
  let endIndex = tabs.length;

  // Calculate total width of all tabs
  const totalTabsWidth = tabWidths.reduce((sum, w, i) => sum + w + (i < tabWidths.length - 1 ? 1 : 0), 0); // +1 for gaps between tabs

  if (totalTabsWidth > maxTabsWidth) {
    // Need to show a subset - account for left arrow when not at start
    const effectiveMaxWidth = maxTabsWidth - LEFT_ARROW_WIDTH;

    // Start with the selected tab
    let windowWidth = tabWidths[safeSelectedIndex] ?? 0;
    startIndex = safeSelectedIndex;
    endIndex = safeSelectedIndex + 1;

    // Expand window to include more tabs
    while (startIndex > 0 || endIndex < tabs.length) {
      const canExpandLeft = startIndex > 0;
      const canExpandRight = endIndex < tabs.length;
      if (canExpandLeft) {
        const leftWidth = (tabWidths[startIndex - 1] ?? 0) + 1; // +1 for gap
        if (windowWidth + leftWidth <= effectiveMaxWidth) {
          startIndex--;
          windowWidth += leftWidth;
          continue;
        }
      }
      if (canExpandRight) {
        const rightWidth = (tabWidths[endIndex] ?? 0) + 1; // +1 for gap
        if (windowWidth + rightWidth <= effectiveMaxWidth) {
          endIndex++;
          windowWidth += rightWidth;
          continue;
        }
      }
      break;
    }
  }
  const hiddenLeft = startIndex;
  const hiddenRight = tabs.length - endIndex;
  const visibleTabs = tabs.slice(startIndex, endIndex);
  const visibleIndices = visibleTabs.map((_, i_0) => startIndex + i_0);
  return <Box flexDirection="row" gap={1}>
      <Text color="suggestion">{resumeLabel}</Text>
      {hiddenLeft > 0 && <Text dimColor>
          {LEFT_ARROW_PREFIX}
          {hiddenLeft}
        </Text>}
      {visibleTabs.map((tab_0, i_1) => {
      const actualIndex = visibleIndices[i_1]!;
      const isSelected = actualIndex === safeSelectedIndex;
      const displayText = tab_0 === ALL_TAB_LABEL ? tab_0 : `#${truncateTag(tab_0, maxSingleTabWidth - TAB_PADDING)}`;
      return <Text key={tab_0} backgroundColor={isSelected ? 'suggestion' : undefined} color={isSelected ? 'inverseText' : undefined} bold={isSelected}>
            {' '}
            {displayText}{' '}
          </Text>;
    })}
      {hiddenRight > 0 ? <Text dimColor>
          {RIGHT_HINT_WITH_COUNT_PREFIX}
          {hiddenRight}
          {RIGHT_HINT_SUFFIX}
        </Text> : <Text dimColor>{RIGHT_HINT_NO_COUNT}</Text>}
    </Box>;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInN0cmluZ1dpZHRoIiwiQm94IiwiVGV4dCIsInRydW5jYXRlVG9XaWR0aCIsIkFMTF9UQUJfTEFCRUwiLCJUQUJfUEFERElORyIsIkhBU0hfUFJFRklYX0xFTkdUSCIsIkxFRlRfQVJST1dfUFJFRklYIiwiUklHSFRfSElOVF9XSVRIX0NPVU5UX1BSRUZJWCIsIlJJR0hUX0hJTlRfU1VGRklYIiwiUklHSFRfSElOVF9OT19DT1VOVCIsIk1BWF9PVkVSRkxPV19ESUdJVFMiLCJMRUZUX0FSUk9XX1dJRFRIIiwibGVuZ3RoIiwiUklHSFRfSElOVF9XSURUSF9XSVRIX0NPVU5UIiwiUklHSFRfSElOVF9XSURUSF9OT19DT1VOVCIsIlByb3BzIiwidGFicyIsInNlbGVjdGVkSW5kZXgiLCJhdmFpbGFibGVXaWR0aCIsInNob3dBbGxQcm9qZWN0cyIsImdldFRhYldpZHRoIiwidGFiIiwibWF4V2lkdGgiLCJ0YWdXaWR0aCIsImVmZmVjdGl2ZVRhZ1dpZHRoIiwiTWF0aCIsIm1pbiIsIm1heCIsInRydW5jYXRlVGFnIiwidGFnIiwiYXZhaWxhYmxlRm9yVGFnIiwiY2hhckF0IiwiVGFnVGFicyIsIlJlYWN0Tm9kZSIsInJlc3VtZUxhYmVsIiwicmVzdW1lTGFiZWxXaWR0aCIsInJpZ2h0SGludFdpZHRoIiwibWF4VGFic1dpZHRoIiwic2FmZVNlbGVjdGVkSW5kZXgiLCJtYXhTaW5nbGVUYWJXaWR0aCIsImZsb29yIiwidGFiV2lkdGhzIiwibWFwIiwic3RhcnRJbmRleCIsImVuZEluZGV4IiwidG90YWxUYWJzV2lkdGgiLCJyZWR1Y2UiLCJzdW0iLCJ3IiwiaSIsImVmZmVjdGl2ZU1heFdpZHRoIiwid2luZG93V2lkdGgiLCJjYW5FeHBhbmRMZWZ0IiwiY2FuRXhwYW5kUmlnaHQiLCJsZWZ0V2lkdGgiLCJyaWdodFdpZHRoIiwiaGlkZGVuTGVmdCIsImhpZGRlblJpZ2h0IiwidmlzaWJsZVRhYnMiLCJzbGljZSIsInZpc2libGVJbmRpY2VzIiwiXyIsImFjdHVhbEluZGV4IiwiaXNTZWxlY3RlZCIsImRpc3BsYXlUZXh0IiwidW5kZWZpbmVkIl0sInNvdXJjZXMiOlsiVGFnVGFicy50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgc3RyaW5nV2lkdGggfSBmcm9tICcuLi9pbmsvc3RyaW5nV2lkdGguanMnXG5pbXBvcnQgeyBCb3gsIFRleHQgfSBmcm9tICcuLi9pbmsuanMnXG5pbXBvcnQgeyB0cnVuY2F0ZVRvV2lkdGggfSBmcm9tICcuLi91dGlscy9mb3JtYXQuanMnXG5cbi8vIENvbnN0YW50cyBmb3Igd2lkdGggY2FsY3VsYXRpb25zIC0gZGVyaXZlZCBmcm9tIGFjdHVhbCByZW5kZXJlZCBzdHJpbmdzXG5jb25zdCBBTExfVEFCX0xBQkVMID0gJ0FsbCdcbmNvbnN0IFRBQl9QQURESU5HID0gMiAvLyBTcGFjZSBiZWZvcmUgYW5kIGFmdGVyIHRhYiB0ZXh0OiBcIiB7dGFifSBcIlxuY29uc3QgSEFTSF9QUkVGSVhfTEVOR1RIID0gMSAvLyBcIiNcIiBwcmVmaXggZm9yIG5vbi1BbGwgdGFic1xuY29uc3QgTEVGVF9BUlJPV19QUkVGSVggPSAn4oaQICdcbmNvbnN0IFJJR0hUX0hJTlRfV0lUSF9DT1VOVF9QUkVGSVggPSAn4oaSJ1xuY29uc3QgUklHSFRfSElOVF9TVUZGSVggPSAnICh0YWIgdG8gY3ljbGUpJ1xuY29uc3QgUklHSFRfSElOVF9OT19DT1VOVCA9ICcodGFiIHRvIGN5Y2xlKSdcbmNvbnN0IE1BWF9PVkVSRkxPV19ESUdJVFMgPSAyIC8vIEFzc3VtZSBtYXggOTkgaGlkZGVuIHRhYnMgZm9yIHdpZHRoIGNhbGN1bGF0aW9uXG5cbi8vIENvbXB1dGVkIHdpZHRoc1xuY29uc3QgTEVGVF9BUlJPV19XSURUSCA9IExFRlRfQVJST1dfUFJFRklYLmxlbmd0aCArIE1BWF9PVkVSRkxPV19ESUdJVFMgKyAxIC8vIFwi4oaQIE5OIFwiIHdpdGggZ2FwXG5jb25zdCBSSUdIVF9ISU5UX1dJRFRIX1dJVEhfQ09VTlQgPVxuICBSSUdIVF9ISU5UX1dJVEhfQ09VTlRfUFJFRklYLmxlbmd0aCArXG4gIE1BWF9PVkVSRkxPV19ESUdJVFMgK1xuICBSSUdIVF9ISU5UX1NVRkZJWC5sZW5ndGggLy8gXCLihpJOTiAodGFiIHRvIGN5Y2xlKVwiXG5jb25zdCBSSUdIVF9ISU5UX1dJRFRIX05PX0NPVU5UID0gUklHSFRfSElOVF9OT19DT1VOVC5sZW5ndGhcblxudHlwZSBQcm9wcyA9IHtcbiAgdGFiczogc3RyaW5nW11cbiAgc2VsZWN0ZWRJbmRleDogbnVtYmVyXG4gIGF2YWlsYWJsZVdpZHRoOiBudW1iZXJcbiAgc2hvd0FsbFByb2plY3RzPzogYm9vbGVhblxufVxuXG4vKipcbiAqIENhbGN1bGF0ZSB0aGUgZGlzcGxheSB3aWR0aCBvZiBhIHRhYlxuICovXG5mdW5jdGlvbiBnZXRUYWJXaWR0aCh0YWI6IHN0cmluZywgbWF4V2lkdGg/OiBudW1iZXIpOiBudW1iZXIge1xuICBpZiAodGFiID09PSBBTExfVEFCX0xBQkVMKSB7XG4gICAgcmV0dXJuIEFMTF9UQUJfTEFCRUwubGVuZ3RoICsgVEFCX1BBRERJTkdcbiAgfVxuICAvLyBGb3Igbm9uLUFsbCB0YWJzOiBcIiAje3RhZ30gXCIgYnV0IHRydW5jYXRlIHRhZyBpZiBuZWVkZWRcbiAgY29uc3QgdGFnV2lkdGggPSBzdHJpbmdXaWR0aCh0YWIpXG4gIGNvbnN0IGVmZmVjdGl2ZVRhZ1dpZHRoID0gbWF4V2lkdGhcbiAgICA/IE1hdGgubWluKHRhZ1dpZHRoLCBtYXhXaWR0aCAtIFRBQl9QQURESU5HIC0gSEFTSF9QUkVGSVhfTEVOR1RIKVxuICAgIDogdGFnV2lkdGhcbiAgcmV0dXJuIE1hdGgubWF4KDAsIGVmZmVjdGl2ZVRhZ1dpZHRoKSArIFRBQl9QQURESU5HICsgSEFTSF9QUkVGSVhfTEVOR1RIXG59XG5cbi8qKlxuICogVHJ1bmNhdGUgYSB0YWcgdG8gZml0IHdpdGhpbiBtYXhXaWR0aCwgYWNjb3VudGluZyBmb3IgcGFkZGluZyBhbmQgaGFzaCBwcmVmaXhcbiAqL1xuZnVuY3Rpb24gdHJ1bmNhdGVUYWcodGFnOiBzdHJpbmcsIG1heFdpZHRoOiBudW1iZXIpOiBzdHJpbmcge1xuICAvLyBBdmFpbGFibGUgc3BhY2UgZm9yIHRoZSB0YWcgdGV4dCBpdHNlbGY6IG1heFdpZHRoIC0gXCIgI1wiIC0gXCIgXCJcbiAgY29uc3QgYXZhaWxhYmxlRm9yVGFnID0gbWF4V2lkdGggLSBUQUJfUEFERElORyAtIEhBU0hfUFJFRklYX0xFTkdUSFxuICBpZiAoc3RyaW5nV2lkdGgodGFnKSA8PSBhdmFpbGFibGVGb3JUYWcpIHtcbiAgICByZXR1cm4gdGFnXG4gIH1cbiAgaWYgKGF2YWlsYWJsZUZvclRhZyA8PSAxKSB7XG4gICAgcmV0dXJuIHRhZy5jaGFyQXQoMClcbiAgfVxuICByZXR1cm4gdHJ1bmNhdGVUb1dpZHRoKHRhZywgYXZhaWxhYmxlRm9yVGFnKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gVGFnVGFicyh7XG4gIHRhYnMsXG4gIHNlbGVjdGVkSW5kZXgsXG4gIGF2YWlsYWJsZVdpZHRoLFxuICBzaG93QWxsUHJvamVjdHMgPSBmYWxzZSxcbn06IFByb3BzKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgY29uc3QgcmVzdW1lTGFiZWwgPSBzaG93QWxsUHJvamVjdHMgPyAnUmVzdW1lIChBbGwgUHJvamVjdHMpJyA6ICdSZXN1bWUnXG4gIGNvbnN0IHJlc3VtZUxhYmVsV2lkdGggPSByZXN1bWVMYWJlbC5sZW5ndGggKyAxIC8vICsxIGZvciBnYXBcblxuICAvLyBDYWxjdWxhdGUgaG93IG11Y2ggc3BhY2Ugd2UgaGF2ZSBmb3IgdGFicyAodXNlIHdvcnN0LWNhc2UgaGludCB3aWR0aClcbiAgY29uc3QgcmlnaHRIaW50V2lkdGggPSBNYXRoLm1heChcbiAgICBSSUdIVF9ISU5UX1dJRFRIX1dJVEhfQ09VTlQsXG4gICAgUklHSFRfSElOVF9XSURUSF9OT19DT1VOVCxcbiAgKVxuICBjb25zdCBtYXhUYWJzV2lkdGggPSBhdmFpbGFibGVXaWR0aCAtIHJlc3VtZUxhYmVsV2lkdGggLSByaWdodEhpbnRXaWR0aCAtIDIgLy8gMiBmb3IgZ2Fwc1xuXG4gIC8vIENsYW1wIHNlbGVjdGVkSW5kZXggdG8gdmFsaWQgcmFuZ2VcbiAgY29uc3Qgc2FmZVNlbGVjdGVkSW5kZXggPSBNYXRoLm1heChcbiAgICAwLFxuICAgIE1hdGgubWluKHNlbGVjdGVkSW5kZXgsIHRhYnMubGVuZ3RoIC0gMSksXG4gIClcblxuICAvLyBDYWxjdWxhdGUgd2lkdGggb2YgZWFjaCB0YWIsIHdpdGggdHJ1bmNhdGlvbiBmb3IgdmVyeSBsb25nIHRhZ3NcbiAgY29uc3QgbWF4U2luZ2xlVGFiV2lkdGggPSBNYXRoLm1heCgyMCwgTWF0aC5mbG9vcihtYXhUYWJzV2lkdGggLyAyKSkgLy8gQXQgbGVhc3Qgc2hvdyBoYWxmIHRoZSBzcGFjZSBmb3Igb25lIHRhYlxuICBjb25zdCB0YWJXaWR0aHMgPSB0YWJzLm1hcCh0YWIgPT4gZ2V0VGFiV2lkdGgodGFiLCBtYXhTaW5nbGVUYWJXaWR0aCkpXG5cbiAgLy8gRmluZCBhIHdpbmRvdyBvZiB0YWJzIHRoYXQgZml0cywgY2VudGVyZWQgYXJvdW5kIHNlbGVjdGVkSW5kZXhcbiAgbGV0IHN0YXJ0SW5kZXggPSAwXG4gIGxldCBlbmRJbmRleCA9IHRhYnMubGVuZ3RoXG5cbiAgLy8gQ2FsY3VsYXRlIHRvdGFsIHdpZHRoIG9mIGFsbCB0YWJzXG4gIGNvbnN0IHRvdGFsVGFic1dpZHRoID0gdGFiV2lkdGhzLnJlZHVjZShcbiAgICAoc3VtLCB3LCBpKSA9PiBzdW0gKyB3ICsgKGkgPCB0YWJXaWR0aHMubGVuZ3RoIC0gMSA/IDEgOiAwKSxcbiAgICAwLFxuICApIC8vICsxIGZvciBnYXBzIGJldHdlZW4gdGFic1xuXG4gIGlmICh0b3RhbFRhYnNXaWR0aCA+IG1heFRhYnNXaWR0aCkge1xuICAgIC8vIE5lZWQgdG8gc2hvdyBhIHN1YnNldCAtIGFjY291bnQgZm9yIGxlZnQgYXJyb3cgd2hlbiBub3QgYXQgc3RhcnRcbiAgICBjb25zdCBlZmZlY3RpdmVNYXhXaWR0aCA9IG1heFRhYnNXaWR0aCAtIExFRlRfQVJST1dfV0lEVEhcblxuICAgIC8vIFN0YXJ0IHdpdGggdGhlIHNlbGVjdGVkIHRhYlxuICAgIGxldCB3aW5kb3dXaWR0aCA9IHRhYldpZHRoc1tzYWZlU2VsZWN0ZWRJbmRleF0gPz8gMFxuICAgIHN0YXJ0SW5kZXggPSBzYWZlU2VsZWN0ZWRJbmRleFxuICAgIGVuZEluZGV4ID0gc2FmZVNlbGVjdGVkSW5kZXggKyAxXG5cbiAgICAvLyBFeHBhbmQgd2luZG93IHRvIGluY2x1ZGUgbW9yZSB0YWJzXG4gICAgd2hpbGUgKHN0YXJ0SW5kZXggPiAwIHx8IGVuZEluZGV4IDwgdGFicy5sZW5ndGgpIHtcbiAgICAgIGNvbnN0IGNhbkV4cGFuZExlZnQgPSBzdGFydEluZGV4ID4gMFxuICAgICAgY29uc3QgY2FuRXhwYW5kUmlnaHQgPSBlbmRJbmRleCA8IHRhYnMubGVuZ3RoXG5cbiAgICAgIGlmIChjYW5FeHBhbmRMZWZ0KSB7XG4gICAgICAgIGNvbnN0IGxlZnRXaWR0aCA9ICh0YWJXaWR0aHNbc3RhcnRJbmRleCAtIDFdID8/IDApICsgMSAvLyArMSBmb3IgZ2FwXG4gICAgICAgIGlmICh3aW5kb3dXaWR0aCArIGxlZnRXaWR0aCA8PSBlZmZlY3RpdmVNYXhXaWR0aCkge1xuICAgICAgICAgIHN0YXJ0SW5kZXgtLVxuICAgICAgICAgIHdpbmRvd1dpZHRoICs9IGxlZnRXaWR0aFxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGNhbkV4cGFuZFJpZ2h0KSB7XG4gICAgICAgIGNvbnN0IHJpZ2h0V2lkdGggPSAodGFiV2lkdGhzW2VuZEluZGV4XSA/PyAwKSArIDEgLy8gKzEgZm9yIGdhcFxuICAgICAgICBpZiAod2luZG93V2lkdGggKyByaWdodFdpZHRoIDw9IGVmZmVjdGl2ZU1heFdpZHRoKSB7XG4gICAgICAgICAgZW5kSW5kZXgrK1xuICAgICAgICAgIHdpbmRvd1dpZHRoICs9IHJpZ2h0V2lkdGhcbiAgICAgICAgICBjb250aW51ZVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGJyZWFrXG4gICAgfVxuICB9XG5cbiAgY29uc3QgaGlkZGVuTGVmdCA9IHN0YXJ0SW5kZXhcbiAgY29uc3QgaGlkZGVuUmlnaHQgPSB0YWJzLmxlbmd0aCAtIGVuZEluZGV4XG4gIGNvbnN0IHZpc2libGVUYWJzID0gdGFicy5zbGljZShzdGFydEluZGV4LCBlbmRJbmRleClcbiAgY29uc3QgdmlzaWJsZUluZGljZXMgPSB2aXNpYmxlVGFicy5tYXAoKF8sIGkpID0+IHN0YXJ0SW5kZXggKyBpKVxuXG4gIHJldHVybiAoXG4gICAgPEJveCBmbGV4RGlyZWN0aW9uPVwicm93XCIgZ2FwPXsxfT5cbiAgICAgIDxUZXh0IGNvbG9yPVwic3VnZ2VzdGlvblwiPntyZXN1bWVMYWJlbH08L1RleHQ+XG4gICAgICB7aGlkZGVuTGVmdCA+IDAgJiYgKFxuICAgICAgICA8VGV4dCBkaW1Db2xvcj5cbiAgICAgICAgICB7TEVGVF9BUlJPV19QUkVGSVh9XG4gICAgICAgICAge2hpZGRlbkxlZnR9XG4gICAgICAgIDwvVGV4dD5cbiAgICAgICl9XG4gICAgICB7dmlzaWJsZVRhYnMubWFwKCh0YWIsIGkpID0+IHtcbiAgICAgICAgY29uc3QgYWN0dWFsSW5kZXggPSB2aXNpYmxlSW5kaWNlc1tpXSFcbiAgICAgICAgY29uc3QgaXNTZWxlY3RlZCA9IGFjdHVhbEluZGV4ID09PSBzYWZlU2VsZWN0ZWRJbmRleFxuICAgICAgICBjb25zdCBkaXNwbGF5VGV4dCA9XG4gICAgICAgICAgdGFiID09PSBBTExfVEFCX0xBQkVMXG4gICAgICAgICAgICA/IHRhYlxuICAgICAgICAgICAgOiBgIyR7dHJ1bmNhdGVUYWcodGFiLCBtYXhTaW5nbGVUYWJXaWR0aCAtIFRBQl9QQURESU5HKX1gXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgPFRleHRcbiAgICAgICAgICAgIGtleT17dGFifVxuICAgICAgICAgICAgYmFja2dyb3VuZENvbG9yPXtpc1NlbGVjdGVkID8gJ3N1Z2dlc3Rpb24nIDogdW5kZWZpbmVkfVxuICAgICAgICAgICAgY29sb3I9e2lzU2VsZWN0ZWQgPyAnaW52ZXJzZVRleHQnIDogdW5kZWZpbmVkfVxuICAgICAgICAgICAgYm9sZD17aXNTZWxlY3RlZH1cbiAgICAgICAgICA+XG4gICAgICAgICAgICB7JyAnfVxuICAgICAgICAgICAge2Rpc3BsYXlUZXh0fXsnICd9XG4gICAgICAgICAgPC9UZXh0PlxuICAgICAgICApXG4gICAgICB9KX1cbiAgICAgIHtoaWRkZW5SaWdodCA+IDAgPyAoXG4gICAgICAgIDxUZXh0IGRpbUNvbG9yPlxuICAgICAgICAgIHtSSUdIVF9ISU5UX1dJVEhfQ09VTlRfUFJFRklYfVxuICAgICAgICAgIHtoaWRkZW5SaWdodH1cbiAgICAgICAgICB7UklHSFRfSElOVF9TVUZGSVh9XG4gICAgICAgIDwvVGV4dD5cbiAgICAgICkgOiAoXG4gICAgICAgIDxUZXh0IGRpbUNvbG9yPntSSUdIVF9ISU5UX05PX0NPVU5UfTwvVGV4dD5cbiAgICAgICl9XG4gICAgPC9Cb3g+XG4gIClcbn1cbiJdLCJtYXBwaW5ncyI6IkFBQUEsT0FBT0EsS0FBSyxNQUFNLE9BQU87QUFDekIsU0FBU0MsV0FBVyxRQUFRLHVCQUF1QjtBQUNuRCxTQUFTQyxHQUFHLEVBQUVDLElBQUksUUFBUSxXQUFXO0FBQ3JDLFNBQVNDLGVBQWUsUUFBUSxvQkFBb0I7O0FBRXBEO0FBQ0EsTUFBTUMsYUFBYSxHQUFHLEtBQUs7QUFDM0IsTUFBTUMsV0FBVyxHQUFHLENBQUMsRUFBQztBQUN0QixNQUFNQyxrQkFBa0IsR0FBRyxDQUFDLEVBQUM7QUFDN0IsTUFBTUMsaUJBQWlCLEdBQUcsSUFBSTtBQUM5QixNQUFNQyw0QkFBNEIsR0FBRyxHQUFHO0FBQ3hDLE1BQU1DLGlCQUFpQixHQUFHLGlCQUFpQjtBQUMzQyxNQUFNQyxtQkFBbUIsR0FBRyxnQkFBZ0I7QUFDNUMsTUFBTUMsbUJB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