async () => {
            showInputBoxStub.onFirstCall().resolves('["testArg]');
            await vscode.commands.executeCommand(ExtensionCommands.SUBMIT_TRANSACTION);
            logSpy.should.have.been.calledTwice;
            logSpy.should.have.been.calledWith(LogType.ERROR, 'Error with transaction arguments: Unexpected end of JSON input');
            logSpy.should.not.have.been.calledWith(LogType.SUCCESS, 'Successfully submitted transaction');
            reporterStub.should.not.have.been.calledWith('submit transaction');
            dockerLogsOutputSpy.should.not.have.been.called;
        }


async () => {
            showInputBoxStub.onFirstCall().resolves('"testArg]');
            await vscode.commands.executeCommand(ExtensionCommands.SUBMIT_TRANSACTION);
            logSpy.should.have.been.calledTwice;
            logSpy.should.have.been.calledWith(LogType.ERROR, 'Error with transaction arguments: transaction arguments should be in the format ["arg1", {"key" : "value"}]');
            logSpy.should.not.have.been.calledWith(LogType.SUCCESS, 'Successfully submitted transaction');
            reporterStub.should.not.have.been.calledWith('submit transaction');
            dockerLogsOutputSpy.should.not.have.been.called;
        }


async () => {
            showInputBoxStub.onFirstCall().resolves('1');
            await vscode.commands.executeCommand(ExtensionCommands.SUBMIT_TRANSACTION);
            logSpy.should.have.been.calledTwice;
            logSpy.should.have.been.calledWith(LogType.ERROR, 'Error with transaction arguments: transaction arguments should be in the format ["arg1", {"key" : "value"}]');
            logSpy.should.not.have.been.calledWith(LogType.SUCCESS, 'Successfully submitted transaction');
            reporterStub.should.not.have.been.calledWith('submit transaction');
            dockerLogsOutputSpy.should.not.have.been.called;
        }


async () => {
            showInputBoxStub.onFirstCall().resolves(undefined);
            await vscode.commands.executeCommand(ExtensionCommands.SUBMIT_TRANSACTION);
            fabricClientConnectionMock.submitTransaction.should.not.have.been.called;
            showInputBoxStub.should.have.been.calledOnce;
            logSpy.should.not.have.been.calledWith(LogType.SUCCESS, 'Successfully submitted transaction');
            reporterStub.should.not.have.been.calledWith('submit transaction');
            dockerLogsOutputSpy.should.not.have.been.called;
        }


async () => {
            const result: string = '{"hello":"world"}';
            const outputAdapterShowSpy: sinon.SinonSpy = mySandBox.spy(VSCodeBlockchainOutputAdapter.instance(), 'show');
            fabricClientConnectionMock.submitTransaction.resolves(result);
            showInputBoxStub.onFirstCall().resolves('[]');
            await vscode.commands.executeCommand(ExtensionCommands.SUBMIT_TRANSACTION);
            fabricClientConnectionMock.submitTransaction.should.have.been.calledWithExactly('myContract', 'transaction1', 'myChannel', [], 'my-contract', undefined);
            showInputBoxStub.should.have.been.calledTwice;
            logSpy.should.have.been.calledWith(LogType.SUCCESS, 'Successfully submitted transaction', `Returned value from transaction1: ${result}`);
            reporterStub.should.have.been.calledWith('submit transaction');
            dockerLogsOutputSpy.should.not.have.been.called;
            outputAdapterShowSpy.should.have.been.calledOnce;
        }


async () => {
            const result: string = undefined;
            const outputAdapterShowSpy: sinon.SinonSpy = mySandBox.spy(VSCodeBlockchainOutputAdapter.instance(), 'show');
            fabricClientConnectionMock.submitTransaction.resolves(result);
            showInputBoxStub.onFirstCall().resolves('[]');
            await vscode.commands.executeCommand(ExtensionCommands.EVALUATE_TRANSACTION);
            fabricClientConnectionMock.submitTransaction.should.have.been.calledWithExactly('myContract', 'transaction1', 'myChannel', [], 'my-contract', undefined, true);
            showInputBoxStub.should.have.been.calledTwice;
            logSpy.should.have.been.calledWith(LogType.SUCCESS, 'Successfully evaluated transaction', `No value returned from transaction1`);
            reporterStub.should.have.been.calledWith('evaluate transaction');
            dockerLogsOutputSpy.should.not.have.been.called;
            outputAdapterShowSpy.should.have.been.calledOnce;
        }


export async function installDependencies(
  baseDir: string,
  deps: any,
  dev: boolean = false
) {
  const useYarn = shouldUseYarn()
  const isOnline = !useYarn || (await getOnline())

  if (deps.length) {
    console.log()
    console.log(`Installing ${dev ? 'devDependencies' : 'dependencies'}:`)
    for (const dep of deps) {
      console.log(`- ${chalk.cyan(dep.pkg)}`)
    }
    console.log()

    const devInstallFlags = { devDependencies: dev, ...{ useYarn, isOnline } }
    await install(
      path.resolve(baseDir),
      deps.map((dep: MissingDependency) => dep.pkg),
      devInstallFlags
    )
    console.log()
  }
}


(dep: MissingDependency) => dep.pkg


export type Dependencies = {
  resolved: Map<string, string>
}


export declare class MatDatepickerInputEvent<D, S = unknown> {
    /** Reference to the datepicker input component that emitted the event. */
    target: MatDatepickerInputBase<S, D>;
    /** Reference to the native input element associated with the datepicker input. */
    targetElement: HTMLElement;
    /** The new value for the target datepicker input. */
    value: D | null;
    constructor(
    /** Reference to the datepicker input component that emitted the event. */
    target: MatDatepickerInputBase<S, D>,
    /** Reference to the native input element associated with the datepicker input. */
    targetElement: HTMLElement);
}


/** Base class for datepicker inputs. */
export declare abstract class MatDatepickerInputBase<S, D = ExtractDateTypeFromSelection<S>> implements ControlValueAccessor, AfterViewInit, OnChanges, OnDestroy, Validator {
    protected _elementRef: ElementRef<HTMLInputElement>;
    _dateAdapter: DateAdapter<D>;
    private _dateFormats;
    /** Whether the component has been initialized. */
    private _isInitialized;
    /** The value of the input. */
    get value(): D | null;
    set value(value: D | null);
    protected _model: MatDateSelectionModel<S, D> | undefined;
    /** Whether the datepicker-input is disabled. */
    get disabled(): boolean;
    set disabled(value: boolean);
    private _disabled;
    /** Emits when a `change` event is fired on this `<input>`. */
    readonly dateChange: EventEmitter<MatDatepickerInputEvent<D, S>>;
    /** Emits when an `input` event is fired on this `<input>`. */
    readonly dateInput: EventEmitter<MatDatepickerInputEvent<D, S>>;
    /** Emits when the value changes (either due to user input or programmatic change). */
    _valueChange: EventEmitter<D | null>;
    /** Emits when the internal state has changed */
    _stateChanges: Subject<void>;
    _onTouched: () => void;
    _validatorOnChange: () => void;
    protected _cvaOnChange: (value: any) => void;
    private _valueChangesSubscription;
    private _localeSubscription;
    /**
     * Since the value is kept on the model which is assigned in an Input,
     * we might get a value before we have a model. This property keeps track
     * of the value until we have somewhere to assign it.
     */
    private _pendingValue;
    /** The form control validator for whether the input parses. */
    private _parseValidator;
    /** The form control validator for the date filter. */
    private _filterValidator;
    /** The form control validator for the min date. */
    private _minValidator;
    /** The form control validator for the max date. */
    private _maxValidator;
    /** Gets the base validator functions. */
    protected _getValidators(): ValidatorFn[];
    /** Gets the minimum date for the input. Used for validation. */
    abstract _getMinDate(): D | null;
    /** Gets the maximum date for the input. Used for validation. */
    abstract _getMaxDate(): D | null;
    /** Gets the date filter function. Used for validation. */
    protected abstract _getDateFilter(): DateFilterFn<D> | undefined;
    /** Registers a date selection model with the input. */
    _registerModel(model: MatDateSelectionModel<S, D>): void;
    /** Opens the popup associated with the input. */
    protected abstract _openPopup(): void;
    /** Assigns a value to the input's model. */
    protected abstract _assignValueToModel(model: D | null): void;
    /** Converts a value from the model into a native value for the input. */
    protected abstract _getValueFromModel(modelValue: S): D | null;
    /** Combined form control validator for this input. */
    protected abstract _validator: ValidatorFn | null;
    /**
     * Callback that'll be invoked when the selection model is changed
     * from somewhere that's not the current datepicker input.
     */
    protected abstract _outsideValueChanged?: () => void;
    /** Predicate that determines whether we're allowed to emit a particular change event. */
    protected abstract _canEmitChangeEvent(event: DateSelectionModelChange<S>): boolean;
    /** Whether the last value set on the input was valid. */
    protected _lastValueValid: boolean;
    constructor(_elementRef: ElementRef<HTMLInputElement>, _dateAdapter: DateAdapter<D>, _dateFormats: MatDateFormats);
    ngAfterViewInit(): void;
    ngOnChanges(): void;
    ngOnDestroy(): void;
    /** @docs-private */
    registerOnValidatorChange(fn: () => void): void;
    /** @docs-private */
    validate(c: AbstractControl): ValidationErrors | null;
    writeValue(value: D): void;
    registerOnChange(fn: (value: any) => void): void;
    registerOnTouched(fn: () => void): void;
    setDisabledState(isDisabled: boolean): void;
    _onKeydown(event: KeyboardEvent): void;
    _onInput(value: string): void;
    _onChange(): void;
    /** Handles blur events on the input. */
    _onBlur(): void;
    /** Formats a value and sets it on the input element. */
    protected _formatValue(value: D | null): void;
    /**
     * @param obj The object to check.
     * @returns The given object if it is both a date instance and valid, otherwise null.
     */
    protected _getValidDateOrNull(obj: any): D | null;
    /** Assigns a value to the model. */
    private _assignValue;
    /** Whether a value is considered valid. */
    private _isValidValue;
    /**
     * Checks whether a parent control is disabled. This is in place so that it can be overridden
     * by inputs extending this one which can be placed inside of a group that can be disabled.
     */
    protected _parentDisabled(): boolean;
    static ngAcceptInputType_value: any;
    static ngAcceptInputType_disabled: BooleanInput;
    static ɵfac: ɵngcc0.ɵɵFactoryDef<MatDatepickerInputBase<any, any>, [null, { optional: true; }, { optional: true; }]>;
    static ɵdir: ɵngcc0.ɵɵDirectiveDefWithMeta<MatDatepickerInputBase<any, any>, never, never, { "value": "value"; "disabled": "disabled"; }, { "dateChange": "dateChange"; "dateInput": "dateInput"; }, never>;
}


/** Function that can be used to filter out dates from a calendar. */
export declare type DateFilterFn<D> = (date: D | null) => boolean;


/** Gets the base validator functions. */
protected _getValidators(): ValidatorFn[];


/** Gets the minimum date for the input. Used for validation. */
abstract _getMinDate(): D | null;


/** Gets the maximum date for the input. Used for validation. */
abstract _getMaxDate(): D | null;


/** Gets the date filter function. Used for validation. */
protected abstract _getDateFilter(): DateFilterFn<D> | undefined;


/** Registers a date selection model with the input. */
_registerModel(model: MatDateSelectionModel<S, D>): void;


/** Opens the popup associated with the input. */
protected abstract _openPopup(): void;


/** Assigns a value to the input's model. */
protected abstract _assignValueToModel(model: D | null): void;


/** Converts a value from the model into a native value for the input. */
protected abstract _getValueFromModel(modelValue: S): D | null;


/** Predicate that determines whether we're allowed to emit a particular change event. */
protected abstract _canEmitChangeEvent(event: DateSelectionModelChange<S>): boolean;


ngOnChanges(): void;


/** @docs-private */
registerOnValidatorChange(fn: () => void): void;


/** @docs-private */
validate(c: AbstractControl): ValidationErrors | null;


writeValue(value: D): void;


registerOnChange(fn: (value: any) => void): void;


registerOnTouched(fn: () => void): void;


_onKeydown(event: KeyboardEvent): void;


_onInput(value: string): void;


_onChange(): void;


/** Handles blur events on the input. */
_onBlur(): void;


/** Formats a value and sets it on the input element. */
protected _formatValue(value: D | null): void;


/**
     * @param obj The object to check.
     * @returns The given object if it is both a date instance and valid, otherwise null.
     */
protected _getValidDateOrNull(obj: any): D | null;


/**
     * Checks whether a parent control is disabled. This is in place so that it can be overridden
     * by inputs extending this one which can be placed inside of a group that can be disabled.
     */
protected _parentDisabled(): boolean;


() => {
  it.todo("No tests yet")
}


function Bird(props: IconProps) {
  return (
    <Svg
      id="Raw"
      viewBox="0 0 256 256"
      width={props.size}
      height={props.size}
      {...props}
    >
      <Rect width={256} height={256} fill="none" />
      <Circle cx={160} cy={72} r={16} fill={props.color} />
      <Path
        d="M208,96v24a96,96,0,0,1-96,96H12L104,96V76A52.00738,52.00738,0,0,1,206.33275,62.88778L232,80Z"
        fill="none"
        stroke={props.color}
        strokeLinecap="round"
        strokeLinejoin="round"
        strokeWidth={24}
      />
      <Line
        x1={90.66667}
        y1={176}
        x2={121.33333}
        y2={136}
        fill="none"
        stroke={props.color}
        strokeLinecap="round"
        strokeLinejoin="round"
        strokeWidth={24}
      />
    </Svg>
  );
}


({
  state,
  blockId,
  txHash,
  type,
  error,
  txTimestamp,
}) => {
  switch (state) {
    case ETxSenderState.WATCHING_PENDING_TXS:
      return <TxExternalPending txHash={txHash!} blockId={blockId} />;

    case ETxSenderState.INIT:
      if (!type) {
        throw new Error("Transaction type needs to be set at transaction init state");
      }
      return <InitComponent type={type} />;

    case ETxSenderState.SUMMARY:
      if (!type) {
        throw new Error("Transaction type needs to be set at transaction summary state");
      }
      return <SummaryComponent type={type} />;

    case ETxSenderState.ACCESSING_WALLET:
      return (
        <AccessWalletContainer
          title={<FormattedMessage id="modals.tx-sender.confirm-title" />}
          message={<FormattedMessage id="modals.tx-sender.confirm-description" />}


(obj: object): boolean => (Array.isArray(obj) || typeof obj !== 'object')


export function mainNgcc(args: string[]): number {
  const formats = args[0] ? args[0].split(',') : ['fesm2015', 'esm2015', 'fesm5', 'esm5'];
  const packagePaths = args[1] ? [path.resolve(args[1])] : findPackagesToCompile();
  const targetPath = args[2] ? args[2] : 'node_modules';

  const transformer = new PackageTransformer();
  packagePaths.forEach(packagePath => {
    formats.forEach(format => {
      // TODO: remove before flight
      console.warn(`Compiling ${packagePath} : ${format}`);
      transformer.transform(packagePath, format, targetPath);
    });
  });

  return 0;
}


// TODO - consider nested node_modules
/**
 * Check whether the given folder needs to be included in the ngcc compilation.
 * We do not care about folders that are:
 *
 * - symlinks
 * - node_modules
 * - do not contain a package.json
 * - do not have a typings property in package.json
 * - do not have an appropriate metadata.json file
 *
 * @param folderPath The absolute path to the folder.
 */
function hasMetadataFile(folderPath: string): boolean {
  const folderName = path.basename(folderPath);
  if (folderName === 'node_modules' || lstatSync(folderPath).isSymbolicLink()) {
    return false;
  }
  const packageJsonPath = path.join(folderPath, 'package.json');
  if (!existsSync(packageJsonPath)) {
    return false;
  }
  const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
  if (!packageJson.typings) {
    return false;
  }
  // TODO: avoid if packageJson contains built marker
  const metadataPath =
      path.join(folderPath, packageJson.typings.replace(/\.d\.ts$/, '.metadata.json'));
  return existsSync(metadataPath);
}


/**
 * Look for packages that need to be compiled.
 * The function will recurse into folders that start with `@...`, e.g. `@angular/...`.
 * Without an argument it starts at `node_modules`.
 */
function findPackagesToCompile(folder: string = 'node_modules'): string[] {
  const fullPath = path.resolve(folder);
  const packagesToCompile: string[] = [];
  readdirSync(fullPath)
      .filter(p => !p.startsWith('.'))
      .filter(p => lstatSync(path.join(fullPath, p)).isDirectory())
      .forEach(p => {
        const packagePath = path.join(fullPath, p);
        if (p.startsWith('@')) {
          packagesToCompile.push(...findPackagesToCompile(packagePath));
        } else {
          packagesToCompile.push(packagePath);
        }
      });

  return packagesToCompile.filter(path => recursiveDirTest(path, hasMetadataFile));
}


function recursiveDirTest(dir: string, test: (dir: string) => boolean): boolean {
  return test(dir) || readdirSync(dir).some(segment => {
    const fullPath = path.join(dir, segment);
    return lstatSync(fullPath).isDirectory() && recursiveDirTest(fullPath, test);
  });
}


packagePath => {
    formats.forEach(format => {
      // TODO: remove before flight
      console.warn(`Compiling ${packagePath} : ${format}`);
      transformer.transform(packagePath, format, targetPath);
    });
  }


format => {
      // TODO: remove before flight
      console.warn(`Compiling ${packagePath} : ${format}`);
      transformer.transform(packagePath, format, targetPath);
    }


p => !p.startsWith('.')


p => lstatSync(path.join(fullPath, p)).isDirectory()


p => {
        const packagePath = path.join(fullPath, p);
        if (p.startsWith('@')) {
          packagesToCompile.push(...findPackagesToCompile(packagePath));
        } else {
          packagesToCompile.push(packagePath);
        }
      }


path => recursiveDirTest(path, hasMetadataFile)


segment => {
    const fullPath = path.join(dir, segment);
    return lstatSync(fullPath).isDirectory() && recursiveDirTest(fullPath, test);
  }


({ theme }) => theme.orbit.paletteInkLighter


({ theme }) => css`
    color: ${theme.orbit.paletteInkLighter};
  `


() => {
  const theme = useTheme();
  return <div>{theme.orbit.paletteInkLighter}</div>;
}


export class CountryMapper {
  public static toAttrs(obj: any) {
    const attrs: CountryAggregateAttributes = {
      name: obj.name,
      nameEn: obj.nameEn,
      sovereignId: obj.sovereignId,
      population: CountryPopulation.create(obj.population),
      geography: CountryGeography.create(obj.geography),
    }
    return attrs
  }

  public static toDomain(obj: any) {
    const id = obj.id || obj._id
    const attrs = CountryMapper.toAttrs(obj)

    const country = CountryAggregate.create(attrs, id ? EntityId.create(id) : null)
    return country
  }

  public static toPersistence(country: CountryAggregate) {
    return {
      id: country.getEntityId().toString(),
      name: country.name,
    }
  }

  public static toDTO(country: CountryAggregate): ICountryDTO {
    return {
      id: country.getEntityId().toString(),
      name: country.name,
      nameEn: country.nameEn,
      sovereignId: country.sovereignId,
      population: country.population
        ? {
            estimate: country.population.estimate,
            rank: country.population.rank,
            year: country.population.year,
          }
        : null,
      geography: country.geography
        ? {
            region: country.geography.region,
            subRegion: country.geography.subRegion,
            subUnit: country.geography.subUnit,
            sovereignNation: country.geography.sovereignNation,
          }
        : null,
    }
  }
}


public static toAttrs(obj: any) {
    const attrs: CountryAggregateAttributes = {
      name: obj.name,
      nameEn: obj.nameEn,
      sovereignId: obj.sovereignId,
      population: CountryPopulation.create(obj.population),
      geography: CountryGeography.create(obj.geography),
    }
    return attrs
  }


public static toDomain(obj: any) {
    const id = obj.id || obj._id
    const attrs = CountryMapper.toAttrs(obj)

    const country = CountryAggregate.create(attrs, id ? EntityId.create(id) : null)
    return country
  }


public static toPersistence(country: CountryAggregate) {
    return {
      id: country.getEntityId().toString(),
      name: country.name,
    }
  }


public static toDTO(country: CountryAggregate): ICountryDTO {
    return {
      id: country.getEntityId().toString(),
      name: country.name,
      nameEn: country.nameEn,
      sovereignId: country.sovereignId,
      population: country.population
        ? {
            estimate: country.population.estimate,
            rank: country.population.rank,
            year: country.population.year,
          }
        : null,
      geography: country.geography
        ? {
            region: country.geography.region,
            subRegion: country.geography.subRegion,
            subUnit: country.geography.subUnit,
            sovereignNation: country.geography.sovereignNation,
          }
        : null,
    }
  }


() => NbCellIrisAnalyticsComponent


(observer) => {
      const interlvaId = setInterval(() => {
        if (this.iframe) {
          clearInterval(interlvaId);
          observer.next(this.iframe);
          observer.complete();
        }
      }, 100);
    }


() => {
        if (this.iframe) {
          clearInterval(interlvaId);
          observer.next(this.iframe);
          observer.complete();
        }
      }


iframe => {
      iframe.nativeElement.src = this._value.content;
    }


@Component({
  selector: 'app-nb-cell-iris-analytics',
  templateUrl: './nb-cell-iris-analytics.component.html',
  styleUrls: ['./nb-cell-iris-analytics.component.scss'],
  providers: [CUSTOM_VALUE_ACCESSOR]
})
export class NbCellIrisAnalyticsComponent extends NbCellComponent implements OnInit {

  @ViewChild('iframe', { static: false })
  public iframe: ElementRef;

  constructor() {
    super();
  }

  ngOnInit(): void {
  }

  getIFrame(): Observable<ElementRef> {
    return Observable.create((observer) => {
      const interlvaId = setInterval(() => {
        if (this.iframe) {
          clearInterval(interlvaId);
          observer.next(this.iframe);
          observer.complete();
        }
      }, 100);
    });
  }

  writeValue(obj: any): void {
    super.writeValue(obj);
    this.getIFrame().subscribe(iframe => {
      iframe.nativeElement.src = this._value.content;
    });
  }

  onSourceCtrlEnter(event: KeyboardEvent) {
    super.onSourceCtrlEnter(event);
    this.getIFrame().subscribe(iframe => {
      iframe.nativeElement.src = this._value.content;
    });
  }

}


getIFrame(): Observable<ElementRef> {
    return Observable.create((observer) => {
      const interlvaId = setInterval(() => {
        if (this.iframe) {
          clearInterval(interlvaId);
          observer.next(this.iframe);
          observer.complete();
        }
      }, 100);
    });
  }


writeValue(obj: any): void {
    super.writeValue(obj);
    this.getIFrame().subscribe(iframe => {
      iframe.nativeElement.src = this._value.content;
    });
  }


onSourceCtrlEnter(event: KeyboardEvent) {
    super.onSourceCtrlEnter(event);
    this.getIFrame().subscribe(iframe => {
      iframe.nativeElement.src = this._value.content;
    });
  }


params => {
        this.scenarioId = params.get('id');
        this.characters = this.scenarioService.getScenarioCharacters(this.scenarioId);
      }


@Component({
  selector: 'amd-scenario-active',
  templateUrl: './scenario-active.component.html',
})
export class ScenarioActiveComponent implements OnInit {
  characters: Promise<Character[]>;
  scenarioId: string;

  constructor(private route: ActivatedRoute, private scenarioService: ScenarioService) { }

  async ngOnInit() {
    this.route.paramMap.pipe(take(1)).subscribe(params => {
        this.scenarioId = params.get('id');
        this.characters = this.scenarioService.getScenarioCharacters(this.scenarioId);
      }
    );
  }

}


async ngOnInit() {
    this.route.paramMap.pipe(take(1)).subscribe(params => {
        this.scenarioId = params.get('id');
        this.characters = this.scenarioService.getScenarioCharacters(this.scenarioId);
      }
    );
  }


(props: AntdIconProps, context: SetupContext) => {
  const p = { ...props, ...context.attrs };
  return <AntdIcon {...p} icon={FridgeLineSvg}></AntdIcon>;
}


(resolve, reject) => {
            this._image = new Image();
            this._image.className = "f-none w-100";

            this._image.onload = () => {
                resolve();
            };
            this._image.src = this._src;
        }


() => {
                resolve();
            }


export class Backer implements IBacker {
    private _site: HTMLElement;

    private _src: string;
    private _image: HTMLImageElement;

    constructor(site: HTMLElement, src: string) {
        this._site = site;
        this._src = src;
    }

    get site(): HTMLElement {
        return this._site;
    }

    get image(): HTMLImageElement {
        return this._image;
    }

    enter(): Promise<void> {
        return Promise.resolve();
    }

    exit(): Promise<void> {
        return Promise.resolve();
    }

    loadAssets(): Promise<void> {
        var p: Promise<void> = new Promise<void>((resolve, reject) => {
            this._image = new Image();
            this._image.className = "f-none w-100";

            this._image.onload = () => {
                resolve();
            };
            this._image.src = this._src;
        });

        return p;
    }
}


enter(): Promise<void> {
        return Promise.resolve();
    }


exit(): Promise<void> {
        return Promise.resolve();
    }


loadAssets(): Promise<void> {
        var p: Promise<void> = new Promise<void>((resolve, reject) => {
            this._image = new Image();
            this._image.className = "f-none w-100";

            this._image.onload = () => {
                resolve();
            };
            this._image.src = this._src;
        });

        return p;
    }


(Client: any, config: any, components: any) => {
  const ca = components.clientAction.factory;

  Client.prototype.slm = components.clientAction.namespaceFactory();
  const slm = Client.prototype.slm.prototype;

  slm.policies = ca({
    urls: [
      {
        fmt: '/_slm/policy',
      },
    ],
    method: 'GET',
  });

  slm.policy = ca({
    urls: [
      {
        fmt: '/_slm/policy/<%=name%>',
        req: {
          name: {
            type: 'string',
          },
        },
      },
    ],
    method: 'GET',
  });

  slm.deletePolicy = ca({
    urls: [
      {
        fmt: '/_slm/policy/<%=name%>',
        req: {
          name: {
            type: 'string',
          },
        },
      },
    ],
    method: 'DELETE',
  });

  slm.executePolicy = ca({
    urls: [
      {
        fmt: '/_slm/policy/<%=name%>/_execute',
        req: {
          name: {
            type: 'string',
          },
        },
      },
    ],
    method: 'PUT',
  });

  slm.updatePolicy = ca({
    urls: [
      {
        fmt: '/_slm/policy/<%=name%>',
        req: {
          name: {
            type: 'string',
          },
        },
      },
    ],
    method: 'PUT',
  });
}


/**
 * Clean HTML after removeFormat and insertHorizontalRule command
 */
export declare class cleanHtml extends Plugin {
    /** @override */
    buttons: Plugin['buttons'];
    /** @override */
    protected afterInit(jodit: IJodit): void;
    /**
     * Replaces an element with a newer one if specified in the configuration match
     */
    private replaceIfMatched;
    /**
     * Clean HTML code on every change
     */
    private onChangeCleanHTML;
    private allowEdit;
    private visitNode;
    private static getHash;
    private allowTagsHash;
    private denyTagsHash;
    /**
     * Remove invisible chars if node has another chars
     */
    private onKeyUpCleanUp;
    private beforeCommand;
    /**
     * Command: removeFormat
     */
    private onRemoveFormat;
    /**
     * For collapsed selection move cursor outside or split inline block
     */
    private removeFormatForCollapsedSelection;
    /**
     * Element has inline display mode
     */
    private isInlineBlock;
    /**
     * Remove formatting for all selected elements
     */
    private removeFormatForSelection;
    private isRemovableNode;
    private static hasNotEmptyTextSibling;
    /**
     * Event handler when manually assigning a value to the HTML editor.
     */
    protected onBeforeSetNativeEditorValue(data: {
        value: string;
    }): boolean;
    protected onSafeHTML(sandBox: HTMLElement): void;
    /** @override */
    protected beforeDestruct(): void;
}


interface Config {
        cleanHTML: {
            timeout: number;
            /**
             * Replace &nbsp; toWYSIWYG plain space
             */
            replaceNBSP: boolean;
            fillEmptyParagraph: boolean;
            removeEmptyElements: boolean;
            replaceOldTags: IDictionary<HTMLTagNames> | false;
            /**
             * Remove onError attributes
             */
            removeOnError: boolean;
            /**
             * Safe href="javascript:" links
             */
            safeJavaScriptLink: boolean;
            /**
             * The allowTags option defines which elements will remain in the
             * edited text when the editor saves. You can use this limit the returned HTML.
             * @example
             * ```javascript
             * var jodit = new Jodit('#editor', {
             *    cleanHTML: {
             *       cleanOnPaste: false
             *    }
             * });
             * ```
             * @example
             * ```javascript
             * var editor = Jodit('#editor', {
             *     cleanHTML: {
             *         allowTags: 'p,a[href],table,tr,td, img[src=1.png]' // allow only <p>,<a>,<table>,<tr>,<td>,<img> tags and
             *         for <a> allow only `href` attribute and <img> allow only `src` attribute == '1.png'
             *     }
             * });
             * editor.value = 'Sorry! <strong>Goodby</strong>\
             * <span>mr.</span> <a style="color:red" href="http://xdsoft.net">Freeman</a>';
             * console.log(editor.value); //Sorry! <a href="http://xdsoft.net">Freeman</a>
             * ```
             *
             * @example
             * ```javascript
             * var editor = Jodit('#editor', {
             *     cleanHTML: {
             *         allowTags: {
             *             p: true,
             *             a: {
             *                 href: true
             *             },
             *             table: true,
             *             tr: true,
             *             td: true,
             *             img: {
             *                 src: '1.png'
             *             }
             *         }
             *     }
             * });
             * ```
             */
            allowTags: false | string | IDictionary<string>;
            denyTags: false | string | IDictionary<string>;
        };
    }


/** @override */
protected afterInit(jodit: IJodit): void;


/**
     * Event handler when manually assigning a value to the HTML editor.
     */
protected onBeforeSetNativeEditorValue(data: {
        value: string;
    }): boolean;


protected onSafeHTML(sandBox: HTMLElement): void;


/** @override */
protected beforeDestruct(): void;


export class AuthedResponseSpec extends Spec {
  override createExam(report: Report, name: string, options: TestOptions): WarpExam {
    return new WarpExam(report, this, name, options);
  }

  @Test
  parseAuthed(exam: WarpExam): void {
    exam.parses("@authed", AuthedResponse.create());
  }

  @Test
  parseAuthedWithBody(exam: WarpExam): void {
    exam.parses("@authed@test", AuthedResponse.create(Record.of(Attr.of("test"))));
  }

  @Test
  writeAuthed(exam: WarpExam): void {
    exam.writes(AuthedResponse.create(), "@authed");
  }

  @Test
  writeAuthedWithBody(exam: WarpExam): void {
    exam.writes(AuthedResponse.create(Record.of(Attr.of("test"))), "@authed@test");
  }
}


override createExam(report: Report, name: string, options: TestOptions): WarpExam {
    return new WarpExam(report, this, name, options);
  }


@Test
  parseAuthed(exam: WarpExam): void {
    exam.parses("@authed", AuthedResponse.create());
  }


@Test
  parseAuthedWithBody(exam: WarpExam): void {
    exam.parses("@authed@test", AuthedResponse.create(Record.of(Attr.of("test"))));
  }


@Test
  writeAuthed(exam: WarpExam): void {
    exam.writes(AuthedResponse.create(), "@authed");
  }


@Test
  writeAuthedWithBody(exam: WarpExam): void {
    exam.writes(AuthedResponse.create(Record.of(Attr.of("test"))), "@authed@test");
  }


(
  config: FontSizePluginConfig,
  element: Element,
  children: JSX.Element
) => {
  const { fontSize } = element;
  if (!fontSize) {
    return children;
  }
  return React.cloneElement(children, {
    style: {
      ...(children && children.props && children.props.style),
      fontSize:
        (config.fontSizesStyle && config.fontSizesStyle[fontSize]) || fontSize,
    },
  });
}


/**
 * ObjectMap is just syntactic sugar to easily use maps in typescript without weird curly braces everywhere.
 * @type ObjectMap
 */
type Map<T> = {[s:string]: T}


export type ObjectMap = Map<Object>


props => {
  const { className, ...rest } = props
  return (
    <div className={sc('header', { extra: className })} {...rest}>
      {props.children}
    </div>


interface Props extends React.HTMLAttributes<HTMLElement> {}


sc('header', { extra: className })


(d) => {
			if (d.options.isWholeLine) {
				return true;
			}

			const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
			const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
			if (startColumn > anchor.range.startColumn || anchor.range.endColumn > endColumn) {
				return false;
			}
			return true;
		}


p => this._computeAsync(p, lineDecorations, anchor, token)


(e: IKeyboardEvent) => {
			if (e.equals(KeyCode.Escape)) {
				this.hide();
			}
		}


(e: ConfigurationChangedEvent) => {
			if (e.hasChanged(EditorOption.fontInfo)) {
				this._updateFont();
			}
		}


() => this.layout()


result => this._withResult(result, true)


result => this._withResult(result, false)


() => {
			if (this._colorPicker) {
				this.getDomNode().classList.add('colorpicker-hover');
			}
		}


() => {
			this.getDomNode().classList.remove('colorpicker-hover');
		}


() => {
			this._hoverOperation.setHoverTime(this._editor.getOption(EditorOption.hover).delay);
		}


() => {
			if (this._isVisible && this._lastAnchor && this._messages.length > 0) {
				this._hover.contentsDomNode.textContent = '';
				this._renderMessages(this._lastAnchor, this._messages);
			}
		}


className => className.startsWith('ced-colorBox')


(a, b) => b.priority - a.priority


node => this._editor.applyFontInfo(node)


(m) => m.isValidForHoverAnchor(anchor)


() => {
				// Give commands a chance to see the key
				if (!this._isVisible) {
					this._hoverVisibleKey.set(false);
				}
			}


class EditorHoverStatusBar extends Disposable implements IEditorHoverStatusBar {

	public readonly hoverElement: HTMLElement;
	private readonly actionsElement: HTMLElement;
	private _hasContent: boolean = false;

	public get hasContent() {
		return this._hasContent;
	}

	constructor(
		@IKeybindingService private readonly _keybindingService: IKeybindingService,
	) {
		super();
		this.hoverElement = $('div.hover-row.status-bar');
		this.actionsElement = dom.append(this.hoverElement, $('div.actions'));
	}

	public addAction(actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): IEditorHoverAction {
		const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);
		const keybindingLabel = keybinding ? keybinding.getLabel() : null;
		this._hasContent = true;
		return this._register(HoverAction.render(this.actionsElement, actionOptions, keybindingLabel));
	}

	public append(element: HTMLElement): HTMLElement {
		const result = dom.append(this.actionsElement, element);
		this._hasContent = true;
		return result;
	}
}


class ModesContentComputer implements IHoverComputer<IHoverPart[]> {

	private readonly _editor: ICodeEditor;
	private _result: IHoverPart[];
	private _anchor: HoverAnchor | null;

	constructor(
		editor: ICodeEditor,
		private readonly _participants: readonly IEditorHoverParticipant[]
	) {
		this._editor = editor;
		this._result = [];
		this._anchor = null;
	}

	public setAnchor(anchor: HoverAnchor): void {
		this._anchor = anchor;
		this._result = [];
	}

	public clearResult(): void {
		this._result = [];
	}

	private static _getLineDecorations(editor: IActiveCodeEditor, anchor: HoverAnchor): IModelDecoration[] {
		if (anchor.type !== HoverAnchorType.Range) {
			return [];
		}

		const model = editor.getModel();
		const lineNumber = anchor.range.startLineNumber;
		const maxColumn = model.getLineMaxColumn(lineNumber);
		return editor.getLineDecorations(lineNumber).filter((d) => {
			if (d.options.isWholeLine) {
				return true;
			}

			const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
			const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
			if (startColumn > anchor.range.startColumn || anchor.range.endColumn > endColumn) {
				return false;
			}
			return true;
		});
	}

	public async computeAsync(token: CancellationToken): Promise<IHoverPart[]> {
		const anchor = this._anchor;

		if (!this._editor.hasModel() || !anchor) {
			return Promise.resolve([]);
		}

		const lineDecorations = ModesContentComputer._getLineDecorations(this._editor, anchor);

		const allResults = await Promise.all(this._participants.map(p => this._computeAsync(p, lineDecorations, anchor, token)));
		return flatten(allResults);
	}

	private async _computeAsync(participant: IEditorHoverParticipant, lineDecorations: IModelDecoration[], anchor: HoverAnchor, token: CancellationToken): Promise<IHoverPart[]> {
		if (!participant.computeAsync) {
			return [];
		}
		return participant.computeAsync(anchor, lineDecorations, token);
	}

	public computeSync(): IHoverPart[] {
		if (!this._editor.hasModel() || !this._anchor) {
			return [];
		}

		const lineDecorations = ModesContentComputer._getLineDecorations(this._editor, this._anchor);

		let result: IHoverPart[] = [];
		for (const participant of this._participants) {
			result = result.concat(participant.computeSync(this._anchor, lineDecorations));
		}

		return coalesce(result);
	}

	public onResult(result: IHoverPart[], isFromSynchronousComputation: boolean): void {
		// Always put synchronous messages before asynchronous ones
		if (isFromSynchronousComputation) {
			this._result = result.concat(this._result);
		} else {
			this._result = this._result.concat(result);
		}
	}

	public getResult(): IHoverPart[] {
		return this._result.slice(0);
	}

	public getResultWithLoadingMessage(): IHoverPart[] {
		if (this._anchor) {
			for (const participant of this._participants) {
				if (participant.createLoadingMessage) {
					const loadingMessage = participant.createLoadingMessage(this._anchor);
					if (loadingMessage) {
						return this._result.slice(0).concat([loadingMessage]);
					}
				}
			}
		}
		return this._result.slice(0);
	}
}


public addAction(actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): IEditorHoverAction {
		const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);
		const keybindingLabel = keybinding ? keybinding.getLabel() : null;
		this._hasContent = true;
		return this._register(HoverAction.render(this.actionsElement, actionOptions, keybindingLabel));
	}


public append(element: HTMLElement): HTMLElement {
		const result = dom.append(this.actionsElement, element);
		this._hasContent = true;
		return result;
	}


public setAnchor(anchor: HoverAnchor): void {
		this._anchor = anchor;
		this._result = [];
	}


public clearResult(): void {
		this._result = [];
	}


private static _getLineDecorations(editor: IActiveCodeEditor, anchor: HoverAnchor): IModelDecoration[] {
		if (anchor.type !== HoverAnchorType.Range) {
			return [];
		}

		const model = editor.getModel();
		const lineNumber = anchor.range.startLineNumber;
		const maxColumn = model.getLineMaxColumn(lineNumber);
		return editor.getLineDecorations(lineNumber).filter((d) => {
			if (d.options.isWholeLine) {
				return true;
			}

			const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
			const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
			if (startColumn > anchor.range.startColumn || anchor.range.endColumn > endColumn) {
				return false;
			}
			return true;
		});
	}


public async computeAsync(token: CancellationToken): Promise<IHoverPart[]> {
		const anchor = this._anchor;

		if (!this._editor.hasModel() || !anchor) {
			return Promise.resolve([]);
		}

		const lineDecorations = ModesContentComputer._getLineDecorations(this._editor, anchor);

		const allResults = await Promise.all(this._participants.map(p => this._computeAsync(p, lineDecorations, anchor, token)));
		return flatten(allResults);
	}


private async _computeAsync(participant: IEditorHoverParticipant, lineDecorations: IModelDecoration[], anchor: HoverAnchor, token: CancellationToken): Promise<IHoverPart[]> {
		if (!participant.computeAsync) {
			return [];
		}
		return participant.computeAsync(anchor, lineDecorations, token);
	}


public computeSync(): IHoverPart[] {
		if (!this._editor.hasModel() || !this._anchor) {
			return [];
		}

		const lineDecorations = ModesContentComputer._getLineDecorations(this._editor, this._anchor);

		let result: IHoverPart[] = [];
		for (const participant of this._participants) {
			result = result.concat(participant.computeSync(this._anchor, lineDecorations));
		}

		return coalesce(result);
	}


public onResult(result: IHoverPart[], isFromSynchronousComputation: boolean): void {
		// Always put synchronous messages before asynchronous ones
		if (isFromSynchronousComputation) {
			this._result = result.concat(this._result);
		} else {
			this._result = this._result.concat(result);
		}
	}


public getResult(): IHoverPart[] {
		return this._result.slice(0);
	}


public getResultWithLoadingMessage(): IHoverPart[] {
		if (this._anchor) {
			for (const participant of this._participants) {
				if (participant.createLoadingMessage) {
					const loadingMessage = participant.createLoadingMessage(this._anchor);
					if (loadingMessage) {
						return this._result.slice(0).concat([loadingMessage]);
					}
				}
			}
		}
		return this._result.slice(0);
	}


public override dispose(): void {
		this._hoverOperation.cancel();
		this._editor.removeContentWidget(this);
		super.dispose();
	}


public getId(): string {
		return this._id;
	}


public getDomNode(): HTMLElement {
		return this._hover.containerDomNode;
	}


private _shouldShowAt(mouseEvent: IEditorMouseEvent): boolean {
		const targetType = mouseEvent.target.type;
		if (targetType === MouseTargetType.CONTENT_TEXT) {
			return true;
		}

		if (targetType === MouseTargetType.CONTENT_EMPTY) {
			const epsilon = this._editor.getOption(EditorOption.fontInfo).typicalHalfwidthCharacterWidth / 2;
			const data = <IEmptyContentData>mouseEvent.target.detail;
			if (data && !data.isAfterLines && typeof data.horizontalDistanceToText === 'number' && data.horizontalDistanceToText < epsilon) {
				// Let hover kick in even when the mouse is technically in the empty area after a line, given the distance is small enough
				return true;
			}
		}

		return false;
	}


public maybeShowAt(mouseEvent: IEditorMouseEvent): boolean {
		const anchorCandidates: HoverAnchor[] = [];

		for (const participant of this._participants) {
			if (typeof participant.suggestHoverAnchor === 'function') {
				const anchor = participant.suggestHoverAnchor(mouseEvent);
				if (anchor) {
					anchorCandidates.push(anchor);
				}
			}
		}

		if (this._shouldShowAt(mouseEvent) && mouseEvent.target.range) {
			// TODO@rebornix. This should be removed if we move Color Picker out of Hover component.
			// Check if mouse is hovering on color decorator
			const hoverOnColorDecorator = [...mouseEvent.target.element?.classList.values() || []].find(className => className.startsWith('ced-colorBox'))
				&& mouseEvent.target.range.endColumn - mouseEvent.target.range.startColumn === 1;
			const showAtRange = (
				hoverOnColorDecorator // shift the mouse focus by one as color decorator is a `before` decoration of next character.
					? new Range(mouseEvent.target.range.startLineNumber, mouseEvent.target.range.startColumn + 1, mouseEvent.target.range.endLineNumber, mouseEvent.target.range.endColumn + 1)
					: mouseEvent.target.range
			);
			anchorCandidates.push(new HoverRangeAnchor(0, showAtRange));
		}

		if (anchorCandidates.length === 0) {
			return false;
		}

		anchorCandidates.sort((a, b) => b.priority - a.priority);
		this._startShowingAt(anchorCandidates[0], HoverStartMode.Delayed, false);

		return true;
	}


private _showAt(position: Position, range: Range | null, focus: boolean): void {
		// Position has changed
		this._showAtPosition = position;
		this._showAtRange = range;
		this._hoverVisibleKey.set(true);
		this._isVisible = true;
		this._hover.containerDomNode.classList.toggle('hidden', !this._isVisible);

		this._editor.layoutContentWidget(this);
		// Simply force a synchronous render on the editor
		// such that the widget does not really render with left = '0px'
		this._editor.render();
		this._stoleFocus = focus;
		if (focus) {
			this._hover.containerDomNode.focus();
		}
	}


public getPosition(): IContentWidgetPosition | null {
		if (this._isVisible) {
			return {
				position: this._showAtPosition,
				range: this._showAtRange,
				preference: [
					ContentWidgetPositionPreference.ABOVE,
					ContentWidgetPositionPreference.BELOW
				]
			};
		}
		return null;
	}


private _updateFont(): void {
		const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code'));
		codeClasses.forEach(node => this._editor.applyFontInfo(node));
	}


private _updateContents(node: Node): void {
		this._hover.contentsDomNode.textContent = '';
		this._hover.contentsDomNode.appendChild(node);
		this._updateFont();

		this._editor.layoutContentWidget(this);
		this._hover.onContentsChanged();
	}


private layout(): void {
		const height = Math.max(this._editor.getLayoutInfo().height / 4, 250);
		const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo);

		this._hover.contentsDomNode.style.fontSize = `${fontSize}px`;
		this._hover.contentsDomNode.style.lineHeight = `${lineHeight}px`;
		this._hover.contentsDomNode.style.maxHeight = `${height}px`;
		this._hover.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`;
	}


public onModelDecorationsChanged(): void {
		if (this._isChangingDecorations) {
			return;
		}
		if (this._isVisible) {
			// The decorations have changed and the hover is visible,
			// we need to recompute the displayed text
			this._hoverOperation.cancel();
			this._computer.clearResult();

			if (!this._colorPicker) { // TODO@Michel ensure that displayed text for other decorations is computed even if color picker is in place
				this._hoverOperation.start(HoverStartMode.Delayed);
			}
		}
	}


public startShowingAtRange(range: Range, mode: HoverStartMode, focus: boolean): void {
		this._startShowingAt(new HoverRangeAnchor(0, range), mode, focus);
	}


private _startShowingAt(anchor: HoverAnchor, mode: HoverStartMode, focus: boolean): void {
		if (this._lastAnchor && this._lastAnchor.equals(anchor)) {
			// We have to show the widget at the exact same range as before, so no work is needed
			return;
		}

		this._hoverOperation.cancel();

		if (this._isVisible) {
			// The range might have changed, but the hover is visible
			// Instead of hiding it completely, filter out messages that are still in the new range and
			// kick off a new computation
			if (!this._showAtPosition || !this._lastAnchor || !anchor.canAdoptVisibleHover(this._lastAnchor, this._showAtPosition)) {
				this.hide();
			} else {
				const filteredMessages = this._messages.filter((m) => m.isValidForHoverAnchor(anchor));
				if (filteredMessages.length === 0) {
					this.hide();
				} else if (filteredMessages.length === this._messages.length) {
					// no change
					return;
				} else {
					this._renderMessages(anchor, filteredMessages);
				}
			}
		}

		this._lastAnchor = anchor;
		this._computer.setAnchor(anchor);
		this._shouldFocus = focus;
		this._hoverOperation.start(mode);
	}


public hide(): void {
		this._lastAnchor = null;
		this._hoverOperation.cancel();

		if (this._isVisible) {
			setTimeout(() => {
				// Give commands a chance to see the key
				if (!this._isVisible) {
					this._hoverVisibleKey.set(false);
				}
			}, 0);
			this._isVisible = false;
			this._hover.containerDomNode.classList.toggle('hidden', !this._isVisible);

			this._editor.layoutContentWidget(this);
			if (this._stoleFocus) {
				this._editor.focus();
			}
		}

		this._isChangingDecorations = true;
		this._highlightDecorations = this._editor.deltaDecorations(this._highlightDecorations, []);
		this._isChangingDecorations = false;
		if (this._renderDisposable) {
			this._renderDisposable.dispose();
			this._renderDisposable = null;
		}
		this._colorPicker = null;
	}


public isColorPickerVisible(): boolean {
		return !!this._colorPicker;
	}


public setColorPicker(widget: ColorPickerWidget): void {
		this._colorPicker = widget;
	}


public onContentsChanged(): void {
		this._hover.onContentsChanged();
	}


private _withResult(result: IHoverPart[], complete: boolean): void {
		this._messages = result;

		if (this._lastAnchor && this._messages.length > 0) {
			this._renderMessages(this._lastAnchor, this._messages);
		} else if (complete) {
			this.hide();
		}
	}


private _renderMessages(anchor: HoverAnchor, messages: IHoverPart[]): void {
		if (this._renderDisposable) {
			this._renderDisposable.dispose();
			this._renderDisposable = null;
		}
		this._colorPicker = null as ColorPickerWidget | null; // TODO: TypeScript thinks this is always null

		// update column from which to show
		let renderColumn = Constants.MAX_SAFE_SMALL_INTEGER;
		let highlightRange: Range = messages[0].range;
		let forceShowAtRange: Range | null = null;
		let fragment = document.createDocumentFragment();

		const disposables = new DisposableStore();
		const hoverParts = new Map<IEditorHoverParticipant, IHoverPart[]>();
		for (const msg of messages) {
			renderColumn = Math.min(renderColumn, msg.range.startColumn);
			highlightRange = Range.plusRange(highlightRange, msg.range);

			if (msg.forceShowAtRange) {
				forceShowAtRange = msg.range;
			}

			if (!hoverParts.has(msg.owner)) {
				hoverParts.set(msg.owner, []);
			}
			const dest = hoverParts.get(msg.owner)!;
			dest.push(msg);
		}

		const statusBar = disposables.add(new EditorHoverStatusBar(this._keybindingService));

		for (const [participant, participantHoverParts] of hoverParts) {
			disposables.add(participant.renderHoverParts(participantHoverParts, fragment, statusBar));
		}

		if (statusBar.hasContent) {
			fragment.appendChild(statusBar.hoverElement);
		}

		this._renderDisposable = disposables;

		// show

		if (fragment.hasChildNodes()) {
			if (forceShowAtRange) {
				this._showAt(forceShowAtRange.getStartPosition(), forceShowAtRange, this._shouldFocus);
			} else {
				this._showAt(new Position(anchor.range.startLineNumber, renderColumn), highlightRange, this._shouldFocus);
			}
			this._updateContents(fragment);
		}
		if (this._colorPicker) {
			this._colorPicker.layout();
		}

		this._isChangingDecorations = true;
		this._highlightDecorations = this._editor.deltaDecorations(this._highlightDecorations, highlightRange ? [{
			range: highlightRange,
			options: ModesContentHoverWidget._DECORATION_OPTIONS
		}] : []);
		this._isChangingDecorations = false;
	}


({ scrollDirection }) => (scrollDirection === "Up" ? "0%" : "-100%")


() => {
  const [scrollDir, setScrollDir] = useState<ScrollDirection>("Up");

  // If Scroll Down, Hide Header
  useEffect(() => {
    const threshold = 0;
    let lastScrollY = window.pageYOffset;
    let ticking = false;

    const updateScrollDir = () => {
      const scrollY = window.pageYOffset;

      if (Math.abs(scrollY - lastScrollY) < threshold) {
        ticking = false;
        return;
      }

      setScrollDir(scrollY > lastScrollY ? "Down" : "Up");
      lastScrollY = scrollY > 0 ? scrollY : 0;
      ticking = false;
    };

    const onScroll = () => {
      if (!ticking) {
        window.requestAnimationFrame(updateScrollDir);
        ticking = true;
      }
    };

    window.addEventListener("scroll", onScroll);

    return () => window.removeEventListener("scroll", onScroll);
  }, [scrollDir]);

  return (
    <>
      <StyledHeader scrollDirection={scrollDir}>
        <HeaderWrapper>
          <NextLink href="/" passHref>
            <motion.a
              aria-label="Cyrilo Logo"
              initial="initial"
              animate="animate"
              variants={groupVariants}
              whileHover={{
                scale: 1.1,
              }}


() => {
    const threshold = 0;
    let lastScrollY = window.pageYOffset;
    let ticking = false;

    const updateScrollDir = () => {
      const scrollY = window.pageYOffset;

      if (Math.abs(scrollY - lastScrollY) < threshold) {
        ticking = false;
        return;
      }

      setScrollDir(scrollY > lastScrollY ? "Down" : "Up");
      lastScrollY = scrollY > 0 ? scrollY : 0;
      ticking = false;
    };

    const onScroll = () => {
      if (!ticking) {
        window.requestAnimationFrame(updateScrollDir);
        ticking = true;
      }
    };

    window.addEventListener("scroll", onScroll);

    return () => window.removeEventListener("scroll", onScroll);
  }


() => {
      const scrollY = window.pageYOffset;

      if (Math.abs(scrollY - lastScrollY) < threshold) {
        ticking = false;
        return;
      }

      setScrollDir(scrollY > lastScrollY ? "Down" : "Up");
      lastScrollY = scrollY > 0 ? scrollY : 0;
      ticking = false;
    }


() => {
      if (!ticking) {
        window.requestAnimationFrame(updateScrollDir);
        ticking = true;
      }
    }


() => window.removeEventListener("scroll", onScroll)


interface HeaderProps {
  scrollDirection: ScrollDirection;
}


type ScrollDirection = "Up" | "Down";


(props: IconProps) => {
  const strokeWidth = props.strokeWidth || 2
  const css = styledSystem(
    props.wheel.wrSystemConfig,
    props.wheel.wrSystemTheme,
    props.ncss
  )
  return (
    <svg
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth={strokeWidth}
      strokeLinecap="round"
      strokeLinejoin="round"
      className="bluetooth_svg__feather bluetooth_svg__feather-bluetooth"
      css={css}
      id={componentId}
      width="100%"
    >
      <path d="M6.5 6.5l11 11L12 23V1l5.5 5.5-11 11" />
    </svg>


interface IconProps extends SVGProps<SVGSVGElement> {
  ncss: any
  wheel: Wheel
  strokeWidth: number
}


export default function Partners() {
    return (
      <>

                 Our Partners

      </>
    );
  }


/**
 * Mock implementation of IDeltaQueue for testing that does nothing
 */
class MockDeltaQueue<T> extends EventEmitter implements IDeltaQueue<T> {
    public get disposed() { return undefined; }

    public get paused(): boolean {
        return false;
    }

    public get length(): number {
        return 0;
    }

    public get idle(): boolean {
        return false;
    }

    public async pause(): Promise<void> {
        return;
    }

    public resume(): void { }

    public peek(): T | undefined {
        return undefined;
    }

    public toArray(): T[] {
        return [];
    }

    public async systemPause(): Promise<void> {
        return;
    }

    public systemResume(): void {
        return undefined;
    }

    public dispose() { }

    constructor() {
        super();
    }
}


/**
 * Mock implementation of IDeltaManager for testing that creates mock DeltaQueues for testing
 */
export class MockDeltaManager extends EventEmitter
    implements IDeltaManager<ISequencedDocumentMessage, IDocumentMessage> {
    public get disposed() { return undefined; }

    public readonly readonly = false;
    public readonly clientType: string;
    public readonly clientDetails: IClientDetails;
    public get IDeltaSender() { return this; }

    private readonly _inbound: MockDeltaQueue<ISequencedDocumentMessage>;
    private readonly _inboundSignal: MockDeltaQueue<ISignalMessage>;
    private readonly _outbound: MockDeltaQueue<IDocumentMessage[]>;

    public get inbound(): IDeltaQueue<ISequencedDocumentMessage> {
        return this._inbound;
    }

    public get outbound(): IDeltaQueue<IDocumentMessage[]> {
        return this._outbound;
    }

    public get inboundSignal(): IDeltaQueue<ISignalMessage> {
        return this._inboundSignal;
    }
    public minimumSequenceNumber = 0;

    public lastSequenceNumber = 0;

    readonly lastKnownSeqNumber = 0;

    public initialSequenceNumber = 0;
    public hasCheckpointSequenceNumber = false;

    public get version(): string {
        return undefined;
    }

    public get maxMessageSize(): number {
        return 0;
    }

    public get serviceConfiguration(): IServiceConfiguration {
        return undefined;
    }

    public get active(): boolean {
        return true;
    }

    public close(): void { }

    public submitSignal(content: any): void { }

    public flush() { }

    public submit(type: MessageType, contents: any, batch = false, localOpMetadata: any): number {
        return 0;
    }

    public dispose() { }

    constructor() {
        super();

        this._inbound = new MockDeltaQueue<ISequencedDocumentMessage>();
        this._outbound = new MockDeltaQueue<IDocumentMessage[]>();
        this._inboundSignal = new MockDeltaQueue<ISignalMessage>();
    }
}


public async pause(): Promise<void> {
        return;
    }


public resume(): void { }


public peek(): T | undefined {
        return undefined;
    }


public toArray(): T[] {
        return [];
    }


public async systemPause(): Promise<void> {
        return;
    }


public systemResume(): void {
        return undefined;
    }


public dispose() { }


public close(): void { }


public submitSignal(content: any): void { }


public flush() { }


public submit(type: MessageType, contents: any, batch = false, localOpMetadata: any): number {
        return 0;
    }


export type UseFieldArrayProps<
  TFieldValues extends FieldValues = FieldValues,
  TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
  TKeyName extends string = 'id',
> = {
  name: TFieldArrayName;
  keyName?: TKeyName;
  control?: Control<TFieldValues>;
  shouldUnregister?: boolean;
};


/**
 * `useFieldArray` returned `fields` with unique id
 */
export type FieldArrayWithId<
  TFieldValues extends FieldValues = FieldValues,
  TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
  TKeyName extends string = 'id',
> = FieldArray<TFieldValues, TFieldArrayName> & Record<TKeyName, string>;


export type FieldArray<
  TFieldValues extends FieldValues = FieldValues,
  TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
> = FieldArrayPathValue<TFieldValues, TFieldArrayName> extends
  | ReadonlyArray<infer U>
  | null
  | undefined
  ? U
  : never;


/**
 * `useFieldArray` focus option, ability to toggle focus on and off with `shouldFocus` and setting focus by either field index or name.
 */
export type FieldArrayMethodProps = {
  shouldFocus?: boolean;
  focusIndex?: number;
  focusName?: string;
};


/**
 * Swap field array by supplying from and to index
 *
 * @remarks
 * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d)
 *
 * @param indexA - from index
 * @param indexB - to index
 *
 * @example
 * ```tsx
 * <button type="button" onClick={() => swap(0, 1)}>swap</button>
 * ```
 */
export type UseFieldArraySwap = (indexA: number, indexB: number) => void;


/**
 * Move field array by supplying from and to index
 *
 * @remarks
 * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d)
 *
 * @param indexA - from index
 * @param indexB - to index
 *
 * @example
 * ```tsx
 * <button type="button" onClick={() => move(0, 1)}>swap</button>
 * ```
 */
export type UseFieldArrayMove = (indexA: number, indexB: number) => void;


/**
 * Prepend field/fields to the start of the fields and optionally focus. The input value will be registered during this action.
 *
 * @remarks
 * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d)
 *
 * @param value - prepend items or items
 * @param options - focus options
 *
 * @example
 * ```tsx
 * <button type="button" onClick={() => prepend({ name: "data" })}>Prepend</button>
 * <button type="button" onClick={() => prepend({ name: "data" }, { shouldFocus: false })}>Prepend</button>
 * <button
 *   type="button"
 *   onClick={() => prepend([{ name: "data" }, { name: "data" }])}
 * >
 *   Prepend
 * </button>
 * ```
 */
export type UseFieldArrayPrepend<
  TFieldValues,
  TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
> = (
  value:
    | Partial<UnpackNestedValue<FieldArray<TFieldValues, TFieldArrayName>>>
    | Partial<UnpackNestedValue<FieldArray<TFieldValues, TFieldArrayName>>>[],
  options?: FieldArrayMethodProps,
) => void;


/**
 * Append field/fields to the end of your fields and focus. The input value will be registered during this action.
 *
 * @remarks
 * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d)
 *
 * @param value - append items or items.
 * @param options - focus options
 *
 * @example
 * ```tsx
 * <button type="button" onClick={() => prepend({ name: "data" })}>Append</button>
 * <button type="button" onClick={() => prepend({ name: "data" }, { shouldFocus: false })}>Append</button>
 * <button
 *   type="button"
 *   onClick={() => append([{ name: "data" }, { name: "data" }])}
 * >
 *   Append
 * </button>
 * ```
 */
export type UseFieldArrayAppend<
  TFieldValues,
  TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
> = (
  value:
    | Partial<UnpackNestedValue<FieldArray<TFieldValues, TFieldArrayName>>>
    | Partial<UnpackNestedValue<FieldArray<TFieldValues, TFieldArrayName>>>[],
  options?: FieldArrayMethodProps,
) => void;


/**
 * Remove field/fields at particular position.
 *
 * @remarks
 * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d)
 *
 * @param index - index to remove at, or remove all when no index provided.
 *
 * @example
 * ```tsx
 * <button type="button" onClick={() => remove(0)}>Remove</button>
 * <button
 *   type="button"
 *   onClick={() => remove()}
 * >
 *   Remove all
 * </button>
 * ```
 */
export type UseFieldArrayRemove = (index?: number | number[]) => void;


/**
 * Insert field/fields at particular position and focus.
 *
 * @remarks
 * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d)
 *
 * @param index - insert position
 * @param value - insert field or fields
 * @param options - focus options
 *
 * @example
 * ```tsx
 * <button type="button" onClick={() => insert(1, { name: "data" })}>Insert</button>
 * <button type="button" onClick={() => insert(1, { name: "data" }, { shouldFocus: false })}>Insert</button>
 * <button
 *   type="button"
 *   onClick={() => insert(1, [{ name: "data" }, { name: "data" }])}
 * >
 *   Insert
 * </button>
 * ```
 */
export type UseFieldArrayInsert<
  TFieldValues,
  TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
> = (
  index: number,
  value:
    | Partial<UnpackNestedValue<FieldArray<TFieldValues, TFieldArrayName>>>
    | Partial<UnpackNestedValue<FieldArray<TFieldValues, TFieldArrayName>>>[],
  options?: FieldArrayMethodProps,
) => void;


/**
 * Update field/fields at particular position.
 *
 * @remarks
 * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d)
 *
 * @param index - insert position
 * @param value - insert field or fields
 *
 * @example
 * ```tsx
 * <button type="button" onClick={() => update(1, { name: "data" })}>Update</button>
 * <button
 *   type="button"
 *   onClick={() => update(1, [{ name: "data" }, { name: "data" }])}
 * >
 *   Update
 * </button>
 * ```
 */
export type UseFieldArrayUpdate<
  TFieldValues,
  TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
> = (
  index: number,
  value: UnpackNestedValue<FieldArray<TFieldValues, TFieldArrayName>>,
) => void;


/**
 * Replace the entire field array values.
 *
 * @remarks
 * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d)
 *
 * @param value - the entire field values.
 *
 * @example
 * ```tsx
 * <button
 *   type="button"
 *   onClick={() => update([{ name: "data" }, { name: "data" }])}
 * >
 *   Replace
 * </button>
 * ```
 */
export type UseFieldArrayReplace<
  TFieldValues,
  TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
> = (
  value:
    | Partial<UnpackNestedValue<FieldArray<TFieldValues, TFieldArrayName>>>
    | Partial<UnpackNestedValue<FieldArray<TFieldValues, TFieldArrayName>>>[],
) => void;


export type UseFieldArrayReturn<
  TFieldValues extends FieldValues = FieldValues,
  TFieldArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,
  TKeyName extends string = 'id',
> = {
  swap: UseFieldArraySwap;
  move: UseFieldArrayMove;
  prepend: UseFieldArrayPrepend<TFieldValues, TFieldArrayName>;
  append: UseFieldArrayAppend<TFieldValues, TFieldArrayName>;
  remove: UseFieldArrayRemove;
  insert: UseFieldArrayInsert<TFieldValues, TFieldArrayName>;
  update: UseFieldArrayUpdate<TFieldValues, TFieldArrayName>;
  replace: UseFieldArrayReplace<TFieldValues, TFieldArrayName>;
  fields: FieldArrayWithId<TFieldValues, TFieldArrayName, TKeyName>[];
};


() => {
        test("with space", () => {
            assert(
                create("borf", {
                    space: { resolutions: { borf: true } }
                }).type
            ).typed as true
            assert(
                create(
                    { snorf: "borf[]" },
                    {
                        space: {
                            resolutions: { borf: { f: false, u: undefined } }
                        }
                    }
                ).type
            ).typed as { snorf: { f: false; u: undefined }[] }
        })
        const getCyclicSpace = () =>
            compile({
                a: { b: "b", isA: "true", isB: "false" },
                b: { a: "a", isA: "false", isB: "true" }
            })
        test("with onCycle option", () => {
            const { type } = getCyclicSpace().create(
                { a: "a", b: "b" },
                {
                    parse: {
                        onCycle: {
                            cyclic: "cyclic?"
                        }
                    }
                }
            )
            assert(type.a.b.a.cyclic).type.toString.snap(
                `"{ b: { a: { b: { a: any; isA: false; isB: true; }; isA: true; isB: false; }; isA: false; isB: true; }; isA: true; isB: false; } | undefined"`
            )
            assert(type.b.a.b.cyclic).type.toString.snap(
                `"{ a: { b: { a: { b: any; isA: true; isB: false; }; isA: false; isB: true; }; isA: true; isB: false; }; isA: false; isB: true; } | undefined"`
            )
            // After initial cycle, no more "cyclic" transformations occur since
            // "deepOnCycle" was not passed
            assert(type.b.a.b.cyclic?.a.b.a.b.a.b.a.b.isB).typed as
                | true
                | undefined
        })
        test("with deepOnCycleOption", () => {
            const { type } = getCyclicSpace().create(
                { a: "a", b: "b" },
                {
                    parse: {
                        onCycle: {
                            cyclic: "cyclic?"
                        },
                        deepOnCycle: true
                    }
                }
            )
            assert(type.a.b.a.cyclic?.b.a.b.cyclic).type.toString.snap(
                `"{ a: { b: { a: { cyclic?: { b: { a: { b: { cyclic?: { a: { b: { a: any; isA: false; isB: true; }; isA: true; isB: false; }; isA: false; isB: true; } | undefined; }; isA: true; isB: false; }; isA: false; isB: true; }; isA: true; isB: false; } | undefined; }; isA: false; isB: true; }; isA: true; isB: false; }; isA: false; isB: true; } | undefined"`
            )
        })
        test("with onResolve option", () => {
            const { type } = getCyclicSpace().create(
                {
                    referencesA: "a",
                    noReferences: {
                        favoriteSoup: "'borscht'"
                    }
                },
                {
                    parse: {
                        onResolve: {
                            wasResolved: "true",
                            resolvedType: "resolved"
                        }
                    }
                }
            )
            assert(type.referencesA.wasResolved).typed as true
            assert(type.referencesA.resolvedType.b.wasResolved).typed as true
            // @ts-expect-error
            assert(type.noReferences.wasResolved).type.errors(
                "Property 'wasResolved' does not exist on type '{ favoriteSoup: \"borscht\"; }'."
            )
        })
    }


() => {
            assert(
                create("borf", {
                    space: { resolutions: { borf: true } }
                }).type
            ).typed as true
            assert(
                create(
                    { snorf: "borf[]" },
                    {
                        space: {
                            resolutions: { borf: { f: false, u: undefined } }
                        }
                    }
                ).type
            ).typed as { snorf: { f: false; u: undefined }[] }
        }


() =>
            compile({
                a: { b: "b", isA: "true", isB: "false" },
                b: { a: "a", isA: "false", isB: "true" }
            })


() => {
            const { type } = getCyclicSpace().create(
                { a: "a", b: "b" },
                {
                    parse: {
                        onCycle: {
                            cyclic: "cyclic?"
                        }
                    }
                }
            )
            assert(type.a.b.a.cyclic).type.toString.snap(
                `"{ b: { a: { b: { a: any; isA: false; isB: true; }; isA: true; isB: false; }; isA: false; isB: true; }; isA: true; isB: false; } | undefined"`
            )
            assert(type.b.a.b.cyclic).type.toString.snap(
                `"{ a: { b: { a: { b: any; isA: true; isB: false; }; isA: false; isB: true; }; isA: true; isB: false; }; isA: false; isB: true; } | undefined"`
            )
            // After initial cycle, no more "cyclic" transformations occur since
            // "deepOnCycle" was not passed
            assert(type.b.a.b.cyclic?.a.b.a.b.a.b.a.b.isB).typed as
                | true
                | undefined
        }


() => {
            const { type } = getCyclicSpace().create(
                { a: "a", b: "b" },
                {
                    parse: {
                        onCycle: {
                            cyclic: "cyclic?"
                        },
                        deepOnCycle: true
                    }
                }
            )
            assert(type.a.b.a.cyclic?.b.a.b.cyclic).type.toString.snap(
                `"{ a: { b: { a: { cyclic?: { b: { a: { b: { cyclic?: { a: { b: { a: any; isA: false; isB: true; }; isA: true; isB: false; }; isA: false; isB: true; } | undefined; }; isA: true; isB: false; }; isA: false; isB: true; }; isA: true; isB: false; } | undefined; }; isA: false; isB: true; }; isA: true; isB: false; }; isA: false; isB: true; } | undefined"`
            )
        }


() => {
            const { type } = getCyclicSpace().create(
                {
                    referencesA: "a",
                    noReferences: {
                        favoriteSoup: "'borscht'"
                    }
                },
                {
                    parse: {
                        onResolve: {
                            wasResolved: "true",
                            resolvedType: "resolved"
                        }
                    }
                }
            )
            assert(type.referencesA.wasResolved).typed as true
            assert(type.referencesA.resolvedType.b.wasResolved).typed as true
            // @ts-expect-error
            assert(type.noReferences.wasResolved).type.errors(
                "Property 'wasResolved' does not exist on type '{ favoriteSoup: \"borscht\"; }'."
            )
        }


() => {
        test("simple space", () => {
            const groceries = create(
                { fruits: "fruit[]" },
                {
                    space: {
                        resolutions: {
                            banana: {
                                length: "number",
                                description: "string?"
                            },
                            apple: { circumference: "number", type: "string" },
                            fruit: "banana|apple"
                        }
                    }
                }
            )
            expect(
                groceries.validate({
                    fruits: [
                        { length: 10 },
                        { circumference: 4.832321, type: "Granny Smith" },
                        { length: 15, description: "nice" }
                    ]
                }).error
            ).toBeFalsy()
            expect(
                groceries.validate(
                    {
                        fruits: [
                            {
                                length: 5000,
                                description: "I'm a big banana!",
                                peel: "slippery"
                            },

                            { type: "Fuji" }
                        ]
                    },

                    // Verbose should explain why each component of the union type doesn't apply
                    { verbose: true }
                ).error
            ).toMatchInlineSnapshot(`
"Encountered errors at the following paths:
{
  fruits/0: '{length: 5000, description: 'I'm a big banana!', peel: 'slippery'} is not assignable to any of banana|apple.
Encountered errors at the following paths:
{
  banana: 'At path fruits/0, keys 'peel' were unexpected.',
  apple: 'At path fruits/0, required keys 'circumference, type' were missing. Keys 'length, description, peel' were unexpected.'
}',
  fruits/1: '{type: 'Fuji'} is not assignable to any of banana|apple.
Encountered errors at the following paths:
{
  banana: 'At path fruits/1, required keys 'length' were missing. Keys 'type' were unexpected.',
  apple: 'At path fruits/1, required keys 'circumference' were missing.'
}'
}"
`)
        })
        test("errors on shallow cycle", () => {
            // @ts-expect-error
            const shallowRecursive = compile({ a: "a" })
            expect(() =>
                shallowRecursive.models.a.assert("what's an a?")
            ).toThrowError("shallow")
            // @ts-expect-error
            const shallowCyclic = compile({ a: "b", b: "c", c: "a|b|c" })
            expect(() =>
                shallowCyclic.models.a.assert(["what's a b?"])
            ).toThrowError("shallow")
        })
        test("cyclic space", () => {
            const bicycle = create(
                { a: "a", b: "b", c: "either[]" },
                {
                    space: {
                        resolutions: {
                            a: { a: "a?", b: "b?", isA: "true" },
                            b: { a: "a?", b: "b?", isA: "false" },
                            either: "a|b"
                        }
                    }
                }
            )
            expect(
                bicycle.validate({
                    a: {
                        isA: true,
                        a: { isA: true },
                        b: { isA: false, a: { isA: true } }
                    },
                    b: { isA: false },
                    c: [
                        { isA: false, a: { isA: true } },
                        { isA: true, b: { isA: false } }
                    ]
                }).error
            ).toBeFalsy()
            expect(
                bicycle.validate({
                    a: {
                        isA: true,
                        a: {
                            isA: true,
                            a: {
                                isA: true,
                                a: {
                                    isA: true,
                                    a: {
                                        isA: true,
                                        a: { isA: true, a: { isA: false } }
                                    }
                                }
                            }
                        }
                    },

                    b: {
                        isA: false,
                        b: {
                            isA: false,
                            b: {
                                isA: false,
                                b: {
                                    isA: false,
                                    b: {
                                        isA: false,
                                        b: { isA: false, b: { isA: true } }
                                    }
                                }
                            }
                        }
                    },

                    c: [
                        { isA: true },
                        { isA: false },
                        { isA: true },
                        { isA: false },
                        { isA: true },
                        { isA: false },
                        { isA: true },
                        { isA: false },
                        { isA: "the duck goes quack" }
                    ]
                }).error
            ).toMatchInlineSnapshot(`
"Encountered errors at the following paths:
{
  a/a/a/a/a/a/a/isA: 'false is not assignable to true.',
  b/b/b/b/b/b/b/isA: 'true is not assignable to false.',
  c/8: '{isA: 'the duck goes quack'} is not assignable to any of a|b.'
}"
`)
        })
        test("doesn't try to parse or validate any", () => {
            // Parse any as type
            assert(create({} as any).type).typed as any
            // Parse any as space
            const parseWithAnySpace = () =>
                create(
                    { literal: "string", alias: "myType" },
                    { space: {} as any }
                ).type
            assert(parseWithAnySpace).typed as () => {
                literal: string
                alias: any
            }
            assert(parseWithAnySpace)
                .throws()
                .snap(
                    `"Unable to determine the type of 'myType' at path alias."`
                )
            // Parse any as space member
            assert(
                create(["number", "a"], {
                    space: { resolutions: { a: {} as any } }
                }).type
            ).typed as [number, any]
        })
    }


() => {
            const groceries = create(
                { fruits: "fruit[]" },
                {
                    space: {
                        resolutions: {
                            banana: {
                                length: "number",
                                description: "string?"
                            },
                            apple: { circumference: "number", type: "string" },
                            fruit: "banana|apple"
                        }
                    }
                }
            )
            expect(
                groceries.validate({
                    fruits: [
                        { length: 10 },
                        { circumference: 4.832321, type: "Granny Smith" },
                        { length: 15, description: "nice" }
                    ]
                }).error
            ).toBeFalsy()
            expect(
                groceries.validate(
                    {
                        fruits: [
                            {
                                length: 5000,
                                description: "I'm a big banana!",
                                peel: "slippery"
                            },

                            { type: "Fuji" }
                        ]
                    },

                    // Verbose should explain why each component of the union type doesn't apply
                    { verbose: true }
                ).error
            ).toMatchInlineSnapshot(`
"Encountered errors at the following paths:
{
  fruits/0: '{length: 5000, description: 'I'm a big banana!', peel: 'slippery'} is not assignable to any of banana|apple.
Encountered errors at the following paths:
{
  banana: 'At path fruits/0, keys 'peel' were unexpected.',
  apple: 'At path fruits/0, required keys 'circumference, type' were missing. Keys 'length, description, peel' were unexpected.'
}',
  fruits/1: '{type: 'Fuji'} is not assignable to any of banana|apple.
Encountered errors at the following paths:
{
  banana: 'At path fruits/1, required keys 'length' were missing. Keys 'type' were unexpected.',
  apple: 'At path fruits/1, required keys 'circumference' were missing.'
}'
}"
`)
        }


() => {
            // @ts-expect-error
            const shallowRecursive = compile({ a: "a" })
            expect(() =>
                shallowRecursive.models.a.assert("what's an a?")
            ).toThrowError("shallow")
            // @ts-expect-error
            const shallowCyclic = compile({ a: "b", b: "c", c: "a|b|c" })
            expect(() =>
                shallowCyclic.models.a.assert(["what's a b?"])
            ).toThrowError("shallow")
        }


() =>
                shallowRecursive.models.a.assert("what's an a?")


() =>
                shallowCyclic.models.a.assert(["what's a b?"])


() => {
            const bicycle = create(
                { a: "a", b: "b", c: "either[]" },
                {
                    space: {
                        resolutions: {
                            a: { a: "a?", b: "b?", isA: "true" },
                            b: { a: "a?", b: "b?", isA: "false" },
                            either: "a|b"
                        }
                    }
                }
            )
            expect(
                bicycle.validate({
                    a: {
                        isA: true,
                        a: { isA: true },
                        b: { isA: false, a: { isA: true } }
                    },
                    b: { isA: false },
                    c: [
                        { isA: false, a: { isA: true } },
                        { isA: true, b: { isA: false } }
                    ]
                }).error
            ).toBeFalsy()
            expect(
                bicycle.validate({
                    a: {
                        isA: true,
                        a: {
                            isA: true,
                            a: {
                                isA: true,
                                a: {
                                    isA: true,
                                    a: {
                                        isA: true,
                                        a: { isA: true, a: { isA: false } }
                                    }
                                }
                            }
                        }
                    },

                    b: {
                        isA: false,
                        b: {
                            isA: false,
                            b: {
                                isA: false,
                                b: {
                                    isA: false,
                                    b: {
                                        isA: false,
                                        b: { isA: false, b: { isA: true } }
                                    }
                                }
                            }
                        }
                    },

                    c: [
                        { isA: true },
                        { isA: false },
                        { isA: true },
                        { isA: false },
                        { isA: true },
                        { isA: false },
                        { isA: true },
                        { isA: false },
                        { isA: "the duck goes quack" }
                    ]
                }).error
            ).toMatchInlineSnapshot(`
"Encountered errors at the following paths:
{
  a/a/a/a/a/a/a/isA: 'false is not assignable to true.',
  b/b/b/b/b/b/b/isA: 'true is not assignable to false.',
  c/8: '{isA: 'the duck goes quack'} is not assignable to any of a|b.'
}"
`)
        }


() => {
            // Parse any as type
            assert(create({} as any).type).typed as any
            // Parse any as space
            const parseWithAnySpace = () =>
                create(
                    { literal: "string", alias: "myType" },
                    { space: {} as any }
                ).type
            assert(parseWithAnySpace).typed as () => {
                literal: string
                alias: any
            }
            assert(parseWithAnySpace)
                .throws()
                .snap(
                    `"Unable to determine the type of 'myType' at path alias."`
                )
            // Parse any as space member
            assert(
                create(["number", "a"], {
                    space: { resolutions: { a: {} as any } }
                }).type
            ).typed as [number, any]
        }


() =>
                create(
                    { literal: "string", alias: "myType" },
                    { space: {} as any }
                ).type


() => {
        test("simple space", () => {
            expect(
                create(
                    {
                        fruits: "fruit[]",
                        bestBanana: "banana",
                        bestApple: "apple",
                        bestFruit: "fruit",
                        optionalFruit: "fruit?"
                    },
                    {
                        space: {
                            resolutions: {
                                banana: {
                                    length: "number",
                                    description: "string?"
                                },
                                apple: {
                                    circumference: "number",
                                    type: "string"
                                },
                                fruit: "banana|apple"
                            }
                        }
                    }
                ).generate()
            ).toStrictEqual({
                fruits: [],
                bestBanana: { length: 0 },
                bestApple: { circumference: 0, type: "" },
                bestFruit: { length: 0 }
            })
        })
        test("optional cycle", () => {
            // If it's optional, the cycle should be ignored and just return undefined
            expect(
                create("a", {
                    space: {
                        resolutions: {
                            a: { b: "b" },
                            b: { c: "c?" },
                            c: "a|b"
                        }
                    }
                }).generate()
            ).toStrictEqual({ b: {} })
        })
        test("required cycle", () => {
            expect(() =>
                create("a", {
                    space: {
                        resolutions: {
                            a: { b: "b" },
                            b: { c: "c" },
                            c: "a|b"
                        }
                    }
                }).generate()
            ).toThrowErrorMatchingInlineSnapshot(`
            "Unable to generate a default value for type including a required cycle:
            a=>b=>c=>a
            If you'd like to avoid throwing in when this occurs, pass a value to return when this occurs to the 'onRequiredCycle' option."
        `)
        })
        test("onRequiredCycle", () => {
            expect(
                create("a", {
                    space: {
                        resolutions: {
                            a: { b: "b" },
                            b: { c: "c" },
                            c: "a|b"
                        }
                    }
                }).generate({ onRequiredCycle: { whoops: ["cycle"] } })
            ).toStrictEqual({
                b: { c: { whoops: ["cycle"] } }
            })
        })
        test("onRequiredCycle with union", () => {
            expect(
                create("a|b", {
                    space: {
                        resolutions: {
                            a: { b: "b" },
                            b: { a: "a" }
                        }
                    }
                }).generate({ onRequiredCycle: "cycle" })
            ).toStrictEqual({ b: { a: "cycle" } })
        })

        test("from parsed", () => {
            const defaultValue = create(
                {
                    requiredGroup: "group",
                    requiredGroups: "group[]",
                    optionalGroup: "group?",
                    optionalGroups: "group[]?"
                },
                {
                    space: {
                        resolutions: {
                            group: { name: "string", description: "string?" }
                        }
                    }
                }
            ).generate()
            expect(defaultValue).toStrictEqual({
                requiredGroup: { name: "" },
                requiredGroups: []
            })
        })
    }


() => {
            expect(
                create(
                    {
                        fruits: "fruit[]",
                        bestBanana: "banana",
                        bestApple: "apple",
                        bestFruit: "fruit",
                        optionalFruit: "fruit?"
                    },
                    {
                        space: {
                            resolutions: {
                                banana: {
                                    length: "number",
                                    description: "string?"
                                },
                                apple: {
                                    circumference: "number",
                                    type: "string"
                                },
                                fruit: "banana|apple"
                            }
                        }
                    }
                ).generate()
            ).toStrictEqual({
                fruits: [],
                bestBanana: { length: 0 },
                bestApple: { circumference: 0, type: "" },
                bestFruit: { length: 0 }
            })
        }


() => {
            // If it's optional, the cycle should be ignored and just return undefined
            expect(
                create("a", {
                    space: {
                        resolutions: {
                            a: { b: "b" },
                            b: { c: "c?" },
                            c: "a|b"
                        }
                    }
                }).generate()
            ).toStrictEqual({ b: {} })
        }


() => {
            expect(() =>
                create("a", {
                    space: {
                        resolutions: {
                            a: { b: "b" },
                            b: { c: "c" },
                            c: "a|b"
                        }
                    }
                }).generate()
            ).toThrowErrorMatchingInlineSnapshot(`
            "Unable to generate a default value for type including a required cycle:
            a=>b=>c=>a
            If you'd like to avoid throwing in when this occurs, pass a value to return when this occurs to the 'onRequiredCycle' option."
        `)
        }


() =>
                create("a", {
                    space: {
                        resolutions: {
                            a: { b: "b" },
                            b: { c: "c" },
                            c: "a|b"
                        }
                    }
                }).generate()


() => {
            expect(
                create("a", {
                    space: {
                        resolutions: {
                            a: { b: "b" },
                            b: { c: "c" },
                            c: "a|b"
                        }
                    }
                }).generate({ onRequiredCycle: { whoops: ["cycle"] } })
            ).toStrictEqual({
                b: { c: { whoops: ["cycle"] } }
            })
        }


() => {
            expect(
                create("a|b", {
                    space: {
                        resolutions: {
                            a: { b: "b" },
                            b: { a: "a" }
                        }
                    }
                }).generate({ onRequiredCycle: "cycle" })
            ).toStrictEqual({ b: { a: "cycle" } })
        }


() => {
            const defaultValue = create(
                {
                    requiredGroup: "group",
                    requiredGroups: "group[]",
                    optionalGroup: "group?",
                    optionalGroups: "group[]?"
                },
                {
                    space: {
                        resolutions: {
                            group: { name: "string", description: "string?" }
                        }
                    }
                }
            ).generate()
            expect(defaultValue).toStrictEqual({
                requiredGroup: { name: "" },
                requiredGroups: []
            })
        }


() => {
    let shallow;

    beforeAll(() => {
        shallow = createShallow();
    });

    const getProps = () => ({
        name: 'test name',
        text: 'test text',
        classes: {},
        ...((global as any) as any).eventkit_test_props,
    });

    const getWrapper = props => shallow(<LicenseRow {...props} />);

    it('should render elements', () => {
        const props = getProps();
        const wrapper = getWrapper(props);
        expect(wrapper.find(TableRow)).toHaveLength(1);
        expect(wrapper.find(TableCell)).toHaveLength(7);
        expect(wrapper.find(BaseDialog)).toHaveLength(1);
        expect(wrapper.find('i')).toHaveLength(1);
        expect(wrapper.find('i').text()).toEqual('Use of this data is governed by\u00a0test name');
    });

    it('setLicenseOpen should set license dialog to open', () => {
        const props = getProps();
        const stateSpy = sinon.spy(LicenseRow.prototype, 'setState');
        const wrapper = shallow(<LicenseRow {...props} />);
        expect(stateSpy.called).toBe(false);
        wrapper.instance().setLicenseOpen();
        expect(stateSpy.calledOnce).toBe(true);
        expect(stateSpy.calledWith({ licenseDialogOpen: true })).toBe(true);
        stateSpy.restore();
    });

    it('handleProviderClose should set the provider dialog to closed', () => {
        const props = getProps();
        const stateSpy = sinon.spy(LicenseRow.prototype, 'setState');
        const wrapper = shallow(<LicenseRow {...props} />);
        expect(stateSpy.called).toBe(false);
        wrapper.instance().handleLicenseClose();
        expect(stateSpy.calledOnce).toBe(true);
        expect(stateSpy.calledWith({ licenseDialogOpen: false })).toBe(true);
        stateSpy.restore();
    });
}


() => {
        shallow = createShallow();
    }


() => ({
        name: 'test name',
        text: 'test text',
        classes: {},
        ...((global as any) as any).eventkit_test_props,
    })


props => shallow(<LicenseRow {...props} />)


() => {
        const props = getProps();
        const wrapper = getWrapper(props);
        expect(wrapper.find(TableRow)).toHaveLength(1);
        expect(wrapper.find(TableCell)).toHaveLength(7);
        expect(wrapper.find(BaseDialog)).toHaveLength(1);
        expect(wrapper.find('i')).toHaveLength(1);
        expect(wrapper.find('i').text()).toEqual('Use of this data is governed by\u00a0test name');
    }


() => {
        const props = getProps();
        const stateSpy = sinon.spy(LicenseRow.prototype, 'setState');
        const wrapper = shallow(<LicenseRow {...props} />);
        expect(stateSpy.called).toBe(false);
        wrapper.instance().setLicenseOpen();
        expect(stateSpy.calledOnce).toBe(true);
        expect(stateSpy.calledWith({ licenseDialogOpen: true })).toBe(true);
        stateSpy.restore();
    }


() => {
        const props = getProps();
        const stateSpy = sinon.spy(LicenseRow.prototype, 'setState');
        const wrapper = shallow(<LicenseRow {...props} />);
        expect(stateSpy.called).toBe(false);
        wrapper.instance().handleLicenseClose();
        expect(stateSpy.calledOnce).toBe(true);
        expect(stateSpy.calledWith({ licenseDialogOpen: false })).toBe(true);
        stateSpy.restore();
    }