export class ServicePureExecutionQueryState extends LambdaEditorState {
  editorStore: EditorStore;
  execution: PureExecution;
  isInitializingLambda = false;

  openQueryImporter = false;
  queries: LightQuery[] = [];
  selectedQueryInfo?: QueryImportInfo | undefined;
  loadQueriesState = ActionState.create();
  loadQueryInfoState = ActionState.create();
  importQueryState = ActionState.create();

  constructor(editorStore: EditorStore, execution: PureExecution) {
    super('', '');

    makeObservable(this, {
      execution: observable,
      isInitializingLambda: observable,
      openQueryImporter: observable,
      queries: observable,
      selectedQueryInfo: observable,
      setOpenQueryImporter: action,
      setIsInitializingLambda: action,
      setLambda: action,
      updateLamba: flow,
      loadQueries: flow,
      setSelectedQueryInfo: flow,
      importQuery: flow,
    });

    this.editorStore = editorStore;
    this.execution = execution;
  }

  get lambdaId(): string {
    return buildSourceInformationSourceId([
      this.execution.owner.path,
      'execution',
    ]);
  }

  get query(): RawLambda {
    return this.execution.func;
  }

  setIsInitializingLambda(val: boolean): void {
    this.isInitializingLambda = val;
  }

  setLambda(val: RawLambda): void {
    this.execution.setFunction(val);
  }

  setOpenQueryImporter(val: boolean): void {
    this.openQueryImporter = val;
  }

  *setSelectedQueryInfo(query: LightQuery | undefined): GeneratorFn<void> {
    if (query) {
      try {
        this.loadQueryInfoState.inProgress();
        const content =
          (yield this.editorStore.graphManagerState.graphManager.lambdaToPureCode(
            (yield this.editorStore.graphManagerState.graphManager.pureCodeToLambda(
              (yield this.editorStore.graphManagerState.graphManager.getQueryContent(
                query.id,
              )) as string,
            )) as RawLambda,
            '',
            true,
          )) as string;
        this.selectedQueryInfo = {
          query,
          content,
        };
      } catch (error) {
        assertErrorThrown(error);
        this.editorStore.applicationStore.notifyError(error);
      } finally {
        this.loadQueryInfoState.reset();
      }
    } else {
      this.selectedQueryInfo = undefined;
    }
  }

  *importQuery(): GeneratorFn<void> {
    if (this.selectedQueryInfo) {
      try {
        this.importQueryState.inProgress();
        const lambda =
          (yield this.editorStore.graphManagerState.graphManager.pureCodeToLambda(
            this.selectedQueryInfo.content,
          )) as RawLambda;
        yield flowResult(this.updateLamba(lambda));
      } catch (error) {
        assertErrorThrown(error);
        this.editorStore.applicationStore.notifyError(error);
      } finally {
        this.setOpenQueryImporter(false);
        this.importQueryState.reset();
      }
    }
  }

  *loadQueries(searchText: string): GeneratorFn<void> {
    const isValidSearchString = searchText.length >= 3;
    this.loadQueriesState.inProgress();
    const dependencyProjectCoordinates = Array.from(
      (
        (yield flowResult(
          this.editorStore.graphState.getConfigurationProjectDependencyEntities(),
        )) as Map<string, Entity[]>
      ).keys(),
    );
    try {
      this.queries =
        (yield this.editorStore.graphManagerState.graphManager.getQueries({
          search: isValidSearchString ? searchText : undefined,
          projectCoordinates: [
            // either get queries for the current project
            generateGAVCoordinates(
              this.editorStore.projectConfigurationEditorState
                .currentProjectConfiguration.groupId,
              this.editorStore.projectConfigurationEditorState
                .currentProjectConfiguration.artifactId,
              undefined,
            ),
            // or any of its dependencies
            ...dependencyProjectCoordinates,
          ],
          limit: 10,
        })) as LightQuery[];
      this.loadQueriesState.pass();
    } catch (error) {
      assertErrorThrown(error);
      this.loadQueriesState.fail();
      this.editorStore.applicationStore.notifyError(error);
    }
  }

  *updateLamba(val: RawLambda): GeneratorFn<void> {
    this.setLambda(val);
    yield flowResult(this.convertLambdaObjectToGrammarString(true));
  }

  *convertLambdaObjectToGrammarString(pretty?: boolean): GeneratorFn<void> {
    if (this.execution.func.body) {
      try {
        const lambdas = new Map<string, RawLambda>();
        lambdas.set(
          this.lambdaId,
          new RawLambda(
            this.execution.func.parameters,
            this.execution.func.body,
          ),
        );
        const isolatedLambdas =
          (yield this.editorStore.graphManagerState.graphManager.lambdasToPureCode(
            lambdas,
            pretty,
          )) as Map<string, string>;
        const grammarText = isolatedLambdas.get(this.lambdaId);
        this.setLambdaString(
          grammarText !== undefined
            ? this.extractLambdaString(grammarText)
            : '',
        );
        this.clearErrors();
      } catch (error) {
        assertErrorThrown(error);
        this.editorStore.applicationStore.log.error(
          LogEvent.create(GRAPH_MANAGER_LOG_EVENT.PARSING_FAILURE),
          error,
        );
      }
    } else {
      this.clearErrors();
      this.setLambdaString('');
    }
  }

  // NOTE: since we don't allow edition in text mode, we don't need to implement this
  *convertLambdaGrammarStringToObject(): GeneratorFn<void> {
    throw new UnsupportedOperationError();
  }
}


export class ServicePureExecutionState extends ServiceExecutionState {
  queryState: ServicePureExecutionQueryState;
  declare execution: PureExecution;
  selectedExecutionConfiguration?:
    | PureSingleExecution
    | KeyedExecutionParameter
    | undefined;
  runtimeEditorState?: RuntimeEditorState | undefined;
  isExecuting = false;
  isGeneratingPlan = false;
  isOpeningQueryEditor = false;
  executionResultText?: string | undefined; // NOTE: stored as lossless JSON string
  executionPlanState: ExecutionPlanState;

  constructor(
    editorStore: EditorStore,
    serviceEditorState: ServiceEditorState,
    execution: PureExecution,
    test: ServiceTest,
  ) {
    super(editorStore, serviceEditorState, execution, test);

    makeObservable(this, {
      queryState: observable,
      selectedExecutionConfiguration: observable,
      runtimeEditorState: observable,
      isExecuting: observable,
      isGeneratingPlan: observable,
      isOpeningQueryEditor: observable,
      executionResultText: observable,
      executionPlanState: observable,
      setExecutionResultText: action,
      closeRuntimeEditor: action,
      openRuntimeEditor: action,
      useCustomRuntime: action,
      setQueryState: action,
      autoSelectRuntimeOnMappingChange: action,
      updateExecutionQuery: action,
      setOpeningQueryEditor: action,
      generatePlan: flow,
      execute: flow,
    });

    this.execution = execution;
    this.selectedExecutionConfiguration =
      this.getInitiallySelectedExecution(execution);
    this.queryState = new ServicePureExecutionQueryState(
      this.editorStore,
      execution,
    );
    this.executionPlanState = new ExecutionPlanState(this.editorStore);
  }

  setOpeningQueryEditor(val: boolean): void {
    this.isOpeningQueryEditor = val;
  }
  setExecutionResultText = (executionResult: string | undefined): void => {
    this.executionResultText = executionResult;
  };
  setQueryState = (queryState: ServicePureExecutionQueryState): void => {
    this.queryState = queryState;
  };

  *generatePlan(): GeneratorFn<void> {
    if (!this.selectedExecutionConfiguration || this.isGeneratingPlan) {
      return;
    }
    try {
      this.isGeneratingPlan = true;
      const query = this.queryState.query;
      yield flowResult(
        this.executionPlanState.generatePlan(
          this.selectedExecutionConfiguration.mapping.value,
          query,
          this.selectedExecutionConfiguration.runtime,
        ),
      );
    } catch (error) {
      assertErrorThrown(error);
      this.editorStore.applicationStore.log.error(
        LogEvent.create(GRAPH_MANAGER_LOG_EVENT.EXECUTION_FAILURE),
        error,
      );
      this.editorStore.applicationStore.notifyError(error);
    } finally {
      this.isGeneratingPlan = false;
    }
  }

  *execute(): GeneratorFn<void> {
    if (!this.selectedExecutionConfiguration || this.isExecuting) {
      return;
    }
    try {
      this.isExecuting = true;
      const query = this.queryState.query;
      const result =
        (yield this.editorStore.graphManagerState.graphManager.executeMapping(
          this.editorStore.graphManagerState.graph,
          this.selectedExecutionConfiguration.mapping.value,
          query,
          this.selectedExecutionConfiguration.runtime,
          PureClientVersion.VX_X_X,
          true,
        )) as ExecutionResult;
      this.setExecutionResultText(
        losslessStringify(result, undefined, TAB_SIZE),
      );
    } catch (error) {
      assertErrorThrown(error);
      this.editorStore.applicationStore.log.error(
        LogEvent.create(GRAPH_MANAGER_LOG_EVENT.EXECUTION_FAILURE),
        error,
      );
      this.editorStore.applicationStore.notifyError(error);
    } finally {
      this.isExecuting = false;
    }
  }

  get serviceExecutionParameters():
    | { query: RawLambda; mapping: Mapping; runtime: Runtime }
    | undefined {
    if (!this.selectedExecutionConfiguration || this.isExecuting) {
      return undefined;
    }
    const query = this.queryState.query;
    return {
      query,
      mapping: this.selectedExecutionConfiguration.mapping.value,
      runtime: this.selectedExecutionConfiguration.runtime,
    };
  }

  closeRuntimeEditor(): void {
    this.runtimeEditorState = undefined;
  }
  openRuntimeEditor(): void {
    if (
      this.selectedExecutionConfiguration &&
      !(this.selectedExecutionConfiguration.runtime instanceof RuntimePointer)
    ) {
      this.runtimeEditorState = new RuntimeEditorState(
        this.editorStore,
        this.selectedExecutionConfiguration.runtime,
        true,
      );
    }
  }

  useCustomRuntime(): void {
    if (this.selectedExecutionConfiguration) {
      const customRuntime = new EngineRuntime();
      customRuntime.addMapping(
        PackageableElementExplicitReference.create(
          this.selectedExecutionConfiguration.mapping.value,
        ),
      );
      decorateRuntimeWithNewMapping(
        this.selectedExecutionConfiguration.runtime,
        this.selectedExecutionConfiguration.mapping.value,
        this.editorStore,
      );
      this.selectedExecutionConfiguration.setRuntime(customRuntime);
    }
  }

  autoSelectRuntimeOnMappingChange(mapping: Mapping): void {
    if (this.selectedExecutionConfiguration) {
      const runtimes =
        this.editorStore.graphManagerState.graph.ownRuntimes.filter((runtime) =>
          runtime.runtimeValue.mappings.map((m) => m.value).includes(mapping),
        );
      if (runtimes.length) {
        this.selectedExecutionConfiguration.setRuntime(
          (runtimes[0] as PackageableRuntime).runtimeValue,
        );
      } else {
        this.useCustomRuntime();
      }
    }
  }

  getInitiallySelectedExecution(
    execution: PureExecution,
  ): PureSingleExecution | KeyedExecutionParameter | undefined {
    if (execution instanceof PureSingleExecution) {
      return execution;
    } else if (execution instanceof PureMultiExecution) {
      if (execution.executionParameters.length) {
        return execution.executionParameters[0];
      }
      return undefined;
    }
    throw new UnsupportedOperationError();
  }

  updateExecutionQuery(): void {
    this.execution.setFunction(this.queryState.query);
  }
}


interface QueryImportInfo {
  query: LightQuery;
  content: string;
}


export enum SERVICE_EXECUTION_TAB {
  MAPPING_AND_RUNTIME = 'MAPPING_&_Runtime',
  TESTS = 'TESTS',
}


setSelectedTab(val: SERVICE_EXECUTION_TAB): void {
    this.selectedTab = val;
  }


getInitiallySelectedTestState(
    execution: ServiceExecution,
    test: ServiceTest,
  ): SingleExecutionTestState | undefined {
    if (execution instanceof PureSingleExecution) {
      return new SingleExecutionTestState(
        this.editorStore,
        this.serviceEditorState,
      );
    } else if (execution instanceof PureMultiExecution) {
      // TODO: handle this properly
      // const multiTest = guaranteeType(test, MultiExecutionTest);
      // if (multiTest.tests.length) {
      //   return new KeyedSingleExecutionState(this.editorStore, multiTest.tests[0], this.serviceEditorState);
      // }
      return undefined;
    }
    throw new UnsupportedOperationError();
  }


setIsInitializingLambda(val: boolean): void {
    this.isInitializingLambda = val;
  }


setLambda(val: RawLambda): void {
    this.execution.setFunction(val);
  }


setOpenQueryImporter(val: boolean): void {
    this.openQueryImporter = val;
  }


*setSelectedQueryInfo(query: LightQuery | undefined): GeneratorFn<void> {
    if (query) {
      try {
        this.loadQueryInfoState.inProgress();
        const content =
          (yield this.editorStore.graphManagerState.graphManager.lambdaToPureCode(
            (yield this.editorStore.graphManagerState.graphManager.pureCodeToLambda(
              (yield this.editorStore.graphManagerState.graphManager.getQueryContent(
                query.id,
              )) as string,
            )) as RawLambda,
            '',
            true,
          )) as string;
        this.selectedQueryInfo = {
          query,
          content,
        };
      } catch (error) {
        assertErrorThrown(error);
        this.editorStore.applicationStore.notifyError(error);
      } finally {
        this.loadQueryInfoState.reset();
      }
    } else {
      this.selectedQueryInfo = undefined;
    }
  }


*importQuery(): GeneratorFn<void> {
    if (this.selectedQueryInfo) {
      try {
        this.importQueryState.inProgress();
        const lambda =
          (yield this.editorStore.graphManagerState.graphManager.pureCodeToLambda(
            this.selectedQueryInfo.content,
          )) as RawLambda;
        yield flowResult(this.updateLamba(lambda));
      } catch (error) {
        assertErrorThrown(error);
        this.editorStore.applicationStore.notifyError(error);
      } finally {
        this.setOpenQueryImporter(false);
        this.importQueryState.reset();
      }
    }
  }


*loadQueries(searchText: string): GeneratorFn<void> {
    const isValidSearchString = searchText.length >= 3;
    this.loadQueriesState.inProgress();
    const dependencyProjectCoordinates = Array.from(
      (
        (yield flowResult(
          this.editorStore.graphState.getConfigurationProjectDependencyEntities(),
        )) as Map<string, Entity[]>
      ).keys(),
    );
    try {
      this.queries =
        (yield this.editorStore.graphManagerState.graphManager.getQueries({
          search: isValidSearchString ? searchText : undefined,
          projectCoordinates: [
            // either get queries for the current project
            generateGAVCoordinates(
              this.editorStore.projectConfigurationEditorState
                .currentProjectConfiguration.groupId,
              this.editorStore.projectConfigurationEditorState
                .currentProjectConfiguration.artifactId,
              undefined,
            ),
            // or any of its dependencies
            ...dependencyProjectCoordinates,
          ],
          limit: 10,
        })) as LightQuery[];
      this.loadQueriesState.pass();
    } catch (error) {
      assertErrorThrown(error);
      this.loadQueriesState.fail();
      this.editorStore.applicationStore.notifyError(error);
    }
  }


*updateLamba(val: RawLambda): GeneratorFn<void> {
    this.setLambda(val);
    yield flowResult(this.convertLambdaObjectToGrammarString(true));
  }


*convertLambdaObjectToGrammarString(pretty?: boolean): GeneratorFn<void> {
    if (this.execution.func.body) {
      try {
        const lambdas = new Map<string, RawLambda>();
        lambdas.set(
          this.lambdaId,
          new RawLambda(
            this.execution.func.parameters,
            this.execution.func.body,
          ),
        );
        const isolatedLambdas =
          (yield this.editorStore.graphManagerState.graphManager.lambdasToPureCode(
            lambdas,
            pretty,
          )) as Map<string, string>;
        const grammarText = isolatedLambdas.get(this.lambdaId);
        this.setLambdaString(
          grammarText !== undefined
            ? this.extractLambdaString(grammarText)
            : '',
        );
        this.clearErrors();
      } catch (error) {
        assertErrorThrown(error);
        this.editorStore.applicationStore.log.error(
          LogEvent.create(GRAPH_MANAGER_LOG_EVENT.PARSING_FAILURE),
          error,
        );
      }
    } else {
      this.clearErrors();
      this.setLambdaString('');
    }
  }


// NOTE: since we don't allow edition in text mode, we don't need to implement this
*convertLambdaGrammarStringToObject(): GeneratorFn<void> {
    throw new UnsupportedOperationError();
  }


setOpeningQueryEditor(val: boolean): void {
    this.isOpeningQueryEditor = val;
  }


*generatePlan(): GeneratorFn<void> {
    if (!this.selectedExecutionConfiguration || this.isGeneratingPlan) {
      return;
    }
    try {
      this.isGeneratingPlan = true;
      const query = this.queryState.query;
      yield flowResult(
        this.executionPlanState.generatePlan(
          this.selectedExecutionConfiguration.mapping.value,
          query,
          this.selectedExecutionConfiguration.runtime,
        ),
      );
    } catch (error) {
      assertErrorThrown(error);
      this.editorStore.applicationStore.log.error(
        LogEvent.create(GRAPH_MANAGER_LOG_EVENT.EXECUTION_FAILURE),
        error,
      );
      this.editorStore.applicationStore.notifyError(error);
    } finally {
      this.isGeneratingPlan = false;
    }
  }


*execute(): GeneratorFn<void> {
    if (!this.selectedExecutionConfiguration || this.isExecuting) {
      return;
    }
    try {
      this.isExecuting = true;
      const query = this.queryState.query;
      const result =
        (yield this.editorStore.graphManagerState.graphManager.executeMapping(
          this.editorStore.graphManagerState.graph,
          this.selectedExecutionConfiguration.mapping.value,
          query,
          this.selectedExecutionConfiguration.runtime,
          PureClientVersion.VX_X_X,
          true,
        )) as ExecutionResult;
      this.setExecutionResultText(
        losslessStringify(result, undefined, TAB_SIZE),
      );
    } catch (error) {
      assertErrorThrown(error);
      this.editorStore.applicationStore.log.error(
        LogEvent.create(GRAPH_MANAGER_LOG_EVENT.EXECUTION_FAILURE),
        error,
      );
      this.editorStore.applicationStore.notifyError(error);
    } finally {
      this.isExecuting = false;
    }
  }


closeRuntimeEditor(): void {
    this.runtimeEditorState = undefined;
  }


openRuntimeEditor(): void {
    if (
      this.selectedExecutionConfiguration &&
      !(this.selectedExecutionConfiguration.runtime instanceof RuntimePointer)
    ) {
      this.runtimeEditorState = new RuntimeEditorState(
        this.editorStore,
        this.selectedExecutionConfiguration.runtime,
        true,
      );
    }
  }


useCustomRuntime(): void {
    if (this.selectedExecutionConfiguration) {
      const customRuntime = new EngineRuntime();
      customRuntime.addMapping(
        PackageableElementExplicitReference.create(
          this.selectedExecutionConfiguration.mapping.value,
        ),
      );
      decorateRuntimeWithNewMapping(
        this.selectedExecutionConfiguration.runtime,
        this.selectedExecutionConfiguration.mapping.value,
        this.editorStore,
      );
      this.selectedExecutionConfiguration.setRuntime(customRuntime);
    }
  }


autoSelectRuntimeOnMappingChange(mapping: Mapping): void {
    if (this.selectedExecutionConfiguration) {
      const runtimes =
        this.editorStore.graphManagerState.graph.ownRuntimes.filter((runtime) =>
          runtime.runtimeValue.mappings.map((m) => m.value).includes(mapping),
        );
      if (runtimes.length) {
        this.selectedExecutionConfiguration.setRuntime(
          (runtimes[0] as PackageableRuntime).runtimeValue,
        );
      } else {
        this.useCustomRuntime();
      }
    }
  }


getInitiallySelectedExecution(
    execution: PureExecution,
  ): PureSingleExecution | KeyedExecutionParameter | undefined {
    if (execution instanceof PureSingleExecution) {
      return execution;
    } else if (execution instanceof PureMultiExecution) {
      if (execution.executionParameters.length) {
        return execution.executionParameters[0];
      }
      return undefined;
    }
    throw new UnsupportedOperationError();
  }


updateExecutionQuery(): void {
    this.execution.setFunction(this.queryState.query);
  }


export class UIAutomator extends LocatorStrategy {
  pick(value: string): LocatorStrategy {
    const uiSelector: string = this.selector.selector.split('=')[1];
    const selector: string = `android=new UiScrollable(${uiSelector}).flingToBeginning(100).scrollIntoView(new UiSelector().textContains(\"${value}\"))`;
    $(selector).click();
    return this;
  }

  slowPick(value: string): LocatorStrategy {
    const uiSelector: string = this.selector.selector.split('=')[1];
    const selector: string = `android=new UiScrollable(${uiSelector}).scrollIntoView(new UiSelector().textContains(\"${value}\"))`;
    $(selector).click();
    return this;
  }

  select(): Selector {
    this.selector = new UIAutomatorSelector(this);
    return this.selector;
  }
}


pick(value: string): LocatorStrategy {
    const uiSelector: string = this.selector.selector.split('=')[1];
    const selector: string = `android=new UiScrollable(${uiSelector}).flingToBeginning(100).scrollIntoView(new UiSelector().textContains(\"${value}\"))`;
    $(selector).click();
    return this;
  }


slowPick(value: string): LocatorStrategy {
    const uiSelector: string = this.selector.selector.split('=')[1];
    const selector: string = `android=new UiScrollable(${uiSelector}).scrollIntoView(new UiSelector().textContains(\"${value}\"))`;
    $(selector).click();
    return this;
  }


select(): Selector {
    this.selector = new UIAutomatorSelector(this);
    return this.selector;
  }


function ToastIcon() {
      const isLaoding = type === 'loading';
      const fill = isLaoding ? '#0278FF' : '#ffffff';
      if (hasIcon) {
        return (
          <i
            class={[bem('icon'), { [`${brandName}loading-circle`]: isLaoding }]}
            style={{ fill, width: '1.5rem', height: '1.5rem' }}
            domPropsInnerHTML={require(`!html-loader!./icon/${type}.svg`)}
          >
        );
      }
    }

    function Message() {
      if (!isDef(message) || message === '') {
        return;
      }

      return
{message}
;
    }

    return (
      <transition
        name={`${brandName}fade`}
        onAfterEnter={this.onAfterEnter}
        onAfterLeave={this.onAfterLeave}
      >

          {ToastIcon()}
          {Message()}

      </transition>
    );
  },
});


value => {
        return types.indexOf(value) > -1;
      }


export interface ToastProps {
  icon: string;
  message: number | string;
  forbidClick: boolean;
  type: ToastTypes;
  position: string;
  lockScroll: boolean;
}


export interface ToastEvents {
  onOpened(): void;
  onClosed(): void;
}


export interface ToastScopedSlots extends DefaultSlots {}


type ToastTypes = 'text' | 'success' | 'warning' | 'error' | 'loading';


data() {
    return {
      clickable: false,
    };
  }


mounted() {
    this.toggleClickable();
  }


destroyed() {
    this.toggleClickable();
  }


value() {
      this.toggleClickable();
    }


forbidClick() {
      this.toggleClickable();
    }


toggleClickable(this: any) {
      const brandName = createBrandName();

      const clickable = this.value && this.forbidClick;
      if (this.clickable !== clickable) {
        this.clickable = clickable;
        const action = clickable ? 'add' : 'remove';
        document.body.classList[action](`${brandName}toast--unclickable`);
      }
    }


onAfterEnter(this: any) {
      this.$emit('opened');
      if (this.onOpened) {
        this.onOpened();
      }
    }


onAfterLeave(this: any) {
      this.$emit('closed');
    }


render(this: any) {
    const brandName = createBrandName();

    const { type, icon, message } = this;

    const hasIcon = icon || (types.indexOf(type) > -1 && type !== 'text');

    function ToastIcon() {
      const isLaoding = type === 'loading';
      const fill = isLaoding ? '#0278FF' : '#ffffff';
      if (hasIcon) {
        return (
          <i
            class={[bem('icon'), { [`${brandName}loading-circle`]: isLaoding }]}
            style={{ fill, width: '1.5rem', height: '1.5rem' }}
            domPropsInnerHTML={require(`!html-loader!./icon/${type}.svg`)}
          >
        );
      }
    }

    function Message() {
      if (!isDef(message) || message === '') {
        return;
      }

      return
{message}
;
    }

    return (
      <transition
        name={`${brandName}fade`}
        onAfterEnter={this.onAfterEnter}
        onAfterLeave={this.onAfterLeave}
      >

          {ToastIcon()}
          {Message()}

      </transition>
    );
  },
});


require(`!html-loader!./icon/${type


export class Table extends MenuItem {
    constructor(vditor: IVditor, menuItem: IMenuItem) {
        super(vditor, menuItem);
        this.element.children[0].innerHTML = menuItem.icon || tableSVG;
        this.bindEvent();
    }

    public bindEvent() {
        super.bindEvent();
    }
}


public bindEvent() {
        super.bindEvent();
    }


value => !!value && value.length >= minLength


(ev: React.ChangeEvent<HTMLInputElement>) => setSearchText(ev.target.value)


export type SearchBarProps = {
    hint?: string;
    delay?: number;
    minLength?: number;
    onSearchFor?(searchText: string): void;
};


export default function Intro() {

  const session = useContext(SessionContext);

  return (

						Say 👋 to Xema.

						A new space for saving everything

						{features.map(feature => (

										<feature.icon className='h-6 w-6' aria-hidden='true' />

										{feature.name}

									{feature.description}

						))}

					{!session ? (

							<Link to='/signin'>
								<button
									type='button'
									className='mb-2 flex animate-bounce items-center justify-center rounded bg-orange-500 px-8 py-3 pb-3 font-bold leading-tight text-white transition duration-150 ease-in-out hover:bg-orange-600 focus:outline-none focus:ring-0 dark:bg-orange-700'
								>
									Get started →
								</button>
							</Link>

					) : (
						<Link to='/home'>
							<button
								type='button'
								className='mb-2 flex animate-bounce items-center justify-center rounded bg-orange-500 px-8 py-3 pb-3 font-bold leading-tight text-white transition duration-150 ease-in-out hover:bg-orange-600 focus:outline-none focus:ring-0 dark:bg-orange-700'
							>
								Go home →
							</button>
						</Link>
					)}


feature => (
							<div key={feature.name}


export default function Index() {
    return (
        <Container>

                    <ExternalLink href="https://shivamrathore.com">
                        Hello, I'm{' '}

                            Shivam

                    </ExternalLink>

                    A weird - but - enthusiastic programmer{' '}

                            👋
                        {' '}
                        By the day, I work as a Sr. Software Engineer at{' '}
                        {externalLinkWrapper(
                            'https://appointy.com',
                            'Appointy',
                        )}{' '}
                        and, as the night gathers, my watch begins either as an{' '}
                        {externalLinkWrapper(
                            'https://github.com/Shivam010',
                            'Open-Source Developer',
                        )}{' '}
                        or as a serial binge-watcher. And Just to make it clear,
                        I am a die-hard Harry Potter and Marvel fan.

                        Taking about Open source: Contributing to open source
                        has taught me many things and is still teaching me.
                        Today, I maintain{' '}
                        {externalLinkWrapper(
                            'https://github.com/Shivam010',
                            'few projects',
                        )}{' '}
                        and contribute to a number of them.

                        I also, work as a freelancer developer and ghost worker,
                        helping individuals and organisations create and/or
                        solve their problems and challenges.

                        Got something to discuss, any project idea, any other
                        help you need? or maybe wanna just say Hello! 👋 Feel
                        free to{' '}
                        {externalLinkWrapper(
                            'mailto:hello@shivam010.in',
                            'Reach out to me!',
                        )}{' '}
                        Also, do Checkout my new website:

                <BigButton
                    isExternal
                    href="https://shivamrathore.com"
                    className="w-64 mx-auto mt-14"
                >
                    New web Presense
                </BigButton>

        </Container>
    );
}


function externalLinkWrapper(href: string, child: string) {
    return (
        <ExternalLink href={href}>
            <span className="relative -bottom-[1px] font-bold text-pink-700 italic hover:underline underline-offset-4">
                {child}
            </span>
        </ExternalLink>
    );
}


x => [...x.values()]


@Injectable({ providedIn: "root" })
export class GlobalSidebarService implements OnDestroy {
    public references: Observable<Array<SidebarRef<any>>>;

    public sidebarContent: SidebarContentComponent = null;
    public sidebar: MatSidenav = null;

    private _references: BehaviorSubject<Map<string, SidebarRef<any>>>
        = new BehaviorSubject(new Map<string, SidebarRef<any>>());

    constructor() {
        this.references = this._references.pipe(
            map(x => [...x.values()]),
            publishReplay(1),
            refCount(),
        );
    }

    public ngOnDestroy() {
        this._references.unsubscribe();
    }

    public has(id: string): boolean {
        return this._references.value.has(id);
    }

    public get(id: string): SidebarRef<any> {
        return this._references.value.get(id);
    }

    public delete(id: string): boolean {
        const references = this._references.value;
        const result = references.delete(id);
        this._references.next(references);
        return result;
    }

    public set(id: string, ref: SidebarRef<any>) {
        const references = this._references.value;
        this._references.value.set(id, ref);
        this._references.next(references);
    }
}


@Injectable()
export class SidebarManager {
    constructor(private reference: GlobalSidebarService, private injector: Injector) {
    }

    /**
     * @param id: Unique id for that form. This will allow it to persist
     * @param componentType: Component class you want to init inside the sidebar
     * @param resetOnOpen: By default when the sidebar is closed indirecly the component will still
     * be there so you can resume work. This will make sure it create a new component
     */
    public open<T>(id: string, componentType: Type<T>, resetOnReOpen = false): SidebarRef<T> {
        let sidebarRef: SidebarRef<T>;
        let openNew = true;
        if (this.reference.has(id)) {
            sidebarRef = this.reference.get(id);
            openNew = resetOnReOpen;
        } else {
            sidebarRef = new SidebarRef<T>(this, id);
            this.reference.set(id, sidebarRef);
        }

        // If the component was already init before and we don't want to create a new one
        if (openNew) {
            this.reference.sidebarContent.open(componentType, sidebarRef, this.injector);
        } else {
            this.reference.sidebarContent.display(sidebarRef);
        }

        this.reference.sidebar.open();

        return sidebarRef;
    }

    public reopen<T>(sidebarRef: SidebarRef<T>) {
        const id = sidebarRef.id;
        if (this.reference.has(id)) {
            this.reference.sidebarContent.display(this.reference.get(id));
            this.reference.sidebar.open();
        } else {
            log.error(`Unkown sidebar reference with id '${id}'. Maybe it was closed already"`);
        }
    }

    /**
     * This will just close the sidebar. All the reference will be saved.
     */
    public close() {
        this.reference.sidebar.close();
    }

    /**
     * Close the sidebar and remove the reference.
     */
    public destroy<T>(sidebarRef: SidebarRef<T>) {
        this.reference.sidebarContent.destroy(sidebarRef);
        this.reference.delete(sidebarRef.id);
    }

    /**
     * Event when the sidebar is fully open.
     */
    public get onOpen(): Observable<void> {
        return this.reference.sidebar.openedStart;
    }

    /**
     * Event when the sidebar is closed.
     */
    public get onClosed(): Observable<void> {
        return this.reference.sidebar.closedStart;
    }
}


public ngOnDestroy() {
        this._references.unsubscribe();
    }


public has(id: string): boolean {
        return this._references.value.has(id);
    }


public get(id: string): SidebarRef<any> {
        return this._references.value.get(id);
    }


public delete(id: string): boolean {
        const references = this._references.value;
        const result = references.delete(id);
        this._references.next(references);
        return result;
    }


public set(id: string, ref: SidebarRef<any>) {
        const references = this._references.value;
        this._references.value.set(id, ref);
        this._references.next(references);
    }


/**
     * @param id: Unique id for that form. This will allow it to persist
     * @param componentType: Component class you want to init inside the sidebar
     * @param resetOnOpen: By default when the sidebar is closed indirecly the component will still
     * be there so you can resume work. This will make sure it create a new component
     */
public open<T>(id: string, componentType: Type<T>, resetOnReOpen = false): SidebarRef<T> {
        let sidebarRef: SidebarRef<T>;
        let openNew = true;
        if (this.reference.has(id)) {
            sidebarRef = this.reference.get(id);
            openNew = resetOnReOpen;
        } else {
            sidebarRef = new SidebarRef<T>(this, id);
            this.reference.set(id, sidebarRef);
        }

        // If the component was already init before and we don't want to create a new one
        if (openNew) {
            this.reference.sidebarContent.open(componentType, sidebarRef, this.injector);
        } else {
            this.reference.sidebarContent.display(sidebarRef);
        }

        this.reference.sidebar.open();

        return sidebarRef;
    }


public reopen<T>(sidebarRef: SidebarRef<T>) {
        const id = sidebarRef.id;
        if (this.reference.has(id)) {
            this.reference.sidebarContent.display(this.reference.get(id));
            this.reference.sidebar.open();
        } else {
            log.error(`Unkown sidebar reference with id '${id}'. Maybe it was closed already"`);
        }
    }


/**
     * This will just close the sidebar. All the reference will be saved.
     */
public close() {
        this.reference.sidebar.close();
    }


/**
     * Close the sidebar and remove the reference.
     */
public destroy<T>(sidebarRef: SidebarRef<T>) {
        this.reference.sidebarContent.destroy(sidebarRef);
        this.reference.delete(sidebarRef.id);
    }


export class CustomGenerator extends Generator {
  public force: boolean;
  public dependencies: string[];
  public answers: Record<string, unknown>;
  public configurationPath: string;
}


() => {
  let imageMapper: ImageMapper;

  const imagesMockData = [
    {
      name: 'front S',
      type: 'Image',
      imageActualHeight: 110,
      imageActualWidth: 110,
      viewID: 'front',
      effectiveUrl: '/INTERSHOP/static/WFS/inSPIRED-inTRONICS-Site/-/inSPIRED/en_US/S/S_201807171_front.jpg',
      typeID: 'S',
      primaryImage: true,
    },
    {
      name: 'front S',
      type: 'Image',
      imageActualHeight: 110,
      imageActualWidth: 110,
      viewID: 'front',
      effectiveUrl: 'http://10.0.27.51:2000/images/S/S_201807171_front.jpg',
      typeID: 'S',
      primaryImage: false,
    },
  ] as Image[];

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [provideMockStore({ selectors: [{ selector: getICMBaseURL, value: 'http://example.org' }] })],
    });
    imageMapper = TestBed.inject(ImageMapper);
  });

  describe('fromImages', () => {
    it(`should return Images when getting an Image`, () => {
      const images = imageMapper.fromImages(imagesMockData);
      expect(images).toBeTruthy();
      expect(images[0].effectiveUrl).toBe(
        'http://example.org/INTERSHOP/static/WFS/inSPIRED-inTRONICS-Site/-/inSPIRED/en_US/S/S_201807171_front.jpg'
      );
      expect(images[1].effectiveUrl).toBe('http://10.0.27.51:2000/images/S/S_201807171_front.jpg');
    });
  });
}


() => {
    TestBed.configureTestingModule({
      providers: [provideMockStore({ selectors: [{ selector: getICMBaseURL, value: 'http://example.org' }] })],
    });
    imageMapper = TestBed.inject(ImageMapper);
  }


() => {
    it(`should return Images when getting an Image`, () => {
      const images = imageMapper.fromImages(imagesMockData);
      expect(images).toBeTruthy();
      expect(images[0].effectiveUrl).toBe(
        'http://example.org/INTERSHOP/static/WFS/inSPIRED-inTRONICS-Site/-/inSPIRED/en_US/S/S_201807171_front.jpg'
      );
      expect(images[1].effectiveUrl).toBe('http://10.0.27.51:2000/images/S/S_201807171_front.jpg');
    });
  }


() => {
      const images = imageMapper.fromImages(imagesMockData);
      expect(images).toBeTruthy();
      expect(images[0].effectiveUrl).toBe(
        'http://example.org/INTERSHOP/static/WFS/inSPIRED-inTRONICS-Site/-/inSPIRED/en_US/S/S_201807171_front.jpg'
      );
      expect(images[1].effectiveUrl).toBe('http://10.0.27.51:2000/images/S/S_201807171_front.jpg');
    }


/**
 * The AWS::Amplify::Domain resource allows you to connect a custom domain to your app.
 */
export class Domain extends pulumi.CustomResource {
    /**
     * Get an existing Domain resource's state with the given name, ID, and optional extra
     * properties used to qualify the lookup.
     *
     * @param name The _unique_ name of the resulting resource.
     * @param id The _unique_ provider ID of the resource to lookup.
     * @param opts Optional settings to control the behavior of the CustomResource.
     */
    public static get(name: string, id: pulumi.Input<pulumi.ID>, opts?: pulumi.CustomResourceOptions): Domain {
        return new Domain(name, undefined as any, { ...opts, id: id });
    }

    /** @internal */
    public static readonly __pulumiType = 'aws-native:amplify:Domain';

    /**
     * Returns true if the given object is an instance of Domain.  This is designed to work even
     * when multiple copies of the Pulumi SDK have been loaded into the same process.
     */
    public static isInstance(obj: any): obj is Domain {
        if (obj === undefined || obj === null) {
            return false;
        }
        return obj['__pulumiType'] === Domain.__pulumiType;
    }

    public readonly appId!: pulumi.Output<string>;
    public /*out*/ readonly arn!: pulumi.Output<string>;
    public readonly autoSubDomainCreationPatterns!: pulumi.Output<string[] | undefined>;
    public readonly autoSubDomainIAMRole!: pulumi.Output<string | undefined>;
    public /*out*/ readonly certificateRecord!: pulumi.Output<string>;
    public readonly domainName!: pulumi.Output<string>;
    public /*out*/ readonly domainStatus!: pulumi.Output<string>;
    public readonly enableAutoSubDomain!: pulumi.Output<boolean | undefined>;
    public /*out*/ readonly statusReason!: pulumi.Output<string>;
    public readonly subDomainSettings!: pulumi.Output<outputs.amplify.DomainSubDomainSetting[]>;

    /**
     * Create a Domain resource with the given unique name, arguments, and options.
     *
     * @param name The _unique_ name of the resource.
     * @param args The arguments to use to populate this resource's properties.
     * @param opts A bag of options that control this resource's behavior.
     */
    constructor(name: string, args: DomainArgs, opts?: pulumi.CustomResourceOptions) {
        let resourceInputs: pulumi.Inputs = {};
        opts = opts || {};
        if (!opts.id) {
            if ((!args || args.appId === undefined) && !opts.urn) {
                throw new Error("Missing required property 'appId'");
            }
            if ((!args || args.subDomainSettings === undefined) && !opts.urn) {
                throw new Error("Missing required property 'subDomainSettings'");
            }
            resourceInputs["appId"] = args ? args.appId : undefined;
            resourceInputs["autoSubDomainCreationPatterns"] = args ? args.autoSubDomainCreationPatterns : undefined;
            resourceInputs["autoSubDomainIAMRole"] = args ? args.autoSubDomainIAMRole : undefined;
            resourceInputs["domainName"] = args ? args.domainName : undefined;
            resourceInputs["enableAutoSubDomain"] = args ? args.enableAutoSubDomain : undefined;
            resourceInputs["subDomainSettings"] = args ? args.subDomainSettings : undefined;
            resourceInputs["arn"] = undefined /*out*/;
            resourceInputs["certificateRecord"] = undefined /*out*/;
            resourceInputs["domainStatus"] = undefined /*out*/;
            resourceInputs["statusReason"] = undefined /*out*/;
        } else {
            resourceInputs["appId"] = undefined /*out*/;
            resourceInputs["arn"] = undefined /*out*/;
            resourceInputs["autoSubDomainCreationPatterns"] = undefined /*out*/;
            resourceInputs["autoSubDomainIAMRole"] = undefined /*out*/;
            resourceInputs["certificateRecord"] = undefined /*out*/;
            resourceInputs["domainName"] = undefined /*out*/;
            resourceInputs["domainStatus"] = undefined /*out*/;
            resourceInputs["enableAutoSubDomain"] = undefined /*out*/;
            resourceInputs["statusReason"] = undefined /*out*/;
            resourceInputs["subDomainSettings"] = undefined /*out*/;
        }
        opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts);
        super(Domain.__pulumiType, name, resourceInputs, opts);
    }
}


/**
 * The set of arguments for constructing a Domain resource.
 */
export interface DomainArgs {
    appId: pulumi.Input<string>;
    autoSubDomainCreationPatterns?: pulumi.Input<pulumi.Input<string>[]>;
    autoSubDomainIAMRole?: pulumi.Input<string>;
    domainName?: pulumi.Input<string>;
    enableAutoSubDomain?: pulumi.Input<boolean>;
    subDomainSettings: pulumi.Input<pulumi.Input<inputs.amplify.DomainSubDomainSettingArgs>[]>;
}


/**
     * Get an existing Domain resource's state with the given name, ID, and optional extra
     * properties used to qualify the lookup.
     *
     * @param name The _unique_ name of the resulting resource.
     * @param id The _unique_ provider ID of the resource to lookup.
     * @param opts Optional settings to control the behavior of the CustomResource.
     */
public static get(name: string, id: pulumi.Input<pulumi.ID>, opts?: pulumi.CustomResourceOptions): Domain {
        return new Domain(name, undefined as any, { ...opts, id: id });
    }


/**
     * Returns true if the given object is an instance of Domain.  This is designed to work even
     * when multiple copies of the Pulumi SDK have been loaded into the same process.
     */
public static isInstance(obj: any): obj is Domain {
        if (obj === undefined || obj === null) {
            return false;
        }
        return obj['__pulumiType'] === Domain.__pulumiType;
    }


@NgModule({
  declarations: [
    StartComponent
  ],
  exports: [
    StartComponent,
    CommonModule,
    FormsModule
  ],
  imports: [
    CommonModule
  ]
})
export class SharedModule { }


(resp) => {
      this.redditFeeds = resp.body.data.children;
      loading.dismiss(); // when data is finished fecthed, dismiss loading screen
      console.log(this.redditFeeds,'data');
   }


() => {
      event.target.complete();
    }


@Component({
  selector: 'app-reddit-page',
  templateUrl: './reddit-page.page.html',
  styleUrls: ['./reddit-page.page.scss'],
  providers: [RedditService]
})
export class RedditPagePage implements OnInit {

  public redditFeeds: any;

  constructor(private redditService: RedditService, public loadingController: LoadingController, public toastController: ToastController) {
    this.redditFeeds = [];
  }

  ngOnInit() {
    // get the feed from the reddit service
    this.getFeed();
  }

  async getFeed() {
    // show loading screen when fetching data from API
    const loading = await this.loadingController.create({
      message: 'Pulling Latest Popular Subreddit'
    });
    loading.present();

    this.redditService.getConfig().subscribe((resp) => {
      this.redditFeeds = resp.body.data.children;
      loading.dismiss(); // when data is finished fecthed, dismiss loading screen
      console.log(this.redditFeeds,'data');
   });
  }

  doRefresh(event) {
    this.getFeed();
    setTimeout(() => {
      event.target.complete();
    }, 2000);
  }

  async presentToast() {
    const toast = await this.toastController.create({
      message: 'Page under construction',
      position: 'top',
      duration: 2000
    });
    toast.present();
  }

}


ngOnInit() {
    // get the feed from the reddit service
    this.getFeed();
  }


async getFeed() {
    // show loading screen when fetching data from API
    const loading = await this.loadingController.create({
      message: 'Pulling Latest Popular Subreddit'
    });
    loading.present();

    this.redditService.getConfig().subscribe((resp) => {
      this.redditFeeds = resp.body.data.children;
      loading.dismiss(); // when data is finished fecthed, dismiss loading screen
      console.log(this.redditFeeds,'data');
   });
  }


doRefresh(event) {
    this.getFeed();
    setTimeout(() => {
      event.target.complete();
    }, 2000);
  }


async presentToast() {
    const toast = await this.toastController.create({
      message: 'Page under construction',
      position: 'top',
      duration: 2000
    });
    toast.present();
  }


function walk(ctx: Lint.WalkContext<void>) {
  function cb(node: ts.Node): void {
    if (tsutils.isCallExpression(node)) {
      const functionTarget = AstUtils.getFunctionTarget(node);
      if (functionTarget === 'document' || functionTarget === 'window.document') {
        if (node.arguments.length === 1) {
          const functionName: string = AstUtils.getFunctionName(node);
          if (functionName === 'write') {
            ctx.addFailureAt(node.getStart(), node.getWidth(), Rule.WRITE_FAILURE);
          } else if (functionName === 'writeln') {
            ctx.addFailureAt(node.getStart(), node.getWidth(), Rule.WRITELN_FAILURE);
          }
        }
      }
    }

    return ts.forEachChild(node, cb);
  }

  return ts.forEachChild(ctx.sourceFile, cb);
}


function cb(node: ts.Node): void {
    if (tsutils.isCallExpression(node)) {
      const functionTarget = AstUtils.getFunctionTarget(node);
      if (functionTarget === 'document' || functionTarget === 'window.document') {
        if (node.arguments.length === 1) {
          const functionName: string = AstUtils.getFunctionName(node);
          if (functionName === 'write') {
            ctx.addFailureAt(node.getStart(), node.getWidth(), Rule.WRITE_FAILURE);
          } else if (functionName === 'writeln') {
            ctx.addFailureAt(node.getStart(), node.getWidth(), Rule.WRITELN_FAILURE);
          }
        }
      }
    }

    return ts.forEachChild(node, cb);
  }


export class Rule extends Lint.Rules.AbstractRule {
  public static metadata: ExtendedMetadata = {
    ruleName: 'no-document-write',
    type: 'maintainability',
    description: 'Do not use document.write',
    options: null, // tslint:disable-line:no-null-keyword
    optionsDescription: '',
    typescriptOnly: true,
    issueClass: 'SDL',
    issueType: 'Error',
    severity: 'Critical',
    level: 'Mandatory',
    group: 'Security',
    commonWeaknessEnumeration: '79, 85',
  };

  public static WRITE_FAILURE: string = 'Forbidden call to document.write';
  public static WRITELN_FAILURE: string = 'Forbidden call to document.writeln';

  public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
    return this.applyWithFunction(sourceFile, walk);
  }
}


public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
    return this.applyWithFunction(sourceFile, walk);
  }


export default function valueDiff(
    offer: TradeOffer,
    keyPrices: KeyPrices,
    isTradingKeys: boolean,
    enableShowOnlyMetal: boolean
): ValueDiff {
    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
    const value: { our: Currency; their: Currency } = offer.data('value');

    let diff: number;
    let diffRef: number;
    let diffKey: string;
    if (!value) {
        diff = 0;
        diffRef = 0;
        diffKey = '';
    } else {
        const newValue: { our: Currency; their: Currency } = {
            our: {
                keys: value.our.keys,
                metal: value.our.metal
            },
            their: {
                keys: value.their.keys,
                metal: value.their.metal
            }
        };

        if (!enableShowOnlyMetal) {
            // if ENABLE_SHOW_ONLY_METAL is set to false, then this need to be converted first.
            if (isTradingKeys) {
                // If trading keys, then their side need to use buying key price.
                newValue.our.metal = Currencies.toRefined(
                    Currencies.toScrap(newValue.our.metal) + newValue.our.keys * keyPrices.sell.toValue()
                );
                newValue.our.keys = 0;
                newValue.their.metal = Currencies.toRefined(
                    Currencies.toScrap(newValue.their.metal) + newValue.their.keys * keyPrices.buy.toValue()
                );
                newValue.their.keys = 0;
            } else {
                // Else both use selling key price.
                newValue.our.metal = Currencies.toRefined(
                    Currencies.toScrap(newValue.our.metal) + newValue.our.keys * keyPrices.sell.toValue()
                );
                newValue.our.keys = 0;
                newValue.their.metal = Currencies.toRefined(
                    Currencies.toScrap(newValue.their.metal) + newValue.their.keys * keyPrices.sell.toValue()
                );
                newValue.their.keys = 0;
            }
        }

        diff = Currencies.toScrap(newValue.their.metal) - Currencies.toScrap(newValue.our.metal);
        diffRef = Currencies.toRefined(Math.abs(diff));
        diffKey = Currencies.toCurrencies(
            Math.abs(diff),
            Math.abs(diff) >= keyPrices.sell.metal ? keyPrices.sell.metal : undefined
        ).toString();
    }
    return { diff, diffRef, diffKey };
}


interface ValueDiff {
    diff: number;
    diffRef: number;
    diffKey: string;
}


pagedData => {
      this.page = pagedData.page;
      this.rows = pagedData.data;
    }


@Component({
  selector: 'paging-scrolling-novirtualization-demo',
  providers: [MockServerResultsService],
  template: `

        Server-side Paging

            Source

      <bks-datatable
        class="material"
        [rows]="rows"
        [columns]="[{ name: 'Name' }, { name: 'Gender' }, { name: 'Company' }]"
        [columnMode]="ColumnMode.force"
        [headerHeight]="50"
        [footerHeight]="50"
        rowHeight="auto"
        [scrollbarV]="true"
        [virtualization]="false"
        [externalPaging]="true"
        [count]="page.totalElements"
        [offset]="page.pageNumber"
        [limit]="page.size"
        (page)="setPage($event)"
      >
      </bks-datatable>

  `
})
export class PagingScrollingNoVirtualizationComponent {
  page = new Page();
  rows = new Array<CorporateEmployee>();

  ColumnMode = ColumnMode;

  constructor(private serverResultsService: MockServerResultsService) {
    this.page.pageNumber = 0;
    this.page.size = 20;
  }

  ngOnInit() {
    this.setPage({ offset: 0 });
  }

  /**
   * Populate the table with new data based on the page number
   * @param page The page to select
   */
  setPage(pageInfo) {
    this.page.pageNumber = pageInfo.offset;
    this.serverResultsService.getResults(this.page).subscribe(pagedData => {
      this.page = pagedData.page;
      this.rows = pagedData.data;
    });
  }
}


ngOnInit() {
    this.setPage({ offset: 0 });
  }


/**
   * Populate the table with new data based on the page number
   * @param page The page to select
   */
setPage(pageInfo) {
    this.page.pageNumber = pageInfo.offset;
    this.serverResultsService.getResults(this.page).subscribe(pagedData => {
      this.page = pagedData.page;
      this.rows = pagedData.data;
    });
  }


export interface IInductSqlModel<T> {
    /** [TRANSACTIONS NOT IMPLEMENTED] Starts a knex transaction and stores this in the class instance */
    // startTransaction: () => Promise<knex.Transaction>;
    /** [TRANSACTIONS NOT IMPLEMENTED] Destroys the current knex transaction */
    // destroyConnection: () => Promise<void>;
    /** [TRANSACTIONS NOT IMPLEMENTED] Commits the current knex transaction */
    // commitTransaction: () => Promise<void>;
    /** [TRANSACTIONS NOT IMPLEMENTED] Performs a rollback of the current knex transaction */
    // rollbackTransaction: () => Promise<void>;
    /** Looks for a value based on the provided id_field in the model */
    findOneById?: (lookup?: T[keyof T]) => Promise<T[]>;
    /** Returns all the values in the provided table */
    findAll?: () => Promise<T[]>;
    /** Inserts one value in the provided table */
    create?: (value?: Partial<T>) => Promise<T>;
    /** Deletes one value based on the provided id_field */
    delete?: (lookup?: T[keyof T]) => Promise<T[keyof T]>;
    /** Updates one or more values based on the provided id_field */
    update?: (value?: Partial<T>) => Promise<T | number>;
    /** Checks if a value exists for a column and value */
    exists?: <K extends keyof T>(
        column: keyof T,
        value: T[K]
    ) => Promise<boolean>;
    /** Runs class-validator on the provided model value */
    validate?: () => Promise<ValidationError[]>;
    /** Sets a value in the model data */
    set<K extends keyof T>(prop: K, value: T[K]): void;
    /** Gets a value from the model data */
    get<K extends keyof T>(prop: K): T[K];
}


export interface ValidationResult<T> {
    data: T | T[];
    errors: Error[];
}


export enum FunctionType {
    Query = "query",
    Mutation = "mutation",
}


export type Constructor<T> = new (...any: any[]) => T;


export type ModelFactory<T> = (
    values: T,
    opts: InductModelOpts<T>,
    ...args: unknown[]
) => Promise<InductModel<T>>;


export type ModelFunction<T> = () => Promise<
    T | T[] | number | ValidationResult<T>
>;


export type ModelConstructor<T> = new (...any: any[]) => InductModel<T>;


/** Mark types that do not match the condition type (2nd parameter) as 'never' */
type SubType<Base, Condition> = Pick<
    Base,
    {
        [Key in keyof Base]: Base[Key] extends Condition ? Key : never;
    }[keyof Base]
>;


export type FunctionOfInductModel<T> = keyof Omit<
    SubType<InductModel<T>, Function>,
    InternalFunctions
>;


export type FunctionOfModel<T> = keyof Omit<
    SubType<T, Function>,
    InternalFunctions
>;


export type InternalFunctions =
    | "commitTransaction"
    | "destroyConnection"
    | "startTransaction"
    | "rollbackTransaction"
    | "validate"
    | "con"
    | "trx"
    | "get"
    | "set";


export type TypegooseModel = ReturnType<typeof getModelForClass>;


export interface ProcessEnv {
    NODE_ENV: 'development' | 'production'
    PORT: string
    MAL_CLIENT_ID: string
    MONGO_DB_URI: string
    PLEX_SECTION_TITLE: string
  }


export class TunnelService extends AbstractTunnelService {
	constructor(
		@ILogService logService: ILogService,
		@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService
	) {
		super(logService);
	}

	protected retainOrCreateTunnel(_addressProvider: IAddressProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean): Promise<RemoteTunnel | undefined> | undefined {
		const existing = this.getTunnelFromMap(remoteHost, remotePort);
		if (existing) {
			++existing.refcount;
			return existing.value;
		}

		if (this._tunnelProvider) {
			const preferredLocalPort = localPort === undefined ? remotePort : localPort;
			const tunnelOptions = { remoteAddress: { host: remoteHost, port: remotePort }, localAddressPort: localPort };
			const creationInfo = { elevationRequired: elevateIfNeeded ? isPortPrivileged(preferredLocalPort) : false };
			const tunnel = this._tunnelProvider.forwardPort(tunnelOptions, creationInfo);
			if (tunnel) {
				this.addTunnelToMap(remoteHost, remotePort, tunnel);
			}
			return tunnel;
		}
		return undefined;
	}

	canTunnel(uri: URI): boolean {
		return super.canTunnel(uri) && !!this.environmentService.remoteAuthority;
	}
}


protected retainOrCreateTunnel(_addressProvider: IAddressProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean): Promise<RemoteTunnel | undefined> | undefined {
		const existing = this.getTunnelFromMap(remoteHost, remotePort);
		if (existing) {
			++existing.refcount;
			return existing.value;
		}

		if (this._tunnelProvider) {
			const preferredLocalPort = localPort === undefined ? remotePort : localPort;
			const tunnelOptions = { remoteAddress: { host: remoteHost, port: remotePort }, localAddressPort: localPort };
			const creationInfo = { elevationRequired: elevateIfNeeded ? isPortPrivileged(preferredLocalPort) : false };
			const tunnel = this._tunnelProvider.forwardPort(tunnelOptions, creationInfo);
			if (tunnel) {
				this.addTunnelToMap(remoteHost, remotePort, tunnel);
			}
			return tunnel;
		}
		return undefined;
	}


canTunnel(uri: URI): boolean {
		return super.canTunnel(uri) && !!this.environmentService.remoteAuthority;
	}


() => {
  describe('INIT_CODE_HASH', () => {
    it('matches computed bytecode hash', () => {
      expect(COMPUTED_INIT_CODE_HASH).toEqual(INIT_CODE_HASH)
    })
  })
}


() => {
    it('matches computed bytecode hash', () => {
      expect(COMPUTED_INIT_CODE_HASH).toEqual(INIT_CODE_HASH)
    })
  }


() => {
      expect(COMPUTED_INIT_CODE_HASH).toEqual(INIT_CODE_HASH)
    }


/**
 * A static class that routes URLs within the application.
 */
export interface IRouter {
    /**
     * The base URL for the router.
     */
    readonly base: string;
    /**
     * The command registry used by the router.
     */
    readonly commands: CommandRegistry;
    /**
     * The parsed current URL of the application.
     */
    readonly current: IRouter.ILocation;
    /**
     * A signal emitted when the router routes a route.
     */
    readonly routed: ISignal<IRouter, IRouter.ILocation>;
    /**
     * If a matching rule's command resolves with the `stop` token during routing,
     * no further matches will execute.
     */
    readonly stop: Token<void>;
    /**
     * Navigate to a new path within the application.
     *
     * @param path - The new path or empty string if redirecting to root.
     *
     * @param options - The navigation options.
     */
    navigate(path: string, options?: IRouter.INavOptions): void;
    /**
     * Register a rule that maps a path pattern to a command.
     *
     * @param options - The route registration options.
     *
     * @returns A disposable that removes the registered rule from the router.
     */
    register(options: IRouter.IRegisterOptions): IDisposable;
    /**
     * Cause a hard reload of the document.
     */
    reload(): void;
    /**
     * Route a specific path to an action.
     *
     * @param url - The URL string that will be routed.
     *
     * #### Notes
     * If a pattern is matched, its command will be invoked with arguments that
     * match the `IRouter.ILocation` interface.
     */
    route(url: string): void;
}


/**
     * The parsed location currently being routed.
     */
interface ILocation extends ReadonlyPartialJSONObject {
        /**
         * The location hash.
         */
        hash: string;
        /**
         * The path that matched a routing pattern.
         */
        path: string;
        /**
         * The request being routed with the router `base` omitted.
         *
         * #### Notes
         * This field includes the query string and hash, if they exist.
         */
        request: string;
        /**
         * The search element, including leading question mark (`'?'`), if any,
         * of the path.
         */
        search?: string;
    }


/**
     * The options passed into a navigation request.
     */
interface INavOptions {
        /**
         * Whether the navigation should be hard URL change instead of an HTML
         * history API change.
         */
        hard?: boolean;
    }


/**
     * The specification for registering a route with the router.
     */
interface IRegisterOptions {
        /**
         * The command string that will be invoked upon matching.
         */
        command: string;
        /**
         * The regular expression that will be matched against URLs.
         */
        pattern: RegExp;
        /**
         * The rank order of the registered rule. A lower rank denotes a higher
         * priority. The default rank is `100`.
         */
        rank?: number;
    }


/**
 * A function that handles a connection to the server being lost.
 *
 * #### Notes
 * The default implementation shows a simple dialog upon connection
 * failures, but it may be overridden by extensions to perform other
 * actions.
 */
export declare type IConnectionLost = (manager: ServiceManager.IManager, err: ServerConnection.NetworkError) => Promise<void>;


/**
 * @name - Table tag configuration
 * @description - Configures table tag (assigns row's/column's headers and their respective data types and formats)
 */
export default function TableTagConfig(props: ITableTagConfigProps) {
    const { setTagInputMode = null, addTableTag = null, splitPaneWidth = null } = props;
    const containerWidth = splitPaneWidth > 520 ? splitPaneWidth - 10 : 510;
    const inputTableName = useRef(null);
    const lastColumnInputRef = useRef(null);
    const lastRowInputRef = useRef(null);
    // Initial state
    let table: ITableTagConfigState;
    if (props.tableTag) {
        if (props.tableTag?.type === FieldType.Object) {
            if (props.tableTag.visualizationHint === TableVisualizationHint.Vertical) {
                table = {
                    name: { tableName: props.tableTag.name, originalTableName: props.tableTag.name },
                    type: FieldType.Object,
                    format: FieldFormat.NotSpecified,
                    rows: props.tableTag.fields?.map(row => ({ name: row.fieldKey, type: row.fieldType, format: row.fieldFormat, originalName: row.fieldKey, originalFormat: row.fieldFormat, originalType: row.fieldType })) || [defaultRowOrColumn],
                    columns: props.tableTag?.definition?.fields?.map(col => ({ name: col.fieldKey, type: col.fieldType, format: col.fieldFormat, originalName: col.fieldKey, originalFormat: col.fieldFormat, originalType: col.fieldType })) || [defaultRowOrColumn],
                    headerTypeAndFormat: TableElements.columns,
                    deletedColumns: [],
                    deletedRows: [],
                }

            } else {
                table = {
                    name: { tableName: props.tableTag.name, originalTableName: props.tableTag.name },
                    type: FieldType.Object,
                    format: FieldFormat.NotSpecified,
                    rows: props.tableTag?.definition?.fields?.map(row => ({ name: row.fieldKey, type: row.fieldType, format: row.fieldFormat, originalName: row.fieldKey, originalFormat: row.fieldFormat, originalType: row.fieldType })) || [defaultRowOrColumn],
                    columns: props.tableTag?.fields?.map(col => ({ name: col.fieldKey, type: col.fieldType, format: col.fieldFormat, originalName: col.fieldKey, originalFormat: col.fieldFormat, originalType: col.fieldType })) || [defaultRowOrColumn],
                    headerTypeAndFormat: TableElements.rows,
                    deletedColumns: [],
                    deletedRows: [],
                }
            }
        } else {
            table = {
                name: { tableName: props.tableTag.name, originalTableName: props.tableTag.name },
                type: FieldType.Array,
                format: FieldFormat.NotSpecified,
                rows: [defaultRowOrColumn],
                columns: props.tableTag?.definition?.fields?.map(col => ({ name: col.fieldKey, type: col.fieldType, format: col.fieldFormat, originalName: col.fieldKey, originalFormat: col.fieldFormat, originalType: col.fieldType })),
                headerTypeAndFormat: TableElements.columns,
                deletedColumns: [],
            }
        }

    } else {
        table = {
            name: { tableName: "" },
            type: FieldType.Object,
            format: FieldFormat.NotSpecified,
            rows: [defaultRowOrColumn],
            columns: [defaultRowOrColumn],
            headerTypeAndFormat: TableElements.columns,
        };
    }

    const currentProjectTags = useSelector<ITag[]>((state: IApplicationState) => state.currentProject.tags);
    const [tableTagName, setTableTagName] = useState(table.name);
    const [type, setType] = useState<FieldType.Object | FieldType.Array>(table.type);
    const [columns, setColumns] = useState(table.columns);
    const [rows, setRows] = useState<ITableConfigItem[]>(table.rows);
    const [notUniqueNames, setNotUniqueNames] = useState<{ columns: [], rows: [], tags: boolean }>({ columns: [], rows: [], tags: false });
    const [headersFormatAndType, setHeadersFormatAndType] = useState<TableElements.columns | TableElements.rows>(table.headerTypeAndFormat);
    const [selectedColumn, setSelectedColumn] = useState<IObjectWithKey>(undefined);
    const [selectedRow, setSelectedRow] = useState<IObjectWithKey>(undefined);
    const [deletedColumns, setDeletedColumns] = useState(table.deletedColumns);
    const [deletedRows, setDeletedRows] = useState<ITableConfigItem[]>(table.deletedRows);
    // const [headerTypeAndFormat, setHeaderTypeAndFormat] = useState<string>(table.headerTypeAndFormat);
    const [shouldAutoFocus, setShouldAutoFocus] = useState(null);

    const isCompatibleWithType = (documentCount: number, type: string, newType: string) => {
        return documentCount <= 0 ? true : getTagCategory(type) === getTagCategory(newType);
    }

    function selectColumnType(idx: number, type: string, docCount: number) {
        setColumns(columns.map((col, currIdx) => {
            if (idx === currIdx) {
                if (isCompatibleWithType(docCount, col.originalType, type))
                    return { ...col, type, format: FieldFormat.NotSpecified }
                else {
                    toast.warn(_.capitalize(interpolate(strings.tags.regionTableTags.configureTag.errors.notCompatibleTableColOrRowType, { kind: "column" })));
                    return col;
                }
            } else {
                return col
            }
        }));
    }

    function selectRowType(idx: number, type: string, docCount: number) {
        setRows(rows.map((row, currIdx) => {
            if (idx === currIdx) {
                if (isCompatibleWithType(docCount, row.originalType, type))
                    return { ...row, type, format: FieldFormat.NotSpecified }
                else {
                    toast.warn(_.capitalize(interpolate(strings.tags.regionTableTags.configureTag.errors.notCompatibleTableColOrRowType, { kind: "row" })));
                    return row;
                }
            } else {
                return row
            }
        }));
    }

    function selectColumnFormat(idx: number, format: string) {
        setColumns(columns.map((col, currIdx) => idx === currIdx ? { ...col, format } : col
        ));
    }

    function selectRowFormat(idx: number, format: string) {
        setRows(rows.map((row, currIdx) => idx === currIdx ? { ...row, format } : row
        ));
    }

    const detailListWidth = {
        nameInput: containerWidth * 0.45,
        typeInput: containerWidth * 0.176,
        formatInput: containerWidth * 0.176,
    }

    const columnListColumns: IColumn[] = [
        {
            key: "name",
            name: "name",
            fieldName: "name",
            minWidth: detailListWidth.nameInput,
            isResizable: false,
            onRender: (row, index) => {
                return (
                    <TextField
                        componentRef={(index === columns.length - 1 && index !== 0) ? lastColumnInputRef : null}
                        className={"column-name_input"}
                        theme={getGreenWithWhiteBackgroundTheme()}
                        onChange={(e) => handleTextInput(e.target["value"], TableElements.column, index)}


function selectColumnType(idx: number, type: string, docCount: number) {
        setColumns(columns.map((col, currIdx) => {
            if (idx === currIdx) {
                if (isCompatibleWithType(docCount, col.originalType, type))
                    return { ...col, type, format: FieldFormat.NotSpecified }
                else {
                    toast.warn(_.capitalize(interpolate(strings.tags.regionTableTags.configureTag.errors.notCompatibleTableColOrRowType, { kind: "column" })));
                    return col;
                }
            } else {
                return col
            }
        }));
    }


function selectRowType(idx: number, type: string, docCount: number) {
        setRows(rows.map((row, currIdx) => {
            if (idx === currIdx) {
                if (isCompatibleWithType(docCount, row.originalType, type))
                    return { ...row, type, format: FieldFormat.NotSpecified }
                else {
                    toast.warn(_.capitalize(interpolate(strings.tags.regionTableTags.configureTag.errors.notCompatibleTableColOrRowType, { kind: "row" })));
                    return row;
                }
            } else {
                return row
            }
        }));
    }


function selectColumnFormat(idx: number, format: string) {
        setColumns(columns.map((col, currIdx) => idx === currIdx ? { ...col, format } : col
        ));
    }


function selectRowFormat(idx: number, format: string) {
        setRows(rows.map((row, currIdx) => idx === currIdx ? { ...row, format } : row
        ));
    }


function addColumn() {
        setColumns([...columns, defaultRowOrColumn]);
        setShouldAutoFocus(TableElements.column);
    }


function addRow() {
        setRows([...rows, defaultRowOrColumn]);
        setShouldAutoFocus(TableElements.row);
    }


function handleTextInput(name: string, role: string, index: number) {
        if (role === TableElements.column) {
            setColumns(
                columns.map((column, currIndex) => (index === currIndex)
                    ? { ...column, name }
                    : column)
            );
        } else {
            setRows(
                rows.map((row, currIndex) => (index === currIndex) ?
                    { ...row, name }
                    : row)
            );
        };
    }


function setTableName(name: string) {
        setTableTagName({ ...tableTagName, tableName: name });
    }


// Row/Column headers command bar (reorder, delete)
function getRowsHeaderItems(): IContextualMenuItem[] {
        const currSelectionIndex = rowSelection.getSelectedIndices()[0];
        return [
            {
                key: 'Name',
                text: 'Name',
                className: "list-headers_name",
                style: { width: detailListWidth.nameInput - 122 },
                disabled: true,
            },
            {
                key: 'moveUp',
                text: 'Move up',
                iconOnly: true,
                iconProps: { iconName: 'Up' },
                onClick: (e) => {
                    onReOrder(-1, TableElements.rows)
                },
                disabled: !selectedRow || currSelectionIndex === 0,
            },
            {
                key: 'moveDown',
                text: 'Move down',
                iconOnly: true,
                iconProps: { iconName: 'Down' },
                onClick: (e) => {
                    onReOrder(1, TableElements.rows)
                },
                disabled: !selectedRow! || currSelectionIndex === rows.length - 1,
            },
            {
                key: 'deleteRow',
                text: 'Delete row',
                iconOnly: true,
                iconProps: { iconName: 'Delete' },
                onClick: () => {
                    const selectedRowIndex = rowSelection.getSelectedIndices()[0];
                    if (props.tableTag && rows[selectedRowIndex].originalName) {
                        const deletedRow = Object.assign({}, rows[selectedRowIndex]);
                        deletedRow.name = deletedRow.originalName;
                        deletedRow.format = deletedRow.originalFormat;
                        deletedRow.type = deletedRow.originalType;
                        setDeletedRows([...deletedRows, deletedRow]);
                    }
                    setRows(rows.filter((i, idx) => idx !== rowSelection.getSelectedIndices()[0]))
                },
                disabled: !selectedRow! || rows.length === 1,
            },
            {
                key: 'type',
                text: 'Type',
                className: "list-headers_type",
                style: { width: detailListWidth.typeInput },
                disabled: true,
            },
            {
                key: 'format',
                text: 'Format',
                className: "list-headers_format",
                disabled: true,
            },
        ];
    }


function getColumnsHeaderItems(): IContextualMenuItem[] {
        const currSelectionIndex = columnSelection.getSelectedIndices()[0];

        return [
            {
                key: 'Name',
                text: 'Name',
                className: "list-headers_name",
                style: { width: detailListWidth.nameInput - 120 },
                disabled: true,
                resizable: true,
            },
            {
                key: 'moveUp',
                text: 'Move up',
                iconOnly: true,
                iconProps: { iconName: 'Up' },
                onClick: (e) => {
                    onReOrder(-1, TableElements.columns)

                },
                disabled: !selectedColumn || currSelectionIndex === 0,
            },
            {
                key: 'moveDown',
                text: 'Move down',
                iconOnly: true,
                iconProps: { iconName: 'Down' },
                onClick: (e) => {
                    onReOrder(1, TableElements.columns)
                },
                disabled: !selectedColumn || currSelectionIndex === columns.length - 1,
            },
            {
                key: 'deleteColumn',
                text: 'Delete column',
                iconOnly: true,
                iconProps: { iconName: 'Delete', },
                onClick: () => {
                    const selectedColumnIndex = columnSelection.getSelectedIndices()[0];
                    if (props.tableTag && columns[selectedColumnIndex].originalName) {
                        const deletedColumn = Object.assign({}, columns[selectedColumnIndex]);
                        deletedColumn.name = deletedColumn.originalName
                        deletedColumn.format = deletedColumn.originalFormat;
                        deletedColumn.type = deletedColumn.originalType;
                        setDeletedColumns([...deletedColumns, deletedColumn])
                    }
                    setColumns(columns.filter((i, idx) => idx !== selectedColumnIndex));
                },
                disabled: !selectedColumn || columns.length === 1,
            },
            {
                key: 'type',
                text: 'Type',
                className: "list-headers_type",
                style: { width: detailListWidth.typeInput },
                disabled: true,
            },
            {
                key: 'format',
                text: 'Format',
                className: "list-headers_format",
                disabled: true,
            },
        ];
    }


// Validation //
function getTextInputError(array: any[], rowName: string, index: number) {
        if (!rowName?.length) {
            return strings.tags.regionTableTags.configureTag.errors.emptyName
        } else if (array.length && array.findIndex((item) => (item === index)) !== -1) {
            return strings.tags.regionTableTags.configureTag.errors.notUniqueName;
        } else {
            return undefined;
        }
    }


function checkNameUniqueness(array: ITableConfigItem[], arrayName: string) {
        const namesMap = {};
        let notUniques = [];
        array.forEach((item, idx) => {

            if (item.name && item.name.length) {
                const name = item.name.trim();
                namesMap[name] = namesMap[name] || [];
                namesMap[name].push(idx)
            }
        });

        for (const name in namesMap) {
            if (namesMap[name].length > 1) {
                notUniques = namesMap[name];
            }
        }
        setNotUniqueNames({ ...notUniqueNames, [arrayName]: notUniques })
    }


function trimFieldNames(array: ITableConfigItem[]) {
        return array.map(i => ({ ...i, name: i.name.trim() }));
    }


function save(cleanTableName: string, cleanRows: ITableConfigItem[], cleanColumns: ITableConfigItem[]) {
        const [firstLayerFieldsInput, secondLayerFieldsInput] = getFieldsLayersInput(headersFormatAndType, cleanRows, cleanColumns);
        const definition = getDefinitionLayer(cleanTableName, secondLayerFieldsInput);
        const fieldsLayer = getFieldsLayer(cleanTableName, firstLayerFieldsInput);
        const itemType = getItemType(cleanTableName);
        const visualizationHint = getVisualizationHint(headersFormatAndType);
        const tableTagToAdd = {
            name: cleanTableName,
            type,
            columns: cleanColumns,
            format: FieldFormat.NotSpecified,
            itemType,
            fields: fieldsLayer,
            definition,
            visualizationHint,
        }
        if (type === FieldType.Object) {
            tableTagToAdd[TableElements.rows] = cleanRows;
        }
        addTableTag(tableTagToAdd);
        setTagInputMode(TagInputMode.Basic, null, null);
        toast.success(`Successfully ${props.tableTag ? "reconfigured" : "saved"} "${tableTagName.tableName}" table tag.`, { autoClose: 8000 });
    }


function getItemType(cleanTableName) {
        if (type === FieldType.Object) {
            return null;
        } else {
            return cleanTableName + "_object";
        }
    }


function getFieldsLayersInput(headersFormatAndType, cleanRows, cleanColumns) {
        if (type === FieldType.Object) {
            if (headersFormatAndType === TableElements.columns) {
                return [cleanRows, cleanColumns];
            } else {
                return [cleanColumns, cleanRows];
            }
        } else {
            return [cleanRows, cleanColumns];
        }
    }


function getDefinitionLayer(cleanTableName, secondLayerFieldsInput) {
        return {
            fieldKey: cleanTableName + "_object",
            fieldType: FieldType.Object,
            fieldFormat: FieldFormat.NotSpecified,
            itemType: null,
            fields: secondLayerFieldsInput.map((field) => {
                return {
                    fieldKey: field.name,
                    fieldType: field.type,
                    fieldFormat: field.format,
                    itemType: null,
                    fields: null,
                }
            })
        }
    }


function getVisualizationHint(headersFormatAndType) {
        if (type === FieldType.Object) {
            if (headersFormatAndType === TableElements.columns) {
                return TableVisualizationHint.Vertical;
            } else {
                return TableVisualizationHint.Horizontal;
            }
        } else {
            return null;
        }
    }


function getFieldsLayer(cleanTableName, firstLayerFieldsInput) {
        if (type === FieldType.Object) {
            return firstLayerFieldsInput.map((field) => {
                return {
                    fieldKey: field.name,
                    fieldType: cleanTableName + "_object",
                    fieldFormat: FieldFormat.NotSpecified,
                    itemType: null,
                    fields: null,
                }
            });
        } else {
            return null;
        }
    }


function hasEmptyNames(array: ITableConfigItem[]) {
        return array.find((i) => !i.name.length) !== undefined ? true : false
    }


function getCleanTable() {
        let cleanRows = rows;
        let cleanColumns = columns;
        if (headersFormatAndType === TableElements.columns) {
            cleanRows = rows.map((row) => {
                return {
                    ...row,
                    type: FieldType.String,
                    format: FieldFormat.NotSpecified,
                }
            });
        } else if (headersFormatAndType === TableElements.rows) {
            cleanColumns = columns.map((col) => ({
                ...col,
                type: FieldType.String,
                format: FieldFormat.NotSpecified
            }));
        }
        cleanColumns = trimFieldNames(columns);
        if (type === FieldType.Object) {
            cleanRows = trimFieldNames(rows);
        }
        const cleanTableName = tableTagName.tableName.trim();
        // const cleanOriginalTableName = tableTagName?.originalTableName?.trim();
        return { cleanTableName, cleanRows, cleanColumns };
    }


function validateInput() {
        return !(
            notUniqueNames.rows.length > 0
            || notUniqueNames.columns.length > 0
            || (props.tableTag && notUniqueNames.tags && (tableTagName.tableName !== tableTagName.originalTableName))
            || (notUniqueNames.tags && !props.tableTag)
            || !tableTagName.tableName.length
            || hasEmptyNames(columns)
            || (type === FieldType.Object && hasEmptyNames(rows))
        );
    }


// Reorder items
function onReOrder(displacement: number, role: string) {
        const items = role === TableElements.rows ? [...rows] : [...columns];
        const selection = role === TableElements.rows ? rowSelection : columnSelection;
        const selectedIndex = selection.getSelectedIndices()[0];
        const itemToBeMoved = items[selectedIndex];
        const newIndex = selectedIndex + displacement;
        if (newIndex < 0 || newIndex > items.length - 1) {
            return;
        }

        items.splice(selectedIndex, 1);
        items.splice(newIndex, 0, itemToBeMoved);

        if (role === TableElements.rows) {
            rowSelection.setIndexSelected(newIndex, true, false);
            setRows(items);
        } else {
            columnSelection.setIndexSelected(newIndex, true, true);
            setColumns(items);
        }
    }


function restoreDeletedField(fieldType: TableElements, index: number) {
        let fields;
        let deletedFields;
        let setFields;
        let setDeletedFields;
        switch (fieldType) {
            case TableElements.row:
                fields = rows;
                deletedFields = [...deletedRows];
                setFields = setRows;
                setDeletedFields = setDeletedRows;
                break;
            case TableElements.column:
                fields = columns;
                deletedFields = [...deletedColumns];
                setFields = setColumns;
                setDeletedFields = setDeletedColumns;
                break;
        }
        setFields([...fields, deletedFields[index]]);
        setDeletedFields([...deletedFields].slice(0, index).concat([...deletedFields].slice(index + 1, deletedFields.length)));
    }


function getDeletedFieldsTable(fieldType: TableElements) {
        let deletedFields;
        switch (fieldType) {
            case TableElements.row:
                deletedFields = deletedRows;
                break;
            case TableElements.column:
                deletedFields = deletedColumns;
                break;
        }
        const tableBody = [[

                        {fieldType.charAt(0).toUpperCase() + fieldType.slice(1) + " fields that'll be deleted"}

        ]];
        for (let i = 0; i < deletedFields.length; i++) {
            tableBody.push([
                <tr className="compact-row" key={`row-${i}`}>
                    <td key={`cell-${i}-0`} className="">

                            {deletedFields[i].originalName}

                    <td key={`cell-${i}-1`}


// Table preview
function getTableBody() {
        let tableBody = null;
        const isRowDynamic = type === FieldType.Array;
        if (table.rows.length !== 0 && table.columns.length !== 0) {
            tableBody = [];
            for (let i = 0; i < (isRowDynamic ? 2 : rows.length + 1); i++) {
                const tableRow = [];
                for (let j = 0; j < columns.length + 1; j++) {
                    if (i === 0 && j !== 0) {
                        const columnHeaderWasRenamed = props.tableTag && columns[j - 1].name !== columns[j - 1].originalName;
                        tableRow.push(
                            <th key={`col-h-${j}`} className="header_column">
                                {columnHeaderWasRenamed &&

{columns[j - 1].originalName}

                                }

                                    {columns[j - 1].name}

                            	);
                    } else if (j === 0 && i !== 0) {
                        if (!isRowDynamic) {
                            const rowHeaderWasRenamed = props.tableTag && rows[i - 1].name !== rows[i - 1].originalName;
                            tableRow.push(
                                <th key={`row-h-${j}`} className="header_row">
                                    {rowHeaderWasRenamed &&

                                            {rows[i - 1].originalName}

                                    }

                                        {rows[i - 1].name}

                            );
                        }
                    }


function getTableTagNameErrorMessage(): string {
        if (props.tableTag && tableTagName.tableName.trim() === props.tableTag.name) {
            return "";
        } else if (!tableTagName.tableName.trim().length) {
            return strings.tags.regionTableTags.configureTag.errors.assignTagName
        } else if (notUniqueNames.tags) {
            return strings.tags.regionTableTags.configureTag.errors.notUniqueTagName;
        }
        return "";
    }


(type = FieldType.String) => {
    const options = [];
    const formats = filterFormat(type)
    Object.entries(formats).forEach(([key, value]) => {
        options.push({ key, text: value })
    });

    return options;
}


([key, value]) => {
        options.push({ key, text: value })
    }


() => {
    const options = [];
    Object.entries(FieldType).forEach(([key, value]) => {
        if (value !== FieldType.Object && value !== FieldType.Array) {
            options.push({ key, text: value });
        }
    });
    return options;
}


([key, value]) => {
        if (value !== FieldType.Object && value !== FieldType.Array) {
            options.push({ key, text: value });
        }
    }


row => ({ name: row.fieldKey, type: row.fieldType, format: row.fieldFormat, originalName: row.fieldKey, originalFormat: row.fieldFormat, originalType: row.fieldType })


col => ({ name: col.fieldKey, type: col.fieldType, format: col.fieldFormat, originalName: col.fieldKey, originalFormat: col.fieldFormat, originalType: col.fieldType })


(state: IApplicationState) => state.currentProject.tags


(documentCount: number, type: string, newType: string) => {
        return documentCount <= 0 ? true : getTagCategory(type) === getTagCategory(newType);
    }


(col, currIdx) => {
            if (idx === currIdx) {
                if (isCompatibleWithType(docCount, col.originalType, type))
                    return { ...col, type, format: FieldFormat.NotSpecified }
                else {
                    toast.warn(_.capitalize(interpolate(strings.tags.regionTableTags.configureTag.errors.notCompatibleTableColOrRowType, { kind: "column" })));
                    return col;
                }
            } else {
                return col
            }
        }


(row, currIdx) => {
            if (idx === currIdx) {
                if (isCompatibleWithType(docCount, row.originalType, type))
                    return { ...row, type, format: FieldFormat.NotSpecified }
                else {
                    toast.warn(_.capitalize(interpolate(strings.tags.regionTableTags.configureTag.errors.notCompatibleTableColOrRowType, { kind: "row" })));
                    return row;
                }
            } else {
                return row
            }
        }


(col, currIdx) => idx === currIdx ? { ...col, format } : col


(row, currIdx) => idx === currIdx ? { ...row, format } : row


(row, index) => {
                return (
                    <TextField
                        componentRef={(index === columns.length - 1 && index !== 0) ? lastColumnInputRef : null}


(row, index) => headersFormatAndType === TableElements.columns ?
                <Customizer {...defaultTheme}>
                    <Dropdown
                        style


(row, index) => {
                return (
                    <TextField
                        componentRef={(index === rows.length - 1 && index !== 0) ? lastRowInputRef : null}


(row, index) => headersFormatAndType === TableElements.rows ?
                <Customizer {...defaultTheme}>
                    <Dropdown
                        className


(column, currIndex) => (index === currIndex)
                    ? { ...column, name }
                    : column


(row, currIndex) => (index === currIndex) ?
                    { ...row, name }
                    : row


(e) => {
                    onReOrder(-1, TableElements.rows)
                }


(e) => {
                    onReOrder(1, TableElements.rows)
                }


() => {
                    const selectedRowIndex = rowSelection.getSelectedIndices()[0];
                    if (props.tableTag && rows[selectedRowIndex].originalName) {
                        const deletedRow = Object.assign({}, rows[selectedRowIndex]);
                        deletedRow.name = deletedRow.originalName;
                        deletedRow.format = deletedRow.originalFormat;
                        deletedRow.type = deletedRow.originalType;
                        setDeletedRows([...deletedRows, deletedRow]);
                    }
                    setRows(rows.filter((i, idx) => idx !== rowSelection.getSelectedIndices()[0]))
                }


(i, idx) => idx !== rowSelection.getSelectedIndices()[0]


(e) => {
                    onReOrder(-1, TableElements.columns)

                }


(e) => {
                    onReOrder(1, TableElements.columns)
                }


() => {
                    const selectedColumnIndex = columnSelection.getSelectedIndices()[0];
                    if (props.tableTag && columns[selectedColumnIndex].originalName) {
                        const deletedColumn = Object.assign({}, columns[selectedColumnIndex]);
                        deletedColumn.name = deletedColumn.originalName
                        deletedColumn.format = deletedColumn.originalFormat;
                        deletedColumn.type = deletedColumn.originalType;
                        setDeletedColumns([...deletedColumns, deletedColumn])
                    }
                    setColumns(columns.filter((i, idx) => idx !== selectedColumnIndex));
                }


(i, idx) => idx !== selectedColumnIndex


(item) => (item === index)


(item, idx) => {

            if (item.name && item.name.length) {
                const name = item.name.trim();
                namesMap[name] = namesMap[name] || [];
                namesMap[name].push(idx)
            }
        }


() => {
        if (columns) {
            checkNameUniqueness(debouncedColumns, TableElements.columns)
        }
        // eslint-disable-next-line
    }


() => {
        if (rows) {
            checkNameUniqueness(debouncedRows, TableElements.rows);
        }
        // eslint-disable-next-line
    }


() => {
        if (tableTagName) {
            const existingTagName = currentProjectTags.find((item: ITag) => item.name === tableTagName.tableName.trim());
            setNotUniqueNames({ ...notUniqueNames, tags: existingTagName !== undefined ? true : false })
        }
        // eslint-disable-next-line
    }


(item: ITag) => item.name === tableTagName.tableName.trim()


i => ({ ...i, name: i.name.trim() })


(field) => {
                return {
                    fieldKey: field.name,
                    fieldType: field.type,
                    fieldFormat: field.format,
                    itemType: null,
                    fields: null,
                }
            }


(field) => {
                return {
                    fieldKey: field.name,
                    fieldType: cleanTableName + "_object",
                    fieldFormat: FieldFormat.NotSpecified,
                    itemType: null,
                    fields: null,
                }
            }


(i) => !i.name.length


(row) => {
                return {
                    ...row,
                    type: FieldType.String,
                    format: FieldFormat.NotSpecified,
                }
            }


(col) => ({
                ...col,
                type: FieldType.String,
                format: FieldFormat.NotSpecified
            })


() =>
        new Selection({
            onSelectionChanged: () => {
                setSelectedRow(rowSelection.getSelection()[0])
            }, selectionMode: SelectionMode.single,
        })


() => {
                setSelectedRow(rowSelection.getSelection()[0])
            }


() =>
        new Selection({
            onSelectionChanged: () => {
                setSelectedColumn(columnSelection.getSelection()[0])
            }, selectionMode: SelectionMode.single,
        })


() => {
                setSelectedColumn(columnSelection.getSelection()[0])
            }


() => {
        setTableChanged(
            (_.isEqual(columns, table.columns) && _.isEqual(rows, table.rows)) ? false : true)
    }


() => {
        inputTableName.current.focus();
    }


() => {
        if (shouldAutoFocus === TableElements.column && lastColumnInputRef.current) {
            lastColumnInputRef.current.focus();
        }
        else if (shouldAutoFocus === TableElements.row && lastRowInputRef.current) {
            lastRowInputRef.current.focus();
        }
        setShouldAutoFocus(null);
    }


interface ITableTagConfigProps {
    setTagInputMode: (addTableMode: TagInputMode, selectedTableTagToLabel?: ITableTag, selectedTableTagBody?: ITableRegion[][][]) => void;
    addTableTag: (table: any) => void;
    splitPaneWidth: number;
    tableTag?: ITableTag;
    reconfigureTableConfirm?: (originalTagName: string, tagName: string, tagType: FieldType.Array | FieldType.Object, tagFormat: FieldFormat, visualizationHint: TableVisualizationHint, deletedColumns: ITableConfigItem[], deletedRows: ITableConfigItem[], newRows: ITableConfigItem[], newColumns: ITableConfigItem[]) => void;
    selectedTableBody: ITableRegion[][][];
}


interface ITableTagConfigState {
    rows?: ITableConfigItem[],
    columns: ITableConfigItem[],
    name: {
        tableName: string,
        originalTableName?: string;
    },
    type: FieldType.Object | FieldType.Array,
    format: FieldFormat.NotSpecified,
    headerTypeAndFormat: TableElements.columns | TableElements.rows;
    originalName?: string;
    deletedRows?: ITableConfigItem[],
    deletedColumns?: ITableConfigItem[],
}


interface ITableConfigItem {
    name: string,
    format: string,
    type: string;
    originalName?: string;
    originalFormat?: string,
    originalType?: string;
    documentCount?: number
}


type and format


getGreenWithWhiteBackgroundTheme()


getTextInputError(notUniqueNames


typeOptions()


formatOptions(row


getTableTagNameErrorMessage()


getRightPaneDefaultButtonTheme()


getPrimaryBlueTheme()


getDeletedFieldsTable(TableElements


getTableBody()


getPrimaryGreyTheme()


getPrimaryGreenTheme()


// Type definitions for pad-left 2.1
// Project: https://github.com/jonschlinkert/pad-left
// Definitions by: Richie Bendall <https://github.com/Richienb>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
declare function padLeft(str: string, num?: number, ch?: string): string;


({ theme: { colors, boxShadow, breakpoints, font, mixins } }) => css`
    background-color: ${colors.bgPrimary};
    box-shadow: ${boxShadow.md};
    font-size: ${font.size.sm};
    font-weight: ${font.weight.bold};
    ${mixins.rounded}

    @media (min-width: ${breakpoints.md}) {
      font-size: ${font.size.xl};
    }
  `


function ContentCardEstTokenOnTriggerModal({
  token,
  liquidationPenaltyFormatted,
}: ContentCardEstTokenOnTriggerModalProps) {
  const { t } = useTranslation()

  return (
    <Grid gap={2}>
      <Heading variant="header3">
        {t('manage-multiply-vault.card.max-token-on-stop-loss-trigger', { token })}
      </Heading>
      <Text variant="subheader" sx={{ fontSize: 2, mt: 2 }}