(): string => {
        if (isGravatarURL()) {
            return ThirdPartyLogos.gravatar;
        }

        return null;
    }


(): boolean => {
        return (userImage && userImage.includes(UIConstants.GRAVATAR_URL))
            || (authState && authState.profileInfo && authState.profileInfo.userImage
                && authState.profileInfo.userImage.includes(UIConstants.GRAVATAR_URL))
            || (authState && authState.profileInfo && authState.profileInfo.profileUrl
                && authState.profileInfo.profileUrl.includes(UIConstants.GRAVATAR_URL));
    }


(e: MouseEvent) => {
        setShowPopup(true);
    }


(e: MouseEvent) => {
        setShowPopup(false);
    }


() => {
        const data = {
            Operations: [
                {
                    op: "replace",
                    value: {
                        profileUrl: url
                    }
                }
            ],
            schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]
        };
        updateProfileInfo(data).then((response) => {
            if (response.status === 200) {
                onAlertFired({
                    description: t(
                        "views:components.profile.notifications.updateProfileInfo.success.description"
                    ),
                    level: AlertLevels.SUCCESS,
                    message: t(
                        "views:components.profile.notifications.updateProfileInfo.success.message"
                    )
                });

                // Re-fetch the profile information
                dispatch(getProfileInformation(true));
                setShowEditModal(false);
            }
        });
    }


(response) => {
            if (response.status === 200) {
                onAlertFired({
                    description: t(
                        "views:components.profile.notifications.updateProfileInfo.success.description"
                    ),
                    level: AlertLevels.SUCCESS,
                    message: t(
                        "views:components.profile.notifications.updateProfileInfo.success.message"
                    )
                });

                // Re-fetch the profile information
                dispatch(getProfileInformation(true));
                setShowEditModal(false);
            }
        }


async (event: React.MouseEvent) => {

        if (_.isEmpty(url)) {
            setUrlError(Error.REQUIRED);
        } else if (! await FormValidation.imageUrl(url)) {
            setUrlError(Error.VALIDATION);
        } else {
            updateProfileUrl();
        }

    }


() => {
        setShowEditModal(false);
        setUrlError(Error.NONE);
    }


() => {
        setShowEditModal(true);
        setUrl(profileUrl);
    }


() => {
        const fieldName = t("views:components.profile.fields."
            + urlSchema.name.replace(".", "_"),
            { defaultValue: urlSchema.displayName }
        );

        return (
            <Modal
                dimmer="blurring"
                size="tiny"
                open={ showEditModal }
                onClose={ closeModal }
            >
                <Modal.Content>
                    <h3>{ t("views:components.userAvatar.urlUpdateHeader") }</h3>
                    <Form>
                        <Form.Input
                            value={ url }
                            onChange={ (e)


/**
 * Prop types for the user avatar component.
 */
interface UserAvatarProps extends AvatarProps {
    authState?: AuthStateInterface;
    gravatarInfoPopoverText?: React.ReactNode;
    showGravatarLabel?: boolean;
    showEdit?: boolean;
    profileUrl?: string;
    urlSchema?: ProfileSchema;
    onAlertFired?: (alert: AlertInterface) => void;
}


/**
 * Enum to be used to specify the type of error when submitting the url
 */
enum Error {
    REQUIRED,
    VALIDATION,
    NONE
}


resolveTopLabel() : null


resolveUserDisplayName(authState) : name


t("views:components.userAvatar.urlUpdateHeader")


t("views:components.profile.forms.generic.inputs.placeholder", {
                                fieldName
                            })


t("common:cancel")


t("common:save")


setShowEditOverlay(true);


setShowEditOverlay(false);


type=>user


scroll_version_group=>scroll_version_group.scroll_versions


main_action=>main_action.scroll_version_


artefact_data=>artefact_data.scroll_versions


artefact_position=>artefact_position.scroll_versions


artefact_shape=>artefact_shape.scroll_versions


char_of_writing=>char_of_writing.scroll_versions


col_sequence=>col_sequence.scroll_versions


col_to_line=>col_to_line.scroll_versions


form_of_writing=>form_of_writing.scroll_versions


line_to_sign=>line_to_sign.scroll_versions


position_in_stream=>position_in_stream.scroll_versions


scribal_font_type=>scribal_font_type.scroll_versions


type=>scribe


scroll_data=>scroll_data.scroll_versions


scroll_to_col=>scroll_to_col.scroll_versions


sign_char_attribute=>sign_char_attribute.scroll_versions


sign_char_commentary=>sign_char_commentary.scroll_versions


sign_char_roi=>sign_char_roi.scroll_versions


type=>word


@Entity("scroll_version",{schema:"SQE_DEV"})
@Index("fk_scroll_version_to_user_idx",["user_",])
@Index("fk_scroll_version_tos_vg_idx",["scroll_version_group_",])
export class scroll_version {

    @PrimaryGeneratedColumn({
        name:"scroll_version_id"
        })
    scroll_version_id:number;

    @ManyToOne(type=>user, user=>user.scroll_versions,{  nullable:false,onDelete: 'NO ACTION',onUpdate: 'NO ACTION' })
    @JoinColumn({ name:'user_id'})
    user_:user | null;

    @ManyToOne(type=>scroll_version_group, scroll_version_group=>scroll_version_group.scroll_versions,{  nullable:false,onDelete: 'CASCADE',onUpdate: 'NO ACTION' })
    @JoinColumn({ name:'scroll_version_group_id'})
    scroll_version_group_:scroll_version_group | null;

    @Column("tinyint",{
        nullable:false,
        default:"0",
        name:"may_write"
        })
    may_write:number;

    @Column("tinyint",{
        nullable:false,
        default:"0",
        name:"may_lock"
        })
    may_lock:number;

    @OneToMany(type=>main_action, main_action=>main_action.scroll_version_,{ onDelete: 'CASCADE' ,onUpdate: 'NO ACTION' })
    main_actions:main_action[];

    @ManyToMany(type=>area_group, area_group=>area_group.scroll_versions)
    area_groups:area_group[];

    @ManyToMany(type=>artefact_data, artefact_data=>artefact_data.scroll_versions)
    artefact_datas:artefact_data[];

    @ManyToMany(type=>artefact_position, artefact_position=>artefact_position.scroll_versions)
    artefact_positions:artefact_position[];

    @ManyToMany(type=>artefact_shape, artefact_shape=>artefact_shape.scroll_versions)
    artefact_shapes:artefact_shape[];

    @ManyToMany(type=>char_of_writing, char_of_writing=>char_of_writing.scroll_versions)
    char_of_writings:char_of_writing[];

    @ManyToMany(type=>col_data, col_data=>col_data.scroll_versions)
    col_datas:col_data[];

    @ManyToMany(type=>col_sequence, col_sequence=>col_sequence.scroll_versions)
    col_sequences:col_sequence[];

    @ManyToMany(type=>col_to_line, col_to_line=>col_to_line.scroll_versions)
    col_to_lines:col_to_line[];

    @ManyToMany(type=>form_of_writing, form_of_writing=>form_of_writing.scroll_versions)
    form_of_writings:form_of_writing[];

    @ManyToMany(type=>line_data, line_data=>line_data.scroll_versions)
    line_datas:line_data[];

    @ManyToMany(type=>line_to_sign, line_to_sign=>line_to_sign.scroll_versions)
    line_to_signs:line_to_sign[];

    @ManyToMany(type=>position_in_stream, position_in_stream=>position_in_stream.scroll_versions)
    position_in_streams:position_in_stream[];

    @ManyToMany(type=>scribal_font_type, scribal_font_type=>scribal_font_type.scroll_versions)
    scribal_font_types:scribal_font_type[];

    @ManyToMany(type=>scribe, scribe=>scribe.scroll_versions)
    scribes:scribe[];

    @ManyToMany(type=>scroll_data, scroll_data=>scroll_data.scroll_versions)
    scroll_datas:scroll_data[];

    @ManyToMany(type=>scroll_to_col, scroll_to_col=>scroll_to_col.scroll_versions)
    scroll_to_cols:scroll_to_col[];

    @ManyToMany(type=>sign_char_attribute, sign_char_attribute=>sign_char_attribute.scroll_versions)
    sign_char_attributes:sign_char_attribute[];

    @ManyToMany(type=>sign_char_commentary, sign_char_commentary=>sign_char_commentary.scroll_versions)
    sign_char_commentarys:sign_char_commentary[];

    @ManyToMany(type=>sign_char_roi, sign_char_roi=>sign_char_roi.scroll_versions)
    sign_char_rois:sign_char_roi[];

    @ManyToMany(type=>word, word=>word.scroll_versions)
    words:word[];

}


({
  title = "Watch lot",
  ...props
}) => {
  return (
    <Icon {...props} viewBox="0 0 18 18">
      <Title>{title}</Title>
      <Path
        d="M14.591 12.229a8.82 8.82 0 0 1-1.653-4.979V5.938a3.938 3.938 0 1 0-7.876 0V7.25a8.82 8.82 0 0 1-1.653 4.979.446.446 0 0 0-.053.464c.074.15.227.245.394.245h2.949a2.336 2.336 0 0 0-.105.656 2.406 2.406 0 0 0 4.812 0 2.336 2.336 0 0 0-.105-.656h2.949c.167 0 .32-.095.394-.245a.446.446 0 0 0-.053-.464zm-4.06 1.365a1.531 1.531 0 1 1-3.062 0c.002-.228.056-.452.157-.656h2.748c.101.204.155.428.157.656zm-5.959-1.531A9.625 9.625 0 0 0 5.937 7.25V5.938a3.063 3.063 0 0 1 6.126 0V7.25a9.625 9.625 0 0 0 1.364 4.813H4.572z"
        fill={color(props.fill)}
        fillRule="nonzero"
      />
    </Icon>


color(props


element => {
        this.form.get(element.split("/")).disable();
      }


element => {
        this.form.get(element.split("/")).enable();
      }


value => {
      if (value) {
        this.map_cfg.features = value;
        value.forEach(feature => {
          switch(feature.type){
            case 'occupazione':
              this.form.get('affected_area').patchValue(feature.features[0] || '');
              break;
          }
        });
        console.log("Dati pratica",this.form.value);
      }
      console.log('Mappa chiusa', value);
    }


feature => {
          switch(feature.type){
            case 'occupazione':
              this.form.get('affected_area').patchValue(feature.features[0] || '');
              break;
          }
        }


error => {
      console.log('errore mappa');
    }


@Component({
  selector: 'view-occupazione-suolo-pubblico',
  templateUrl: './view-occupazione-suolo-pubblico.component.html',
  styleUrls: ['./view-occupazione-suolo-pubblico.component.scss']
})
export class ViewOccupazioneSuoloPubblicoComponent implements OnInit {

  form: FormGroup;
  @Input() data: any;
  @Input() modifiable: boolean

  @Output() update_details = new EventEmitter();

  can_modify = false;

  isLoading = false;

  tipologie = [
    {value: 'less_than_year', name: "Minore di un anno"},
    {value: 'more_than_year', name: "Maggiore di un anno"},
    {value: 'permanent', name: "Permanente"}
  ];

  map_cfg = {
    buttons: [
      {
        name: "Occupazione",
        style: 'style_scavo',
        geometryType: 'Polygon',
        tooltip: 'Disegna area occupazione suolo pubblico',
        target: 'occupazione'
      },
    ],
    layers: [
      {
        name: "Occupazione suolo pubblico",
        style: "style_scavo",
        id: 'occupazione'
      },
    ],
    features: [
      {
        type: 'occupazione',
        features: []
      }
    ]
  };

  constructor(
    private validationService: ValidationService,
    private formService: FormUtilService,
    private dialog: DialogMessageService
  ) { }

  ngOnInit(): void {
    this.form = this.formService.createDetailsOccupazioneAreePubbliche();
    this.form.patchValue(this.data);
    this.patchDate();
    this.form.disable();
  }

  resetDetails(){
    this.form.patchValue(this.data);
    this.patchDate();
    this.form.disable();
  }

  patchDate(){
    this.form.get('start_date').patchValue(this.formService.convertItalianDate(this.data.start_date));
    if(this.data.end_date){
      this.form.get('end_date').patchValue(this.formService.convertItalianDate(this.data.end_date));
    }
  }

  changeTipologia(event: any, target: string[]){
    let value = event.value
    if(value === 'permanent'){
      target.forEach(element => {
        this.form.get(element.split("/")).disable();
      });
    } else {
      target.forEach(element => {
        this.form.get(element.split("/")).enable();
      });
    }
  }

  minDate(){
    var result = new Date();
    result.setDate(result.getDate() + 20);
    return result;
  }

  differenceDate(form: AbstractControl, value1: string, value2: string, dest: string) {
    if (form.get(value1).value === null || form.get(value1).value === '' || form.get(value2).value === undefined)
      return;
    if (form.get(value2).value === null || form.get(value2).value === '' || form.get(value2).value === undefined)
      return;
    let date1: any = new Date(form.get(value1).value);
    let date2: any = new Date(form.get(value2).value);
    form.get(dest).patchValue(Math.floor((date1 - date2) / (1000 * 60 * 60 * 24)));
  }

  calculateMinDate(form: AbstractControl, target: string) {
    if (form.get(target).value === null || form.get(target).value === '')
      return;
    let date: any = new Date(form.get(target).value);
    return new Date(date.setDate(date.getDate()));
  }

  changeOther(event: any, control: AbstractControl){
    switch(event.checked){
      case true:
        control.enable();
        control.updateValueAndValidity();
        break;
      case false:
        control.disable()
        control.updateValueAndValidity();
        break;
    }
  }

  modify(){
    if(this.can_modify){
      this.form.disable();
      this.resetDetails();
    } else {
      this.form.enable();
      this.form.get('start_date').disable();
      this.form.get('end_date').disable();
    }
    this.can_modify = !this.can_modify;
  }

  save(){
    if(this.form.valid){
      this.isLoading = true
      let result = this.form.getRawValue();
      this.formatData(result);
      this.update_details.next({details: result});
    } else {
      this.validationService.validateAllFormFields(this.form);
    }
  }

  completeModify(){
    this.isLoading = false;
    this.can_modify = false;
    this.form.disable();
  }

  abortModify(){
    this.isLoading = false;
  }

  formatData(body: any){
    if(body.end_date){
      body.end_date = formatDate(body.end_date, "yyyy-MM-dd", "en");
    }
    if(body.start_date){
      body.start_date = formatDate(body.start_date, "yyyy-MM-dd", "en");
    }
  }

  getErrorMessage(control: AbstractControl) {
    return this.validationService.getErrorMessage(control);
  }

  openMap() {
    event.preventDefault();
    event.stopPropagation();
    let features = [
      {
        type: 'occupazione',
        features: this.form.get('affected_area').value != '' ? [this.form.get('affected_area').value] : []
      }
    ]
    this.map_cfg.features = features;
    this.dialog.openMap(this.map_cfg).subscribe(value => {
      if (value) {
        this.map_cfg.features = value;
        value.forEach(feature => {
          switch(feature.type){
            case 'occupazione':
              this.form.get('affected_area').patchValue(feature.features[0] || '');
              break;
          }
        });
        console.log("Dati pratica",this.form.value);
      }
      console.log('Mappa chiusa', value);
    }, error => {
      console.log('errore mappa');
    });
  }
}


ngOnInit(): void {
    this.form = this.formService.createDetailsOccupazioneAreePubbliche();
    this.form.patchValue(this.data);
    this.patchDate();
    this.form.disable();
  }


resetDetails(){
    this.form.patchValue(this.data);
    this.patchDate();
    this.form.disable();
  }


patchDate(){
    this.form.get('start_date').patchValue(this.formService.convertItalianDate(this.data.start_date));
    if(this.data.end_date){
      this.form.get('end_date').patchValue(this.formService.convertItalianDate(this.data.end_date));
    }
  }


changeTipologia(event: any, target: string[]){
    let value = event.value
    if(value === 'permanent'){
      target.forEach(element => {
        this.form.get(element.split("/")).disable();
      });
    } else {
      target.forEach(element => {
        this.form.get(element.split("/")).enable();
      });
    }
  }


minDate(){
    var result = new Date();
    result.setDate(result.getDate() + 20);
    return result;
  }


differenceDate(form: AbstractControl, value1: string, value2: string, dest: string) {
    if (form.get(value1).value === null || form.get(value1).value === '' || form.get(value2).value === undefined)
      return;
    if (form.get(value2).value === null || form.get(value2).value === '' || form.get(value2).value === undefined)
      return;
    let date1: any = new Date(form.get(value1).value);
    let date2: any = new Date(form.get(value2).value);
    form.get(dest).patchValue(Math.floor((date1 - date2) / (1000 * 60 * 60 * 24)));
  }


calculateMinDate(form: AbstractControl, target: string) {
    if (form.get(target).value === null || form.get(target).value === '')
      return;
    let date: any = new Date(form.get(target).value);
    return new Date(date.setDate(date.getDate()));
  }


changeOther(event: any, control: AbstractControl){
    switch(event.checked){
      case true:
        control.enable();
        control.updateValueAndValidity();
        break;
      case false:
        control.disable()
        control.updateValueAndValidity();
        break;
    }
  }


modify(){
    if(this.can_modify){
      this.form.disable();
      this.resetDetails();
    } else {
      this.form.enable();
      this.form.get('start_date').disable();
      this.form.get('end_date').disable();
    }
    this.can_modify = !this.can_modify;
  }


save(){
    if(this.form.valid){
      this.isLoading = true
      let result = this.form.getRawValue();
      this.formatData(result);
      this.update_details.next({details: result});
    } else {
      this.validationService.validateAllFormFields(this.form);
    }
  }


completeModify(){
    this.isLoading = false;
    this.can_modify = false;
    this.form.disable();
  }


abortModify(){
    this.isLoading = false;
  }


formatData(body: any){
    if(body.end_date){
      body.end_date = formatDate(body.end_date, "yyyy-MM-dd", "en");
    }
    if(body.start_date){
      body.start_date = formatDate(body.start_date, "yyyy-MM-dd", "en");
    }
  }


getErrorMessage(control: AbstractControl) {
    return this.validationService.getErrorMessage(control);
  }


openMap() {
    event.preventDefault();
    event.stopPropagation();
    let features = [
      {
        type: 'occupazione',
        features: this.form.get('affected_area').value != '' ? [this.form.get('affected_area').value] : []
      }
    ]
    this.map_cfg.features = features;
    this.dialog.openMap(this.map_cfg).subscribe(value => {
      if (value) {
        this.map_cfg.features = value;
        value.forEach(feature => {
          switch(feature.type){
            case 'occupazione':
              this.form.get('affected_area').patchValue(feature.features[0] || '');
              break;
          }
        });
        console.log("Dati pratica",this.form.value);
      }
      console.log('Mappa chiusa', value);
    }, error => {
      console.log('errore mappa');
    });
  }


(params) => {

        const { target, command, projectName, version } = params;
        const outputDir = `../${projectName}_qqgame`;
        if (command == 'build') {
            return {
                outputDir,
                commands: [
                    new CleanPlugin({ matchers: ["js", "resource"] }),
                    new CompilePlugin({ libraryType: "debug", defines: { DEBUG: true, RELEASE: false } }),
                    new ExmlPlugin('commonjs'), // 非 EUI 项目关闭此设置
                    // new EuiCompilerPlugin(),//新的 eui 编译器
                    new QQgamePlugin(useQQPlugin, pluginList),
                    new ManifestPlugin({ output: 'manifest.js', qqPlugin: { use: useQQPlugin, pluginList: pluginList } })
                ]
            }
        }
        else if (command == 'publish') {
            return {
                outputDir,
                commands: [
                    new CleanPlugin({ matchers: ["js", "resource"] }),
                    new CompilePlugin({ libraryType: "release", defines: { DEBUG: false, RELEASE: true } }),
                    // new WebpackBundlePlugin({ libraryType: "debug", defines: { DEBUG: false, RELEASE: true } }),//新的 Webpack 编译器
                    new ExmlPlugin('commonjs'), // 非 EUI 项目关闭此设置
                    // new EuiCompilerPlugin(),//新的 eui 编译器
                    new QQgamePlugin(useQQPlugin, pluginList),
                    new UglifyPlugin([
                        // 使用 EUI 项目，要压缩皮肤文件，可以开启这个压缩配置
                        // {
                        //     sources: ["resource/default.thm.js"],
                        //     target: "default.thm.min.js"
                        // },
                        {
                            sources: ["main.js"],
                            target: "main.min.js"
                        }
                    ]),
                    new ManifestPlugin({ output: 'manifest.js', qqPlugin: { use: useQQPlugin, pluginList: pluginList } })
                ]
            }
        }
        else {
            throw `unknown command : ${params.command}`;
        }
    }


() => {
  const clientForm = shallow(
    <ClientForm
      isClientFormVisible={true}
      createClient={({}) => {}}


() => {
  const toggleClientFormSpy = jest.fn();
  const clientForm = shallow(
    <ClientForm
      isClientFormVisible={true}
      createClient={({}) => {}}


(l) => l.Key === test


(l) =>
      l.Key.startsWith(this.props.genlocales[0].Key)


(l) => (
                  <MenuItem value={l.Key}


(l) => l.Key.startsWith(this.state.selectedGenLocale)


(l) => (
                    <MenuItem value={l.Key}


(p) => (
                  <MenuItem value={p.Key}


export default class PacksPage extends React.Component<
  IPacksPageProps,
  IPacksPageState
> {
  constructor(props: IPacksPageProps) {
    super(props);
    this.state = {
      selectedGenLocale:
        props.genlocales.length === 0 ? "" : props.genlocales[0].Key,
      selectedLocale:
        props.locales.length === 0
          ? ""
          : this.findBestLocale(props.genlocales[0].Key),
      selectedPackage:
        props.packages.length === 0 ? -1 : parseInt(props.packages[0].Key),
    };
  }

  private findBestLocale(genLocale: string): string {
    var test = `${genLocale}-${genLocale.toUpperCase()}`;
    var res = this.props.locales.filter((l) => l.Key === test);
    if (res.length > 0) {
      return res[0].Key;
    }
    return this.props.locales.filter((l) =>
      l.Key.startsWith(this.props.genlocales[0].Key)
    )[0].Key;
  }

  public render(): JSX.Element {
    return (

            <FormControl style={{ minWidth: "200px" }}>
              <Select
                value={this.state.selectedGenLocale}
                onChange={(e) =>
                  this.setState({
                    selectedGenLocale: e.target.value as string,
                    selectedLocale: this.findBestLocale(
                      e.target.value as string
                    ),
                  })
                }
                style={


interface IPacksPageProps {
  module: IAppModule;
  packages: { Key: string; Value: string }[];
  locales: { Key: string; Value: string }[];
  genlocales: { Key: string; Value: string }[];
}


interface IPacksPageState {
  selectedPackage: number;
  selectedGenLocale: string;
  selectedLocale: string;
}


private findBestLocale(genLocale: string): string {
    var test = `${genLocale}-${genLocale.toUpperCase()}`;
    var res = this.props.locales.filter((l) => l.Key === test);
    if (res.length > 0) {
      return res[0].Key;
    }
    return this.props.locales.filter((l) =>
      l.Key.startsWith(this.props.genlocales[0].Key)
    )[0].Key;
  }


public render(): JSX.Element {
    return (

            <FormControl style={{ minWidth: "200px" }}>
              <Select
                value={this.state.selectedGenLocale}
                onChange={(e) =>
                  this.setState({
                    selectedGenLocale: e.target.value as string,
                    selectedLocale: this.findBestLocale(
                      e.target.value as string
                    ),
                  })
                }


() => {

	const pluginId = "c061d18abea0";
	let activityService: ActivityService;
	let userSettingsService: UserSettingsService;
	let syncService: SyncService;
	let component: FitnessTrendComponent;
	let fixture: ComponentFixture<FitnessTrendComponent>;

	beforeEach((done: Function) => {

		spyOn(ExternalUpdatesService, "getBrowserExternalMessages").and.returnValue({
			addListener: (request: any, sender: chrome.runtime.MessageSender) => {
			}
		});

		spyOn(ExternalUpdatesService, "getBrowserPluginId").and.returnValue(pluginId);

		TestBed.configureTestingModule({
			imports: [
				CoreModule,
				SharedModule,
				FitnessTrendModule
			]
		}).compileComponents();

		// Retrieve injected service
		activityService = TestBed.get(ActivityService);
		userSettingsService = TestBed.get(UserSettingsService);
		syncService = TestBed.get(SyncService);

		// Mocking
		spyOn(activityService, "fetch").and.returnValue(Promise.resolve(_.cloneDeep(TEST_SYNCED_ACTIVITIES)));
		spyOn(userSettingsService, "fetch").and.returnValue(Promise.resolve(_.cloneDeep(userSettingsData)));

		spyOn(syncService, "getLastSyncDateTime").and.returnValue(Promise.resolve(Date.now()));
		spyOn(syncService, "getSyncState").and.returnValue(Promise.resolve(SyncState.SYNCED));

		fixture = TestBed.createComponent(FitnessTrendComponent);
		component = fixture.componentInstance;

		component.fitnessTrendConfigModel = FitnessTrendComponent.DEFAULT_CONFIG;

		fixture.detectChanges();

		done();
	});

	it("should create", (done: Function) => {
		expect(component).toBeTruthy();
		done();
	});

	it("should keep enabled: PSS impulses, SwimSS impulses & Training Zones on toggles verification with HRSS=ON", (done: Function) => {

		// Given
		component.fitnessTrendConfigModel.heartRateImpulseMode = HeartRateImpulseMode.HRSS;
		component.isTrainingZonesEnabled = true;
		component.isPowerMeterEnabled = true;
		component.isSwimEnabled = true;
		component.isEBikeRidesEnabled = true;
		const localStorageGetItemSpy = spyOn(localStorage, "getItem").and.returnValue("true"); // Indicate that toggles are enabled from user saved prefs (local storage)

		// When
		component.updateTogglesStatesAlongHrMode();

		// Then
		expect(component.isTrainingZonesEnabled).toEqual(true);
		expect(component.isPowerMeterEnabled).toEqual(true);
		expect(component.isSwimEnabled).toEqual(true);
		expect(component.isEBikeRidesEnabled).toEqual(true);
		expect(localStorageGetItemSpy).toHaveBeenCalledTimes(3);

		done();
	});

	it("should disable: PSS impulses, SwimSS impulses & Training Zones on toggles verification with TRIMP=ON", (done: Function) => {

		// Given
		component.fitnessTrendConfigModel.heartRateImpulseMode = HeartRateImpulseMode.TRIMP;
		component.isTrainingZonesEnabled = true;
		component.isPowerMeterEnabled = true;
		component.isSwimEnabled = true;
		component.isEBikeRidesEnabled = true;
		const localStorageGetItemSpy = spyOn(localStorage, "getItem").and.returnValue(undefined); // Indicate that toggles are NOT enabled from user saved prefs (local storage)

		// When
		component.updateTogglesStatesAlongHrMode();

		// Then
		expect(component.isTrainingZonesEnabled).toEqual(false);
		expect(component.isPowerMeterEnabled).toEqual(false);
		expect(component.isSwimEnabled).toEqual(false);
		expect(component.isEBikeRidesEnabled).toEqual(true);
		expect(localStorageGetItemSpy).toHaveBeenCalledTimes(0);

		done();
	});

}


(done: Function) => {

		spyOn(ExternalUpdatesService, "getBrowserExternalMessages").and.returnValue({
			addListener: (request: any, sender: chrome.runtime.MessageSender) => {
			}
		});

		spyOn(ExternalUpdatesService, "getBrowserPluginId").and.returnValue(pluginId);

		TestBed.configureTestingModule({
			imports: [
				CoreModule,
				SharedModule,
				FitnessTrendModule
			]
		}).compileComponents();

		// Retrieve injected service
		activityService = TestBed.get(ActivityService);
		userSettingsService = TestBed.get(UserSettingsService);
		syncService = TestBed.get(SyncService);

		// Mocking
		spyOn(activityService, "fetch").and.returnValue(Promise.resolve(_.cloneDeep(TEST_SYNCED_ACTIVITIES)));
		spyOn(userSettingsService, "fetch").and.returnValue(Promise.resolve(_.cloneDeep(userSettingsData)));

		spyOn(syncService, "getLastSyncDateTime").and.returnValue(Promise.resolve(Date.now()));
		spyOn(syncService, "getSyncState").and.returnValue(Promise.resolve(SyncState.SYNCED));

		fixture = TestBed.createComponent(FitnessTrendComponent);
		component = fixture.componentInstance;

		component.fitnessTrendConfigModel = FitnessTrendComponent.DEFAULT_CONFIG;

		fixture.detectChanges();

		done();
	}


(request: any, sender: chrome.runtime.MessageSender) => {
			}


(done: Function) => {
		expect(component).toBeTruthy();
		done();
	}


(done: Function) => {

		// Given
		component.fitnessTrendConfigModel.heartRateImpulseMode = HeartRateImpulseMode.HRSS;
		component.isTrainingZonesEnabled = true;
		component.isPowerMeterEnabled = true;
		component.isSwimEnabled = true;
		component.isEBikeRidesEnabled = true;
		const localStorageGetItemSpy = spyOn(localStorage, "getItem").and.returnValue("true"); // Indicate that toggles are enabled from user saved prefs (local storage)

		// When
		component.updateTogglesStatesAlongHrMode();

		// Then
		expect(component.isTrainingZonesEnabled).toEqual(true);
		expect(component.isPowerMeterEnabled).toEqual(true);
		expect(component.isSwimEnabled).toEqual(true);
		expect(component.isEBikeRidesEnabled).toEqual(true);
		expect(localStorageGetItemSpy).toHaveBeenCalledTimes(3);

		done();
	}


(done: Function) => {

		// Given
		component.fitnessTrendConfigModel.heartRateImpulseMode = HeartRateImpulseMode.TRIMP;
		component.isTrainingZonesEnabled = true;
		component.isPowerMeterEnabled = true;
		component.isSwimEnabled = true;
		component.isEBikeRidesEnabled = true;
		const localStorageGetItemSpy = spyOn(localStorage, "getItem").and.returnValue(undefined); // Indicate that toggles are NOT enabled from user saved prefs (local storage)

		// When
		component.updateTogglesStatesAlongHrMode();

		// Then
		expect(component.isTrainingZonesEnabled).toEqual(false);
		expect(component.isPowerMeterEnabled).toEqual(false);
		expect(component.isSwimEnabled).toEqual(false);
		expect(component.isEBikeRidesEnabled).toEqual(true);
		expect(localStorageGetItemSpy).toHaveBeenCalledTimes(0);

		done();
	}


() => {
  const toast = useToast()
  const formik = useFormik({
    initialValues: { nickname: '', username: '', email: '', password: '' },
    validationSchema: SignUpSchema,
    onSubmit: async (values) => {
      values.username = values.username.toLowerCase()
      await signUp(values).catch(({ code }: { code: string }) => {
        if (code === 'auth/username-already-in-use') {
          showSimpleToast(toast, 'Nome de usuário já em uso')
        } else if (code === 'auth/email-already-in-use') {
          showSimpleToast(toast, 'Email já cadastrado')
        } else if (code === 'auth/invalid-email') {
          showSimpleToast(toast, 'Email inválido')
        } else if (code === 'auth/weak-password') {
          showSimpleToast(toast, 'A senha deve ter uma mistura de letras maiúsculas, letras minúsculas e números')
        } else {
          showSimpleToast(toast, 'Erro inesperado, tente novamente mais tarde.')
        }
      })
    },
  })
  const [isPasswordShowing, setIsPasswordShowing] = useState(false)

  return (
    <ScrollView>
      <Box flex={1} padding={8} width="100%">
        <Box alignSelf="center">
          <Text fontWeight="700" fontSize="xl">
            Crie sua conta
          </Text>
          <Text marginBottom={6}>Preencha o formulário e já tenha sua conta nova em mãos.</Text>
        </Box>

        <VStack space={4} width="100%" marginBottom={8}>
          <FormControl
            isInvalid={!!formik.touched.nickname && !!formik.errors.nickname}
            isDisabled={formik.isSubmitting}
          >
            <FormControl.Label>Apelido</FormControl.Label>
            <Input
              onChangeText={formik.handleChange('nickname')}
              onBlur={formik.handleBlur('nickname')}
              value={formik.values.nickname}
              placeholder="Apelido"
            />
            <FormControl.ErrorMessage>{formik.errors.nickname}</FormControl.ErrorMessage>
          </FormControl>

          <FormControl
            isInvalid={!!formik.touched.username && !!formik.errors.username}


async (values) => {
      values.username = values.username.toLowerCase()
      await signUp(values).catch(({ code }: { code: string }) => {
        if (code === 'auth/username-already-in-use') {
          showSimpleToast(toast, 'Nome de usuário já em uso')
        } else if (code === 'auth/email-already-in-use') {
          showSimpleToast(toast, 'Email já cadastrado')
        } else if (code === 'auth/invalid-email') {
          showSimpleToast(toast, 'Email inválido')
        } else if (code === 'auth/weak-password') {
          showSimpleToast(toast, 'A senha deve ter uma mistura de letras maiúsculas, letras minúsculas e números')
        } else {
          showSimpleToast(toast, 'Erro inesperado, tente novamente mais tarde.')
        }
      })
    }


({ code }: { code: string }) => {
        if (code === 'auth/username-already-in-use') {
          showSimpleToast(toast, 'Nome de usuário já em uso')
        } else if (code === 'auth/email-already-in-use') {
          showSimpleToast(toast, 'Email já cadastrado')
        } else if (code === 'auth/invalid-email') {
          showSimpleToast(toast, 'Email inválido')
        } else if (code === 'auth/weak-password') {
          showSimpleToast(toast, 'A senha deve ter uma mistura de letras maiúsculas, letras minúsculas e números')
        } else {
          showSimpleToast(toast, 'Erro inesperado, tente novamente mais tarde.')
        }
      }


isPasswordShowing ? (
                    <Icon as={Feather} name="eye-off" size={4} color="primary.500" />
                  ) : (
                    <Icon as={Feather} name="eye" size={4} color="primary.500"


(hours) => hours / 24


(rads) => rads * 24


(turbidity) => {
    CommandManager.instance.setPropertyOnSelection('turbidity', turbidity)
  }


(rayleigh) => {
    CommandManager.instance.setPropertyOnSelection('rayleigh', rayleigh)
  }


(luminance) => {
    CommandManager.instance.setPropertyOnSelection('luminance', luminance)
  }


(mieCoefficient) => {
    CommandManager.instance.setPropertyOnSelection('mieCoefficient', mieCoefficient)
  }


(mieDirectionalG) => {
    CommandManager.instance.setPropertyOnSelection('mieDirectionalG', mieDirectionalG)
  }


(inclination) => {
    CommandManager.instance.setPropertyOnSelection('inclination', inclination)
  }


(azimuth) => {
    CommandManager.instance.setPropertyOnSelection('azimuth', azimuth)
  }


(distance) => {
    CommandManager.instance.setPropertyOnSelection('distance', distance)
  }


(backgroundType) => {
    CommandManager.instance.setPropertyOnSelection('backgroundType', backgroundType)
  }


(path) => {
    CommandManager.instance.setPropertyOnSelection('equirectangularPath', path)
  }


(path) => {
    CommandManager.instance.setPropertyOnSelection('cubemapPath', path)
  }


(backgroundColor) => {
    CommandManager.instance.setPropertyOnSelection('backgroundColor', backgroundColor)
  }


(node) => (
    <>
      <NumericInputGroup
        name="Time of Day"


(value, onChange) => (
    <>
      <InputGroup name="Texture"


(node) => (
    <>
      <InputGroup name="Color"


(node) => {
    switch (node.backgroundType) {
      case SkyTypeEnum.equirectangular as any:
        return this.renderTextureSettings((node as any).equirectangularPath, this.onChangeEquirectangularPathOption)
      case SkyTypeEnum.cubemap as any:
        return this.renderTextureSettings((node as any).cubemapPath, this.onChangeCubemapPathOption)
      case SkyTypeEnum.color as any:
        return this.renderColorSettings(node)
      default:
        return this.renderSkyboxSettings(node)
    }
  }


/**
 * SkyboxNodeEditor component class used to render editor view to customize component property.
 *
 * @author Robert Long
 * @type {class component}
 */
export class SkyboxNodeEditor extends Component<SkyboxNodeEditorProps, {}> {
  //defining iconComponent with icon name
  static iconComponent = Cloud
  static description = i18n.t('editor:properties.skybox.description')

  //function to handle changes in turbidity Property
  onChangeTurbidity = (turbidity) => {
    CommandManager.instance.setPropertyOnSelection('turbidity', turbidity)
  }

  //function to handle changes in rayleigh property
  onChangeRayleigh = (rayleigh) => {
    CommandManager.instance.setPropertyOnSelection('rayleigh', rayleigh)
  }

  //function to handle the changes in luminance property
  onChangeLuminance = (luminance) => {
    CommandManager.instance.setPropertyOnSelection('luminance', luminance)
  }

  //function to handle the changes in mieCoefficient property
  onChangeMieCoefficient = (mieCoefficient) => {
    CommandManager.instance.setPropertyOnSelection('mieCoefficient', mieCoefficient)
  }

  //function to handle the changes in mieDirectionalG property
  onChangeMieDirectionalG = (mieDirectionalG) => {
    CommandManager.instance.setPropertyOnSelection('mieDirectionalG', mieDirectionalG)
  }

  //function to handle the changes in inclination
  onChangeInclination = (inclination) => {
    CommandManager.instance.setPropertyOnSelection('inclination', inclination)
  }

  //function to handle changes azimuth
  onChangeAzimuth = (azimuth) => {
    CommandManager.instance.setPropertyOnSelection('azimuth', azimuth)
  }

  //function to handle changes in distance property
  onChangeDistance = (distance) => {
    CommandManager.instance.setPropertyOnSelection('distance', distance)
  }

  //function to handle the changes skyType
  onChangeSkyOption = (backgroundType) => {
    CommandManager.instance.setPropertyOnSelection('backgroundType', backgroundType)
  }

  //function to handle the changes backgroundPath
  onChangeEquirectangularPathOption = (path) => {
    CommandManager.instance.setPropertyOnSelection('equirectangularPath', path)
  }

  onChangeCubemapPathOption = (path) => {
    CommandManager.instance.setPropertyOnSelection('cubemapPath', path)
  }

  //function to handle the changes backgroundPath
  onChangeColorOption = (backgroundColor) => {
    CommandManager.instance.setPropertyOnSelection('backgroundColor', backgroundColor)
  }

  //creating editor view for skybox setting
  renderSkyboxSettings = (node) => (
    <>
      <NumericInputGroup
        name="Time of Day"
        label={this.props.t('editor:properties.skybox.lbl-timeOfDay')}
        smallStep={0.1}
        mediumStep={0.5}
        largeStep={1}
        min={0}
        max={24}
        convertFrom={radiansToHours}
        convertTo={hoursToRadians}
        value={node.azimuth}
        onChange={this.onChangeAzimuth}
        unit="h"
      />
      <RadianNumericInputGroup
        name="Latitude"
        label={this.props.t('editor:properties.skybox.lbl-latitude')}
        min={-90}


/**
 * SkyboxNodeEditorProps declaring props for SkyboxNodeEditor.
 *
 * @author Robert Long
 * @type {Object}
 */
type SkyboxNodeEditorProps = {
  node?: object
  t: Function
}


() => {
            return Bluebird.fromCallback(
              fs.readFile.bind(
                null,
                node.path
              )
            )
          }


/**
 * A node converter for socko-api's CartridgeNodeInterfaces
 */
export class CartridgeNodeConverter implements NodeConverterInterface {
  private _log: Logger

  constructor () {
    this._log = getLogger('socko-converter-file:converter:CartridgeNodeConverter')
  }

  public isEligible (options: ConverterOptionsInterface, node: FileNode): boolean {
    let check = node.name.endsWith(options.cartridgeNodeExtension)
    if (check) {
      this._log.debug('This is a Cartridge node.')
    }
    return check
  }

  public convert (options: ConverterOptionsInterface, node: FileNode): Bluebird<SockoNodeInterface> {
    let name = node.name.slice(0, node.name.indexOf(options.cartridgeNodeExtension))
    return Bluebird.resolve(
      new CartridgeNodeBuilder()
        .withName(name)
        .withReadContent(
          () => {
            return Bluebird.fromCallback(
              fs.readFile.bind(
                null,
                node.path
              )
            )
          }
        )
        .build()
    )
  }
}


public isEligible (options: ConverterOptionsInterface, node: FileNode): boolean {
    let check = node.name.endsWith(options.cartridgeNodeExtension)
    if (check) {
      this._log.debug('This is a Cartridge node.')
    }
    return check
  }


public convert (options: ConverterOptionsInterface, node: FileNode): Bluebird<SockoNodeInterface> {
    let name = node.name.slice(0, node.name.indexOf(options.cartridgeNodeExtension))
    return Bluebird.resolve(
      new CartridgeNodeBuilder()
        .withName(name)
        .withReadContent(
          () => {
            return Bluebird.fromCallback(
              fs.readFile.bind(
                null,
                node.path
              )
            )
          }
        )
        .build()
    )
  }


photosVideos => {
                this.photosVideos = photosVideos;
            }


@Component({
    selector     : 'profile-photos-videos',
    templateUrl  : './photos-videos.component.html',
    styleUrls    : ['./photos-videos.component.scss'],
    encapsulation: ViewEncapsulation.None,
    animations   : fuseAnimations
})
export class ProfilePhotosVideosComponent implements OnInit, OnDestroy
{
    photosVideos: any;

    // Private
    private _unsubscribeAll: Subject<any>;

    /**
     * Constructor
     *
     * @param {ProfileService} _profileService
     */
    constructor(
        private _profileService: ProfileService
    )
    {
        // Set the private defaults
        this._unsubscribeAll = new Subject();
    }

    // -----------------------------------------------------------------------------------------------------
    // @ Lifecycle hooks
    // -----------------------------------------------------------------------------------------------------

    /**
     * On init
     */
    ngOnInit(): void
    {
        this._profileService.photosVideosOnChanged
            .pipe(takeUntil(this._unsubscribeAll))
            .subscribe(photosVideos => {
                this.photosVideos = photosVideos;
            });
    }

    /**
     * On destroy
     */
    ngOnDestroy(): void
    {
        // Unsubscribe from all subscriptions
        this._unsubscribeAll.next();
        this._unsubscribeAll.complete();
    }
}


// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
     * On init
     */
ngOnInit(): void
    {
        this._profileService.photosVideosOnChanged
            .pipe(takeUntil(this._unsubscribeAll))
            .subscribe(photosVideos => {
                this.photosVideos = photosVideos;
            });
    }


/**
     * On destroy
     */
ngOnDestroy(): void
    {
        // Unsubscribe from all subscriptions
        this._unsubscribeAll.next();
        this._unsubscribeAll.complete();
    }


/**
 * HTTPエラー。Variant Also Negotiates.
 */
class HttpVariantAlsoNegotiatesException extends HttpException {

	/**
	 * @constructor
	 * @public
	 * @param {number} status
	 * @param {string} code=null
	 * @param {string} message=""
	 */
	constructor(status:number, code:string=null, message:string="") {
		super(status, code, message == null || message == "" ? "HTTPエラー。Variant Also Negotiates." : message);
	}

}


function assignOptionIds(
  options: (OptionDescriptor | ActionListItemDescriptor)[],
  comboBoxId: string,
): OptionDescriptor[] | ActionListItemDescriptor[] {
  options.map(
    (
      option: OptionDescriptor | ActionListItemDescriptor,
      optionIndex: number,
    ) => {
      option.id = `${comboBoxId}-${optionIndex}`;
    },
  );
  return options;
}


function optionsAreEqual(
  firstOptions: (OptionDescriptor | ActionListItemDescriptor)[],
  secondOptions: (OptionDescriptor | ActionListItemDescriptor)[],
) {
  if (firstOptions.length !== secondOptions.length) {
    return false;
  }
  return firstOptions.every(
    (firstItem: OptionDescriptor | ActionListItemDescriptor, index: number) => {
      const secondItem = secondOptions[index];
      if (isOption(firstItem)) {
        if (isOption(secondItem)) {
          return firstItem.value === secondItem.value;
        }
        return false;
      } else {
        if (!isOption(secondItem)) {
          return firstItem.content === secondItem.content;
        }
        return false;
      }
    },
  );
}


function isOption(
  navigableOption: OptionDescriptor | ActionListItemDescriptor,
): navigableOption is OptionDescriptor {
  return (navigableOption as OptionDescriptor).value !== undefined;
}


function filterForOptions(
  mixedArray: (ActionListItemDescriptor | OptionDescriptor)[],
): OptionDescriptor[] {
  return mixedArray.filter((item) => isOption(item)) as OptionDescriptor[];
}


(subscriberCallback) => subscriberCallback()


(callback: () => void) => {
    this.subscriptions.push(callback);
  }


(callback: () => void) => {
    this.subscriptions = this.subscriptions.filter(
      (subscription) => subscription !== callback,
    );
  }


(subscription) => subscription !== callback


() => {
    this.selectNextOption();
    this.handlePopoverOpen;
  }


() => {
    this.selectPreviousOption();
    this.handlePopoverOpen;
  }


() => {
    const {selectedOption} = this.state;

    if (this.state.popoverActive && selectedOption) {
      if (isOption(selectedOption)) {
        this.handleSelection(selectedOption.value);
      } else {
        selectedOption.onAction && selectedOption.onAction();
      }
    }

    this.handlePopoverOpen;
  }


() => {
    this.setState({popoverActive: true, popoverWasActive: true});
  }


() => {
    this.setState({popoverActive: false, popoverWasActive: false}, () => {
      this.resetVisuallySelectedOptions();
    });
  }


() => {
      this.resetVisuallySelectedOptions();
    }


() => {
    !this.state.popoverActive && this.setState({popoverActive: true});
  }


(newSelected: string) => {
    const {selected, allowMultiple} = this.props;
    let newlySelectedOptions = selected;
    if (selected.includes(newSelected)) {
      newlySelectedOptions.splice(newlySelectedOptions.indexOf(newSelected), 1);
    } else if (allowMultiple) {
      newlySelectedOptions.push(newSelected);
    } else {
      newlySelectedOptions = [newSelected];
    }

    this.selectOptions(newlySelectedOptions);
  }


(selected: string[]) => {
    const {onSelect, allowMultiple} = this.props;
    selected && onSelect(selected);
    if (!allowMultiple) {
      this.resetVisuallySelectedOptions();
      this.setState({popoverActive: false, popoverWasActive: false});
    }
  }


(
    newOptions: (OptionDescriptor | ActionListItemDescriptor)[],
  ) => {
    const {selectedIndex, selectedOption} = this.state;
    if (selectedOption && newOptions.includes(selectedOption)) {
      this.selectOptionAtIndex(newOptions.indexOf(selectedOption));
    } else if (selectedIndex > newOptions.length - 1) {
      this.resetVisuallySelectedOptions();
    } else {
      this.selectOptionAtIndex(selectedIndex);
    }
  }


() => {
    const {navigableOptions} = this.state;
    this.setState({
      selectedOption: undefined,
      selectedIndex: -1,
    });
    navigableOptions &&
      navigableOptions.forEach((option) => {
        option.active = false;
      });
  }


(option) => {
        option.active = false;
      }


() => {
    this.setState({popoverActive: false, popoverWasActive: false});
  }


() => {
    const {popoverActive, navigableOptions} = this.state;

    !popoverActive &&
      navigableOptions &&
      navigableOptions.length > 0 &&
      this.setState({popoverActive: true, popoverWasActive: true});
  }


() => {
    const {selectedIndex, navigableOptions} = this.state;

    if (!navigableOptions || navigableOptions.length === 0) {
      return;
    }

    let newIndex = selectedIndex;

    if (selectedIndex + 1 >= navigableOptions.length) {
      newIndex = 0;
    } else {
      newIndex++;
    }

    this.selectOptionAtIndex(newIndex);
  }


() => {
    const {selectedIndex, navigableOptions} = this.state;

    if (!navigableOptions || navigableOptions.length === 0) {
      return;
    }

    let newIndex = selectedIndex;

    if (selectedIndex <= 0) {
      newIndex = navigableOptions.length - 1;
    } else {
      newIndex--;
    }

    this.selectOptionAtIndex(newIndex);
  }


(newOptionIndex: number) => {
    const {navigableOptions, selectedOption: oldSelectedOption} = this.state;
    if (!navigableOptions || navigableOptions.length === 0) {
      return;
    }
    const newSelectedOption = navigableOptions[newOptionIndex];

    this.setState(
      {
        selectedOption: newSelectedOption,
        selectedIndex: newOptionIndex,
      },
      () => {
        this.visuallyUpdateSelectedOption(newSelectedOption, oldSelectedOption);
      },
    );
  }


() => {
        this.visuallyUpdateSelectedOption(newSelectedOption, oldSelectedOption);
      }


(
    newOption: OptionDescriptor | ActionListItemDescriptor,
    oldOption: OptionDescriptor | ActionListItemDescriptor | undefined,
  ) => {
    if (oldOption) {
      oldOption.active = false;
    }
    if (newOption) {
      newOption.active = true;
    }
  }


(
      option: OptionDescriptor | ActionListItemDescriptor,
      optionIndex: number,
    ) => {
      option.id = `${comboBoxId}-${optionIndex}`;
    }


(firstItem: OptionDescriptor | ActionListItemDescriptor, index: number) => {
      const secondItem = secondOptions[index];
      if (isOption(firstItem)) {
        if (isOption(secondItem)) {
          return firstItem.value === secondItem.value;
        }
        return false;
      } else {
        if (!isOption(secondItem)) {
          return firstItem.content === secondItem.content;
        }
        return false;
      }
    }


(item) => isOption(item)


export interface State {
  comboBoxId: string;
  selectedOption?: OptionDescriptor | ActionListItemDescriptor | undefined;
  selectedIndex: number;
  selectedOptions: string[];
  navigableOptions: (OptionDescriptor | ActionListItemDescriptor)[];
  popoverActive: boolean;
  popoverWasActive: boolean;
}


export interface Props {
  /** A unique identifier for the ComboBox */
  id?: string;
  /** Collection of options to be listed */
  options: OptionDescriptor[];
  /** The selected options */
  selected: string[];
  /** The text field component attached to the list of options */
  textField: React.ReactElement<any>;
  /** The preferred direction to open the popover */
  preferredPosition?: PreferredPosition;
  /** Title of the list of options */
  listTitle?: string;
  /** Allow more than one option to be selected */
  allowMultiple?: boolean;
  /** Actions to be displayed before the list of options */
  actionsBefore?: ActionListItemDescriptor[];
  /** Actions to be displayed after the list of options */
  actionsAfter?: ActionListItemDescriptor[];
  /** Content to be displayed before the list of options */
  contentBefore?: React.ReactNode;
  /** Content to be displayed after the list of options */
  contentAfter?: React.ReactNode;
  /** Is rendered when there are no options */
  emptyState?: React.ReactNode;
  /** Callback when the selection of options is changed */
  onSelect(selected: string[]): void;
  /** Callback when the end of the list is reached */
  onEndReached?(): void;
}


export interface Context {
  comboBoxId: string;
  selectedOptionId?: string;
  subscribe(callback: () => void): void;
  unsubscribe(callback: () => void): void;
}


static getDerivedStateFromProps(
    {
      options: nextOptions,
      selected: nextSelected,
      actionsBefore: nextActionsBefore,
      actionsAfter: nextActionsAfter,
    }: Props,
    {navigableOptions, selectedOptions, comboBoxId}: State,
  ) {
    const optionsChanged =
      filterForOptions(navigableOptions) &&
      nextOptions &&
      !optionsAreEqual(navigableOptions, nextOptions);

    let newNavigableOptions: (
      | OptionDescriptor
      | ActionListItemDescriptor)[] = [];
    if (nextActionsBefore) {
      newNavigableOptions = newNavigableOptions.concat(nextActionsBefore);
    }
    if (optionsChanged || nextActionsBefore) {
      newNavigableOptions = newNavigableOptions.concat(nextOptions);
    }
    if (nextActionsAfter) {
      newNavigableOptions = newNavigableOptions.concat(nextActionsAfter);
    }
    newNavigableOptions = assignOptionIds(newNavigableOptions, comboBoxId);

    if (optionsChanged && selectedOptions !== nextSelected) {
      return {
        navigableOptions: newNavigableOptions,
        selectedOptions: nextSelected,
      };
    } else if (optionsChanged) {
      return {
        navigableOptions: newNavigableOptions,
      };
    } else if (selectedOptions !== nextSelected) {
      return {selectedOptions: nextSelected};
    }
    return null;
  }


getChildContext(): Context {
    return {
      comboBoxId: this.state.comboBoxId,
      selectedOptionId: this.selectedOptionId,
      subscribe: this.subscribe,
      unsubscribe: this.unsubscribe,
    };
  }


componentDidMount() {
    const {options, actionsBefore, actionsAfter} = this.props;
    const comboBoxId = this.getComboBoxId();
    let navigableOptions: (OptionDescriptor | ActionListItemDescriptor)[] = [];

    if (actionsBefore) {
      navigableOptions = navigableOptions.concat(actionsBefore);
    }
    if (options) {
      navigableOptions = navigableOptions.concat(options);
    }
    if (actionsAfter) {
      navigableOptions = navigableOptions.concat(actionsAfter);
    }
    navigableOptions = assignOptionIds(navigableOptions, comboBoxId);

    this.setState({
      navigableOptions,
    });
  }


componentDidUpdate(_: Props, prevState: State) {
    const {contentBefore, contentAfter, emptyState} = this.props;
    const {navigableOptions, popoverWasActive} = this.state;
    this.subscriptions.forEach((subscriberCallback) => subscriberCallback());

    const optionsChanged =
      navigableOptions &&
      prevState.navigableOptions &&
      !optionsAreEqual(navigableOptions, prevState.navigableOptions);

    if (optionsChanged) {
      this.updateIndexOfSelectedOption(navigableOptions);
    }

    if (
      navigableOptions &&
      navigableOptions.length === 0 &&
      !contentBefore &&
      !contentAfter &&
      !emptyState
    ) {
      // eslint-disable-next-line react/no-did-update-set-state
      this.setState({popoverActive: false});
    } else if (
      popoverWasActive &&
      navigableOptions &&
      navigableOptions.length !== 0
    ) {
      // eslint-disable-next-line react/no-did-update-set-state
      this.setState({popoverActive: true});
    }
  }


getComboBoxId(): string {
    if (this.state && this.state.comboBoxId) {
      return this.state.comboBoxId;
    }
    return this.props.id || getUniqueId();
  }


render() {
    const {
      options,
      textField,
      listTitle,
      allowMultiple,
      preferredPosition,
      actionsBefore,
      actionsAfter,
      contentBefore,
      contentAfter,
      onEndReached,
      emptyState,
    } = this.props;

    const actionsBeforeMarkup = actionsBefore &&
      actionsBefore.length > 0 && (
        <ActionList actionRole="option" items={actionsBefore} />
      );

    const actionsAfterMarkup = actionsAfter &&
      actionsAfter.length > 0 && (
        <ActionList actionRole="option" items={actionsAfter} />
      );

    const optionsMarkup = options.length > 0 && (
      <OptionList
        role="presentation"
        optionRole="option"
        options={filterForOptions(this.state.navigableOptions)}
        onChange={this.selectOptions}
        selected={this.state.selectedOptions}
        title={listTitle}
        allowMultiple={allowMultiple}
      />
    );

    const emptyStateMarkup = !actionsAfter &&
      !actionsBefore &&
      !contentAfter &&
      !contentBefore &&
      options.length === 0 &&
      emptyState &&
{emptyState}
;

    return (

        <KeypressListener
          keyCode={Key.DownArrow}
          handler={this.handleDownArrow}
        />
        <KeypressListener keyCode={Key.UpArrow} handler={this.handleUpArrow} />
        <KeypressListener keyCode={Key.Enter} handler={this.handleEnter} />
        <KeypressListener
          keyCode={Key.Escape}
          handler={this.handlePopoverClose}
        />
        <Popover
          activator={textField}
          active={this.state.popoverActive}
          onClose={this.handlePopoverClose}
          preferredPosition={preferredPosition}
          fullWidth
          preventAutofocus
        >
          <Popover.Pane onScrolledToBottom={onEndReached}>

              {contentBefore}
              {actionsBeforeMarkup}
              {optionsMarkup}
              {actionsAfterMarkup}
              {contentAfter}
              {emptyStateMarkup}

          </Popover.Pane>
        </Popover>

    );
  }


filterForOptions(this


@Module({
  imports: [TodoModule],
  controllers: [AppController],
  providers: [AppService],
})

export class AppModule {}


async function updateEpoch() {
      const e = epochformattedRemaining();

      setEstimatedEpoch(parseInt(e.split('-')[0], 10));
      setNextEpochIn(e.split('-')[1]);
    }


() => {
    const f = async () => {
      const poolLP = await getPoolLPAddress();
      const poolBonding = await getPoolBondingAddress();

      const [
        spot,
        twap,
        supply,
        bondedLiquidity,
        stagedLiquidity,
        lpBonded,
        lpStaged,
        daoBonded,
        daoStaged,
        bondingBonded,
        bondingStaged,
        expansionAmount,
        bootstrapping,
        daoE,
        treasuryQSD,
      ] = await Promise.all([
        getInstantaneousQSDPrice(),
        getTWAPPrice(),
        getTokenTotalSupply(QSD.addr),
        getLPBondedLiquidity(),
        getLPStagedLiquidity(),
        getPoolTotalBonded(poolLP),
        getPoolTotalStaged(poolLP),
        getTotalBonded(QSDS.addr),
        getTotalStaged(QSDS.addr),
        getPoolTotalBonded(poolBonding),
        getPoolTotalStaged(poolBonding),
        getExpansionAmount(),
        getDaoIsBootstrapping(),
        getEpoch(QSDS.addr),
        getTokenBalance(QSD.addr, TreasuryAddress),
      ]);

      setTwapPrice(twap);
      setTotalSupply(toTokenUnitsBN(supply, 18));
      setQSDPrice(toTokenUnitsBN(spot, 18));
      setQSDStagedLiquidity(stagedLiquidity.qsd);
      setDAIStagedLiquidity(stagedLiquidity.dai);
      setQSDBondedLiquidity(bondedLiquidity.qsd);
      setDAIBondedLiquidity(bondedLiquidity.dai);
      setLPBonded(toTokenUnitsBN(lpBonded, 18));
      setLPStaged(toTokenUnitsBN(lpStaged, 18));
      setDaoEpoch(parseInt(daoE, 10));
      setTreasuryQSDAmount(toTokenUnitsBN(treasuryQSD, QSD.decimals));

      // If is bootstrapping, then bonding will be referencing dao
      // otherwise it'll be referencing bonding
      if (bootstrapping) {
        setDaoBonded(toTokenUnitsBN(daoBonded, 18));
        setDaoStaged(toTokenUnitsBN(daoStaged, 18));
      } else {
        setDaoBonded(toTokenUnitsBN(bondingBonded, 18));
        setDaoStaged(toTokenUnitsBN(bondingStaged, 18));
      }

      setExpansionAmount(expansionAmount);
    };

    const g = async () => {
      if (!user) return;

      const poolLP = await getPoolLPAddress();

      const [
        userQSDBal,
        userUniBal,
        userLpBonded,
        userLpStaged,
        userDaoBonded,
        userDaoStaged,
        walletLiquidity,
        stagedLiquidity,
        bondedLiquidity,
      ] = await Promise.all([
        getTokenBalance(QSD.addr, user),
        getTokenBalance(UNI.addr, user),
        getPoolBalanceOfBonded(poolLP, user),
        getPoolBalanceOfStaged(poolLP, user),
        getBalanceBonded(PoolBonding, user),
        getBalanceOfStaged(PoolBonding, user),
        getUserLPWallet(user),
        getUserLPStaged(user),
        getUserLPBonded(user),
      ]);

      setUserQsdBal(toTokenUnitsBN(userQSDBal, 18));
      setUserUniBal(toTokenUnitsBN(userUniBal, 18));
      setUserLpBonded(toTokenUnitsBN(userLpBonded, 18));
      setUserLpStaged(toTokenUnitsBN(userLpStaged, 18));
      setUserDaoBonded(toTokenUnitsBN(userDaoBonded, 18));
      setUserDaoStaged(toTokenUnitsBN(userDaoStaged, 18));

      setUserQSDWalletLiquidity(walletLiquidity.qsd);
      setUserDAIWalletLiquidity(walletLiquidity.dai);

      setUserQSDStagedLiquidity(stagedLiquidity.qsd);
      setUserDAIStagedLiquidity(stagedLiquidity.dai);

      setUserQSDBondedLiquidity(bondedLiquidity.qsd);
      setUserDAIBondedLiquidity(bondedLiquidity.dai);
    };

    async function updateEpoch() {
      const e = epochformattedRemaining();

      setEstimatedEpoch(parseInt(e.split('-')[0], 10));
      setNextEpochIn(e.split('-')[1]);
    }

    setInterval(updateEpoch, 1000);

    f();
    g();
  }


async () => {
      const poolLP = await getPoolLPAddress();
      const poolBonding = await getPoolBondingAddress();

      const [
        spot,
        twap,
        supply,
        bondedLiquidity,
        stagedLiquidity,
        lpBonded,
        lpStaged,
        daoBonded,
        daoStaged,
        bondingBonded,
        bondingStaged,
        expansionAmount,
        bootstrapping,
        daoE,
        treasuryQSD,
      ] = await Promise.all([
        getInstantaneousQSDPrice(),
        getTWAPPrice(),
        getTokenTotalSupply(QSD.addr),
        getLPBondedLiquidity(),
        getLPStagedLiquidity(),
        getPoolTotalBonded(poolLP),
        getPoolTotalStaged(poolLP),
        getTotalBonded(QSDS.addr),
        getTotalStaged(QSDS.addr),
        getPoolTotalBonded(poolBonding),
        getPoolTotalStaged(poolBonding),
        getExpansionAmount(),
        getDaoIsBootstrapping(),
        getEpoch(QSDS.addr),
        getTokenBalance(QSD.addr, TreasuryAddress),
      ]);

      setTwapPrice(twap);
      setTotalSupply(toTokenUnitsBN(supply, 18));
      setQSDPrice(toTokenUnitsBN(spot, 18));
      setQSDStagedLiquidity(stagedLiquidity.qsd);
      setDAIStagedLiquidity(stagedLiquidity.dai);
      setQSDBondedLiquidity(bondedLiquidity.qsd);
      setDAIBondedLiquidity(bondedLiquidity.dai);
      setLPBonded(toTokenUnitsBN(lpBonded, 18));
      setLPStaged(toTokenUnitsBN(lpStaged, 18));
      setDaoEpoch(parseInt(daoE, 10));
      setTreasuryQSDAmount(toTokenUnitsBN(treasuryQSD, QSD.decimals));

      // If is bootstrapping, then bonding will be referencing dao
      // otherwise it'll be referencing bonding
      if (bootstrapping) {
        setDaoBonded(toTokenUnitsBN(daoBonded, 18));
        setDaoStaged(toTokenUnitsBN(daoStaged, 18));
      } else {
        setDaoBonded(toTokenUnitsBN(bondingBonded, 18));
        setDaoStaged(toTokenUnitsBN(bondingStaged, 18));
      }

      setExpansionAmount(expansionAmount);
    }


async () => {
      if (!user) return;

      const poolLP = await getPoolLPAddress();

      const [
        userQSDBal,
        userUniBal,
        userLpBonded,
        userLpStaged,
        userDaoBonded,
        userDaoStaged,
        walletLiquidity,
        stagedLiquidity,
        bondedLiquidity,
      ] = await Promise.all([
        getTokenBalance(QSD.addr, user),
        getTokenBalance(UNI.addr, user),
        getPoolBalanceOfBonded(poolLP, user),
        getPoolBalanceOfStaged(poolLP, user),
        getBalanceBonded(PoolBonding, user),
        getBalanceOfStaged(PoolBonding, user),
        getUserLPWallet(user),
        getUserLPStaged(user),
        getUserLPBonded(user),
      ]);

      setUserQsdBal(toTokenUnitsBN(userQSDBal, 18));
      setUserUniBal(toTokenUnitsBN(userUniBal, 18));
      setUserLpBonded(toTokenUnitsBN(userLpBonded, 18));
      setUserLpStaged(toTokenUnitsBN(userLpStaged, 18));
      setUserDaoBonded(toTokenUnitsBN(userDaoBonded, 18));
      setUserDaoStaged(toTokenUnitsBN(userDaoStaged, 18));

      setUserQSDWalletLiquidity(walletLiquidity.qsd);
      setUserDAIWalletLiquidity(walletLiquidity.dai);

      setUserQSDStagedLiquidity(stagedLiquidity.qsd);
      setUserDAIStagedLiquidity(stagedLiquidity.dai);

      setUserQSDBondedLiquidity(bondedLiquidity.qsd);
      setUserDAIBondedLiquidity(bondedLiquidity.dai);
    }


(a: BigNumber): number => {
    return parseFloat(formatBN(a, 2).split(',').join(''));
  }


(props) => (
    <Section
      style={


() => {
                advance(QSDS.addr);
              }


({ title, children }) => (

    <div style={


interface InfoBoxProps extends React.ComponentProps<'div'> {
  title: string;
}


formatBN(treasuryQSDAmount, 2)


formatBN(userQsdBal, 2)


formatBN(userDaoStaged, 2)


formatBN(userDaoBonded, 2)


formatBN(userUniBal, 2)


formatBN(userLpStaged, 2)


formatBN(userLpBonded, 2)


export function TranslateServiceNgSummary():any[] {
  return [{summaryKind:3,type:{reference:i0.TranslateService,diDeps:[{isAttribute:false,
      isHost:false,isSelf:false,isSkipSelf:false,isOptional:false,token:{identifier:{reference:i1.TranslateStore}}},
      {isAttribute:false,isHost:false,isSelf:false,isSkipSelf:false,isOptional:false,
          token:{identifier:{reference:i2.TranslateLoader}}},{isAttribute:false,isHost:false,
          isSelf:false,isSkipSelf:false,isOptional:false,token:{identifier:{reference:i3.TranslateCompiler}}},
      {isAttribute:false,isHost:false,isSelf:false,isSkipSelf:false,isOptional:false,
          token:{identifier:{reference:i4.TranslateParser}}},{isAttribute:false,isHost:false,
          isSelf:false,isSkipSelf:false,isOptional:false,token:{identifier:{reference:i5.MissingTranslationHandler}}},
      {isAttribute:false,isHost:false,isSelf:false,isSkipSelf:false,isOptional:false,
          token:{identifier:{reference:i0.USE_DEFAULT_LANG}}},{isAttribute:false,isHost:false,
          isSelf:false,isSkipSelf:false,isOptional:false,token:{identifier:{reference:i0.USE_STORE}}}],
      lifecycleHooks:([] as any[])}}];
}


async function runMigrations(
      db: IDatabase,
      oldVersion: number,
      newVersion: number,
      t: IDatabaseTransaction,
    ): Promise<void> {
      await testStore.put('oldVersion', oldVersion, t)
      await testStore.put('newVersion', newVersion, t)
    }


async () => {
    await db.close()
  }


async () => {
    async function runMigrations(
      db: IDatabase,
      oldVersion: number,
      newVersion: number,
      t: IDatabaseTransaction,
    ): Promise<void> {
      await testStore.put('oldVersion', oldVersion, t)
      await testStore.put('newVersion', newVersion, t)
    }

    await db.open({ upgrade: runMigrations })
    expect(await testStore.get('oldVersion')).toBe(0)
    expect(await testStore.get('newVersion')).toBe(8)
  }


async () => {
    interface EmptySchema extends DatabaseSchema {
      key: string
      value: number
    }

    const store = db.addStore<EmptySchema>({
      version: 8,
      name: 'Nested',
      keyEncoding: new StringEncoding(),
      valueEncoding: new JsonEncoding<number>(),
      upgrade: async (
        db: IDatabase,
        oldVersion: number,
        newVersion: number,
        t: IDatabaseTransaction,
      ): Promise<void> => {
        await store.put('oldVersion', oldVersion, t)
        await store.put('newVersion', newVersion, t)
      },
    })

    await db.open()
    expect(await store.get('oldVersion')).toBe(0)
    expect(await store.get('newVersion')).toBe(8)
  }


async (
        db: IDatabase,
        oldVersion: number,
        newVersion: number,
        t: IDatabaseTransaction,
      ): Promise<void> => {
        await store.put('oldVersion', oldVersion, t)
        await store.put('newVersion', newVersion, t)
      }


async () => {
    await db.open()
    const foo = { hash: 'hello', name: 'ironfish' }
    const fooHash = Buffer.from(JSON.stringify(foo))

    await fooStore.put('hello', foo)
    await barStore.put('hello', fooHash)
    await bazStore.put(fooHash, 'hello')

    expect(await fooStore.get('hello')).toMatchObject(foo)
    expect(await barStore.get('hello')).toEqual(fooHash)
    expect(await bazStore.get(fooHash)).toEqual('hello')

    await fooStore.del('hello')
    await barStore.del('hello')
    await bazStore.del(fooHash)

    expect(await fooStore.get('hello')).not.toBeDefined()
    expect(await barStore.get('hello')).not.toBeDefined()
    expect(await bazStore.get(fooHash)).not.toBeDefined()
  }


async () => {
    await db.open()
    const foo = { hash: 'hello', name: 'ironfish' }
    const fooHash = Buffer.from(JSON.stringify(foo))

    await fooStore.put('hello', foo)
    await barStore.put('hello', fooHash)

    expect(await fooStore.get('hello')).toMatchObject(foo)
    expect(await barStore.get('hello')).toEqual(fooHash)

    await fooStore.clear()

    expect(await fooStore.get('hello')).not.toBeDefined()
    expect(await barStore.get('hello')).toEqual(fooHash)
  }


async () => {
    await db.open()
    await db.metaStore.clear()

    await db.metaStore.add('a', 1)
    await expect(db.metaStore.get('a')).resolves.toBe(1)

    await expect(db.metaStore.add('a', 2)).rejects.toThrow(DuplicateKeyError)
    await expect(db.metaStore.get('a')).resolves.toBe(1)
  }


async () => {
    await db.open()
    await db.metaStore.clear()

    await db.transaction([db.metaStore], 'readwrite', async (tx) => {
      // db=undefined, tx=1
      await db.metaStore.add('a', 1, tx)
      await expect(db.metaStore.get('a', tx)).resolves.toBe(1)

      // db=undefined, tx=2
      await expect(db.metaStore.add('a', 2, tx)).rejects.toThrow(DuplicateKeyError)
      await expect(db.metaStore.get('a', tx)).resolves.toBe(1)
      await expect(db.metaStore.get('a')).resolves.toBeUndefined()
    })

    await expect(db.metaStore.get('a')).resolves.toBe(1)
  }


async (tx) => {
      // db=undefined, tx=1
      await db.metaStore.add('a', 1, tx)
      await expect(db.metaStore.get('a', tx)).resolves.toBe(1)

      // db=undefined, tx=2
      await expect(db.metaStore.add('a', 2, tx)).rejects.toThrow(DuplicateKeyError)
      await expect(db.metaStore.get('a', tx)).resolves.toBe(1)
      await expect(db.metaStore.get('a')).resolves.toBeUndefined()
    }


async () => {
    await db.open()
    await arrayKeyStore.put(['jason', 5, false], true)
    expect(await arrayKeyStore.get(['jason', 5, false])).toBe(true)
    expect(await arrayKeyStore.get(['jason', 5, true])).toBe(undefined)

    await arrayKeyStore.del(['jason', 5, false])
    expect(await arrayKeyStore.get(['jason', 5, false])).toBe(undefined)
  }


async () => {
    interface NestedSchema extends DatabaseSchema {
      key: string
      value: {
        buffer: Buffer
      }
    }

    const store = db.addStore<NestedSchema>({
      version: 1,
      name: 'Nested',
      keyEncoding: new StringEncoding(),
      valueEncoding: new JsonEncoding<{ buffer: Buffer }>(),
    })

    await db.open()

    const buffer = Buffer.alloc(2, 10)

    await store.put('a', { buffer: buffer })
    const stored = await store.get('a')

    expect(stored).toBeTruthy()
    expect(stored?.buffer).toBeInstanceOf(Buffer)
    expect(stored?.buffer.byteLength).toBe(2)
    expect(stored?.buffer[0]).toBe(10)
    expect(stored?.buffer[1]).toBe(10)
  }


() => {
    it('should batch array of writes', async () => {
      await db.open()

      const foo = { hash: 'hello', name: 'ironfish' }
      const fooHash = Buffer.from(JSON.stringify(foo))

      await db.batch([
        [fooStore, 'hello', foo],
        [barStore, 'hello', fooHash],
        [bazStore, fooHash, 'hello'],
      ])

      expect(await fooStore.get('hello')).toMatchObject(foo)
      expect(await barStore.get('hello')).toEqual(fooHash)
      expect(await bazStore.get(fooHash)).toEqual('hello')

      await db.batch([
        [fooStore, 'hello'],
        [barStore, 'hello'],
        [bazStore, fooHash],
      ])

      expect(await fooStore.get('hello')).not.toBeDefined()
      expect(await barStore.get('hello')).not.toBeDefined()
      expect(await bazStore.get(fooHash)).not.toBeDefined()
    })

    it('should batch chained of writes', async () => {
      await db.open()

      const foo = { hash: 'hello', name: 'ironfish' }
      const fooHash = Buffer.from(JSON.stringify(foo))

      await db
        .batch()
        .put(fooStore, 'hello', foo)
        .put(barStore, 'hello', fooHash)
        .put(bazStore, fooHash, 'hello')
        .commit()

      expect(await fooStore.get('hello')).toMatchObject(foo)
      expect(await barStore.get('hello')).toEqual(fooHash)
      expect(await bazStore.get(fooHash)).toEqual('hello')

      await db
        .batch()
        .del(fooStore, 'hello')
        .del(barStore, 'hello')
        .del(bazStore, fooHash)
        .commit()

      expect(await fooStore.get('hello')).not.toBeDefined()
      expect(await barStore.get('hello')).not.toBeDefined()
      expect(await bazStore.get(fooHash)).not.toBeDefined()
    })
  }


async () => {
      await db.open()

      const foo = { hash: 'hello', name: 'ironfish' }
      const fooHash = Buffer.from(JSON.stringify(foo))

      await db.batch([
        [fooStore, 'hello', foo],
        [barStore, 'hello', fooHash],
        [bazStore, fooHash, 'hello'],
      ])

      expect(await fooStore.get('hello')).toMatchObject(foo)
      expect(await barStore.get('hello')).toEqual(fooHash)
      expect(await bazStore.get(fooHash)).toEqual('hello')

      await db.batch([
        [fooStore, 'hello'],
        [barStore, 'hello'],
        [bazStore, fooHash],
      ])

      expect(await fooStore.get('hello')).not.toBeDefined()
      expect(await barStore.get('hello')).not.toBeDefined()
      expect(await bazStore.get(fooHash)).not.toBeDefined()
    }


async () => {
      await db.open()

      const foo = { hash: 'hello', name: 'ironfish' }
      const fooHash = Buffer.from(JSON.stringify(foo))

      await db
        .batch()
        .put(fooStore, 'hello', foo)
        .put(barStore, 'hello', fooHash)
        .put(bazStore, fooHash, 'hello')
        .commit()

      expect(await fooStore.get('hello')).toMatchObject(foo)
      expect(await barStore.get('hello')).toEqual(fooHash)
      expect(await bazStore.get(fooHash)).toEqual('hello')

      await db
        .batch()
        .del(fooStore, 'hello')
        .del(barStore, 'hello')
        .del(bazStore, fooHash)
        .commit()

      expect(await fooStore.get('hello')).not.toBeDefined()
      expect(await barStore.get('hello')).not.toBeDefined()
      expect(await bazStore.get(fooHash)).not.toBeDefined()
    }


() => {
    it('should write in transaction manually', async () => {
      await db.open()

      const foo = { hash: 'hello', name: 'ironfish' }
      const fooHash = Buffer.from(JSON.stringify(foo))

      let transaction = db.transaction([fooStore, barStore, bazStore], 'readwrite')
      await fooStore.put('hello', foo, transaction)
      await barStore.put('hello', fooHash, transaction)
      await bazStore.put(fooHash, 'hello', transaction)
      await transaction.commit()

      expect(await fooStore.get('hello')).toMatchObject(foo)
      expect(await barStore.get('hello')).toEqual(fooHash)
      expect(await bazStore.get(fooHash)).toEqual('hello')

      transaction = db.transaction([fooStore, barStore, bazStore], 'readwrite')
      await fooStore.del('hello', transaction)
      await barStore.del('hello', transaction)
      await bazStore.del(fooHash, transaction)

      expect(await fooStore.get('hello')).toMatchObject(foo)
      expect(await barStore.get('hello')).toEqual(fooHash)
      expect(await bazStore.get(fooHash)).toEqual('hello')

      // Now commit transaction
      await transaction.commit()

      expect(await fooStore.get('hello')).not.toBeDefined()
      expect(await barStore.get('hello')).not.toBeDefined()
      expect(await bazStore.get(fooHash)).not.toBeDefined()
    })

    it('should write in transaction automatically', async () => {
      await db.open()

      const foo = { hash: 'hello', name: 'ironfish' }
      const fooHash = Buffer.from(JSON.stringify(foo))

      await expect(() =>
        db.transaction<void>(
          [fooStore, barStore, bazStore],
          'readwrite',
          async (transaction) => {
            await fooStore.put('hello', foo, transaction)
            await barStore.put('hello', fooHash, transaction)
            await bazStore.put(fooHash, 'hello', transaction)
            throw new Error('Aborted Transaction!')
          },
        ),
      ).rejects.toThrowError('Aborted')

      expect(await fooStore.get('hello')).not.toBeDefined()
      expect(await barStore.get('hello')).not.toBeDefined()
      expect(await bazStore.get(fooHash)).not.toBeDefined()

      await db.transaction<void>(
        [fooStore, barStore, bazStore],
        'readwrite',
        async (transaction) => {
          await fooStore.put('hello', foo, transaction)
          await barStore.put('hello', fooHash, transaction)
          await bazStore.put(fooHash, 'hello', transaction)
        },
      )

      await db.transaction<void>(
        [fooStore, barStore, bazStore],
        'readwrite',
        async (transaction) => {
          await fooStore.del('hello', transaction)
          await barStore.del('hello', transaction)
          await bazStore.del(fooHash, transaction)

          // Should not be commited until this function returns
          expect(await fooStore.get('hello')).toMatchObject(foo)
          expect(await barStore.get('hello')).toEqual(fooHash)
          expect(await bazStore.get(fooHash)).toEqual('hello')
        },
      )

      expect(await fooStore.get('hello')).not.toBeDefined()
      expect(await barStore.get('hello')).not.toBeDefined()
      expect(await bazStore.get(fooHash)).not.toBeDefined()
    })

    it('should cache transaction operations', async () => {
      await db.open()

      const foo = { hash: 'hello', name: 'ironfish' }
      const bar = { hash: 'hello', name: 'world' }

      // With an automatic transaction
      await db.transaction<void>([fooStore], 'readwrite', async (transaction) => {
        await fooStore.put('cache', bar)
        await fooStore.del('cache', transaction)

        expect(await fooStore.get('cache', transaction)).toBeUndefined()
        expect(await fooStore.get('cache')).toMatchObject(bar)

        await fooStore.put('cache', foo, transaction)

        expect(await fooStore.get('cache', transaction)).toMatchObject(foo)
        expect(await fooStore.get('cache')).toMatchObject(bar)

        expect(await fooStore.has('cache', transaction)).toBe(true)
        expect(await fooStore.has('cache')).toBe(true)
      })

      expect(await fooStore.get('cache')).toMatchObject(foo)
      expect(await fooStore.has('cache')).toBe(true)
    })

    it('should cache has and del missing values', async () => {
      await db.open()
      await db.metaStore.clear()

      await db.transaction([db.metaStore], 'readwrite', async (tx) => {
        // db=undefined, tx=undefined
        expect(await db.metaStore.get('a', tx)).toBeUndefined()

        // db=1, tx=undefined
        await db.metaStore.put('a', 1)
        expect(await db.metaStore.get('a', tx)).toBeUndefined()

        // db=1, tx=1
        await db.metaStore.put('a', 1, tx)
        expect(await db.metaStore.get('a', tx)).toBe(1)

        // db=1, tx=undefined
        await db.metaStore.del('a', tx)
        expect(await db.metaStore.get('a', tx)).toBe(undefined)
      })
    })
  }


async () => {
      await db.open()

      const foo = { hash: 'hello', name: 'ironfish' }
      const fooHash = Buffer.from(JSON.stringify(foo))

      let transaction = db.transaction([fooStore, barStore, bazStore], 'readwrite')
      await fooStore.put('hello', foo, transaction)
      await barStore.put('hello', fooHash, transaction)
      await bazStore.put(fooHash, 'hello', transaction)
      await transaction.commit()

      expect(await fooStore.get('hello')).toMatchObject(foo)
      expect(await barStore.get('hello')).toEqual(fooHash)
      expect(await bazStore.get(fooHash)).toEqual('hello')

      transaction = db.transaction([fooStore, barStore, bazStore], 'readwrite')
      await fooStore.del('hello', transaction)
      await barStore.del('hello', transaction)
      await bazStore.del(fooHash, transaction)

      expect(await fooStore.get('hello')).toMatchObject(foo)
      expect(await barStore.get('hello')).toEqual(fooHash)
      expect(await bazStore.get(fooHash)).toEqual('hello')

      // Now commit transaction
      await transaction.commit()

      expect(await fooStore.get('hello')).not.toBeDefined()
      expect(await barStore.get('hello')).not.toBeDefined()
      expect(await bazStore.get(fooHash)).not.toBeDefined()
    }


async () => {
      await db.open()

      const foo = { hash: 'hello', name: 'ironfish' }
      const fooHash = Buffer.from(JSON.stringify(foo))

      await expect(() =>
        db.transaction<void>(
          [fooStore, barStore, bazStore],
          'readwrite',
          async (transaction) => {
            await fooStore.put('hello', foo, transaction)
            await barStore.put('hello', fooHash, transaction)
            await bazStore.put(fooHash, 'hello', transaction)
            throw new Error('Aborted Transaction!')
          },
        ),
      ).rejects.toThrowError('Aborted')

      expect(await fooStore.get('hello')).not.toBeDefined()
      expect(await barStore.get('hello')).not.toBeDefined()
      expect(await bazStore.get(fooHash)).not.toBeDefined()

      await db.transaction<void>(
        [fooStore, barStore, bazStore],
        'readwrite',
        async (transaction) => {
          await fooStore.put('hello', foo, transaction)
          await barStore.put('hello', fooHash, transaction)
          await bazStore.put(fooHash, 'hello', transaction)
        },
      )

      await db.transaction<void>(
        [fooStore, barStore, bazStore],
        'readwrite',
        async (transaction) => {
          await fooStore.del('hello', transaction)
          await barStore.del('hello', transaction)
          await bazStore.del(fooHash, transaction)

          // Should not be commited until this function returns
          expect(await fooStore.get('hello')).toMatchObject(foo)
          expect(await barStore.get('hello')).toEqual(fooHash)
          expect(await bazStore.get(fooHash)).toEqual('hello')
        },
      )

      expect(await fooStore.get('hello')).not.toBeDefined()
      expect(await barStore.get('hello')).not.toBeDefined()
      expect(await bazStore.get(fooHash)).not.toBeDefined()
    }


() =>
        db.transaction<void>(
          [fooStore, barStore, bazStore],
          'readwrite',
          async (transaction) => {
            await fooStore.put('hello', foo, transaction)
            await barStore.put('hello', fooHash, transaction)
            await bazStore.put(fooHash, 'hello', transaction)
            throw new Error('Aborted Transaction!')
          },
        )


async (transaction) => {
            await fooStore.put('hello', foo, transaction)
            await barStore.put('hello', fooHash, transaction)
            await bazStore.put(fooHash, 'hello', transaction)
            throw new Error('Aborted Transaction!')
          }


async (transaction) => {
          await fooStore.put('hello', foo, transaction)
          await barStore.put('hello', fooHash, transaction)
          await bazStore.put(fooHash, 'hello', transaction)
        }


async (transaction) => {
          await fooStore.del('hello', transaction)
          await barStore.del('hello', transaction)
          await bazStore.del(fooHash, transaction)

          // Should not be commited until this function returns
          expect(await fooStore.get('hello')).toMatchObject(foo)
          expect(await barStore.get('hello')).toEqual(fooHash)
          expect(await bazStore.get(fooHash)).toEqual('hello')
        }


async () => {
      await db.open()

      const foo = { hash: 'hello', name: 'ironfish' }
      const bar = { hash: 'hello', name: 'world' }

      // With an automatic transaction
      await db.transaction<void>([fooStore], 'readwrite', async (transaction) => {
        await fooStore.put('cache', bar)
        await fooStore.del('cache', transaction)

        expect(await fooStore.get('cache', transaction)).toBeUndefined()
        expect(await fooStore.get('cache')).toMatchObject(bar)

        await fooStore.put('cache', foo, transaction)

        expect(await fooStore.get('cache', transaction)).toMatchObject(foo)
        expect(await fooStore.get('cache')).toMatchObject(bar)

        expect(await fooStore.has('cache', transaction)).toBe(true)
        expect(await fooStore.has('cache')).toBe(true)
      })

      expect(await fooStore.get('cache')).toMatchObject(foo)
      expect(await fooStore.has('cache')).toBe(true)
    }


async (transaction) => {
        await fooStore.put('cache', bar)
        await fooStore.del('cache', transaction)

        expect(await fooStore.get('cache', transaction)).toBeUndefined()
        expect(await fooStore.get('cache')).toMatchObject(bar)

        await fooStore.put('cache', foo, transaction)

        expect(await fooStore.get('cache', transaction)).toMatchObject(foo)
        expect(await fooStore.get('cache')).toMatchObject(bar)

        expect(await fooStore.has('cache', transaction)).toBe(true)
        expect(await fooStore.has('cache')).toBe(true)
      }


async () => {
      await db.open()
      await db.metaStore.clear()

      await db.transaction([db.metaStore], 'readwrite', async (tx) => {
        // db=undefined, tx=undefined
        expect(await db.metaStore.get('a', tx)).toBeUndefined()

        // db=1, tx=undefined
        await db.metaStore.put('a', 1)
        expect(await db.metaStore.get('a', tx)).toBeUndefined()

        // db=1, tx=1
        await db.metaStore.put('a', 1, tx)
        expect(await db.metaStore.get('a', tx)).toBe(1)

        // db=1, tx=undefined
        await db.metaStore.del('a', tx)
        expect(await db.metaStore.get('a', tx)).toBe(undefined)
      })
    }


async (tx) => {
        // db=undefined, tx=undefined
        expect(await db.metaStore.get('a', tx)).toBeUndefined()

        // db=1, tx=undefined
        await db.metaStore.put('a', 1)
        expect(await db.metaStore.get('a', tx)).toBeUndefined()

        // db=1, tx=1
        await db.metaStore.put('a', 1, tx)
        expect(await db.metaStore.get('a', tx)).toBe(1)

        // db=1, tx=undefined
        await db.metaStore.del('a', tx)
        expect(await db.metaStore.get('a', tx)).toBe(undefined)
      }


() => {
    it('should commit transaction', async () => {
      await db.open()
      await db.metaStore.put('test', 0)

      await db.withTransaction(null, [db.metaStore], 'readwrite', async (transaction) => {
        await db.metaStore.put('test', 1, transaction)
        expect(await db.metaStore.get('test')).toBe(0)
      })

      expect(await db.metaStore.get('test')).toBe(1)
    })

    it('should abort transaction if error thrown', async () => {
      await db.open()
      await db.metaStore.put('test', 0)

      await expect(
        db.withTransaction(null, [db.metaStore], 'readwrite', async (transaction) => {
          await db.metaStore.put('test', 1, transaction)
          throw new Error('test')
        }),
      ).rejects.toThrowError('test')

      expect(await db.metaStore.get('test')).toBe(0)
    })

    it('should abort transaction if calls abort', async () => {
      await db.open()
      await db.metaStore.put('test', 0)

      await db.withTransaction(null, [db.metaStore], 'readwrite', async (transaction) => {
        await db.metaStore.put('test', 1, transaction)
        await transaction.abort()
      })

      expect(await db.metaStore.get('test')).toBe(0)
    })

    it('should properly nest transactions', async () => {
      await db.open()
      await db.metaStore.put('test', 0)
      const transaction = db.transaction([db.metaStore], 'readwrite')

      await db.withTransaction(
        transaction,
        [db.metaStore],
        'readwrite',
        async (transaction) => {
          await db.metaStore.put('test', 1, transaction)

          await db.withTransaction(
            transaction,
            [db.metaStore],
            'readwrite',
            async (transaction) => {
              await db.metaStore.put('test', 2, transaction)
            },
          )

          // Should not commit after inner withTransaction
          expect(await db.metaStore.get('test')).toBe(0)
        },
      )

      // Should not commit after outer withTransaction
      expect(await db.metaStore.get('test')).toBe(0)

      await transaction.commit()
      expect(await db.metaStore.get('test')).toBe(2)
    })
  }


async () => {
      await db.open()
      await db.metaStore.put('test', 0)

      await db.withTransaction(null, [db.metaStore], 'readwrite', async (transaction) => {
        await db.metaStore.put('test', 1, transaction)
        expect(await db.metaStore.get('test')).toBe(0)
      })

      expect(await db.metaStore.get('test')).toBe(1)
    }


async (transaction) => {
        await db.metaStore.put('test', 1, transaction)
        expect(await db.metaStore.get('test')).toBe(0)
      }


async () => {
      await db.open()
      await db.metaStore.put('test', 0)

      await expect(
        db.withTransaction(null, [db.metaStore], 'readwrite', async (transaction) => {
          await db.metaStore.put('test', 1, transaction)
          throw new Error('test')
        }),
      ).rejects.toThrowError('test')

      expect(await db.metaStore.get('test')).toBe(0)
    }


async (transaction) => {
          await db.metaStore.put('test', 1, transaction)
          throw new Error('test')
        }


async () => {
      await db.open()
      await db.metaStore.put('test', 0)

      await db.withTransaction(null, [db.metaStore], 'readwrite', async (transaction) => {
        await db.metaStore.put('test', 1, transaction)
        await transaction.abort()
      })

      expect(await db.metaStore.get('test')).toBe(0)
    }


async (transaction) => {
        await db.metaStore.put('test', 1, transaction)
        await transaction.abort()
      }


async () => {
      await db.open()
      await db.metaStore.put('test', 0)
      const transaction = db.transaction([db.metaStore], 'readwrite')

      await db.withTransaction(
        transaction,
        [db.metaStore],
        'readwrite',
        async (transaction) => {
          await db.metaStore.put('test', 1, transaction)

          await db.withTransaction(
            transaction,
            [db.metaStore],
            'readwrite',
            async (transaction) => {
              await db.metaStore.put('test', 2, transaction)
            },
          )

          // Should not commit after inner withTransaction
          expect(await db.metaStore.get('test')).toBe(0)
        },
      )

      // Should not commit after outer withTransaction
      expect(await db.metaStore.get('test')).toBe(0)

      await transaction.commit()
      expect(await db.metaStore.get('test')).toBe(2)
    }


async (transaction) => {
          await db.metaStore.put('test', 1, transaction)

          await db.withTransaction(
            transaction,
            [db.metaStore],
            'readwrite',
            async (transaction) => {
              await db.metaStore.put('test', 2, transaction)
            },
          )

          // Should not commit after inner withTransaction
          expect(await db.metaStore.get('test')).toBe(0)
        }


async (transaction) => {
              await db.metaStore.put('test', 2, transaction)
            }


() => {
    it('should create key from value', async () => {
      await db.open()

      const foo = { hash: 'keypath', name: '' }
      await fooStore.put(foo)
      expect(await fooStore.get('keypath')).toMatchObject(foo)
    })

    it('should create array key from value', async () => {
      await db.open()

      const value = { a: '', b: 3, c: true }
      await keypathStore.put(value)
      expect(await keypathStore.get(['', 3, true])).toMatchObject(value)
    })

    it('should create array key with transaction', async () => {
      await db.open()

      const key = ['key', 3, true] as SchemaKey<KeypathSchema>
      const value = { a: 'key', b: 3, c: true }

      await db.transaction([keypathStore], 'readwrite', async (t) => {
        await keypathStore.put(value, t)
        expect(await keypathStore.get(key)).toBeUndefined()
      })

      expect(await keypathStore.get(key)).toMatchObject(value)
    })
  }


async () => {
      await db.open()

      const foo = { hash: 'keypath', name: '' }
      await fooStore.put(foo)
      expect(await fooStore.get('keypath')).toMatchObject(foo)
    }


async () => {
      await db.open()

      const value = { a: '', b: 3, c: true }
      await keypathStore.put(value)
      expect(await keypathStore.get(['', 3, true])).toMatchObject(value)
    }


async () => {
      await db.open()

      const key = ['key', 3, true] as SchemaKey<KeypathSchema>
      const value = { a: 'key', b: 3, c: true }

      await db.transaction([keypathStore], 'readwrite', async (t) => {
        await keypathStore.put(value, t)
        expect(await keypathStore.get(key)).toBeUndefined()
      })

      expect(await keypathStore.get(key)).toMatchObject(value)
    }


async (t) => {
        await keypathStore.put(value, t)
        expect(await keypathStore.get(key)).toBeUndefined()
      }


() => {
    it('should get all keys', async () => {
      await db.open()
      await db.metaStore.clear()
      await db.metaStore.put('a', 1000)
      await db.metaStore.put('b', 1001)
      await db.metaStore.put('c', 1002)
      await db.metaStore.put('d', 1003)

      const values = await db.metaStore.getAllValues()

      expect(values).toHaveLength(4)
      expect(values).toContain(1000)
      expect(values).toContain(1001)
      expect(values).toContain(1002)
      expect(values).toContain(1003)

      const keys = await db.metaStore.getAllKeys()

      expect(keys).toHaveLength(4)
      expect(keys).toContain('a')
      expect(keys).toContain('b')
      expect(keys).toContain('c')
      expect(keys).toContain('d')
    })

    it('should encode and decode keys', async () => {
      await db.open()
      await bazStore.clear()

      const hash = Buffer.from([0x54, 0x57, 0xf6, 0x2c])

      // in a transaction
      await db.transaction([bazStore], 'readwrite', async (tx) => {
        await bazStore.add(hash, 'VALUE', tx)
        const keys = await bazStore.getAllKeys(tx)
        expect(keys.length).toBe(1)
        expect(keys[0]?.equals(hash)).toBe(true)
      })

      // and out of a transaction
      const keys = await bazStore.getAllKeys()
      expect(keys.length).toBe(1)
      expect(keys[0]?.equals(hash)).toBe(true)
    })

    it('should get transactional values', async () => {
      await db.open()
      await db.metaStore.clear()

      await db.transaction([db.metaStore], 'readwrite', async (tx) => {
        // a, db=1000, tx=undefined
        await db.metaStore.put('a', 1000)
        let values = await db.metaStore.getAllValues(tx)
        expect(values).toHaveLength(1)
        expect(values).toContain(1000)

        // a, db=1000, tx=1001
        await db.metaStore.put('a', 1001, tx)
        values = await db.metaStore.getAllValues(tx)
        expect(values).toHaveLength(1)
        expect(values).toContain(1001)

        // b, db=undefined, tx=1002
        await db.metaStore.put('b', 1002, tx)
        values = await db.metaStore.getAllValues(tx)
        expect(values).toHaveLength(2)
        expect(values).toContain(1001)
        expect(values).toContain(1002)
      })
    })

    it('should not yield undefined', async () => {
      await db.open()
      await db.metaStore.clear()
      await db.metaStore.put('a', 1)

      await db.transaction([db.metaStore], 'readwrite', async (tx) => {
        expect(await db.metaStore.get('a', tx)).toBe(1)

        let values = await db.metaStore.getAllValues(tx)
        expect(values).toHaveLength(1)
        expect(values).toContain(1)

        // cache has undefined and should not yield
        await db.metaStore.del('a', tx)

        values = await db.metaStore.getAllValues(tx)
        expect(values).toHaveLength(0)
      })
    })

    it('should find entries that have 0xff keys', async () => {
      await db.open()
      await bazStore.clear()

      await bazStore.put(Buffer.alloc(100, 0xff), '1')
      expect((await bazStore.getAllKeys()).length).toBe(1)
    })

    it('should not find entries with an off-by-one prefix and empty key', async () => {
      await db.open()
      const keyStore = testPrefixKeyStore as LevelupStore<BazSchema>
      await keyStore.clear()

      // Increment the prefix buffer by one
      expect(keyStore.prefixBuffer).toEqual(Buffer.from([92, 188, 18, 188]))
      keyStore.prefixBuffer[keyStore.prefixBuffer.length - 1]++

      // Add an entry with an empty buffer for the key
      expect(keyStore.prefixBuffer).toEqual(Buffer.from([92, 188, 18, 189]))
      await keyStore.put(Buffer.alloc(0), '1')
      expect(await keyStore.get(Buffer.alloc(0))).toEqual('1')

      // Decrement the prefix buffer
      keyStore.prefixBuffer[keyStore.prefixBuffer.length - 1]--
      expect(keyStore.prefixBuffer).toEqual(Buffer.from([92, 188, 18, 188]))

      // No keys should exist
      expect(await keyStore.getAllKeys()).toHaveLength(0)
    })
  }


async () => {
      await db.open()
      await db.metaStore.clear()
      await db.metaStore.put('a', 1000)
      await db.metaStore.put('b', 1001)
      await db.metaStore.put('c', 1002)
      await db.metaStore.put('d', 1003)

      const values = await db.metaStore.getAllValues()

      expect(values).toHaveLength(4)
      expect(values).toContain(1000)
      expect(values).toContain(1001)
      expect(values).toContain(1002)
      expect(values).toContain(1003)

      const keys = await db.metaStore.getAllKeys()

      expect(keys).toHaveLength(4)
      expect(keys).toContain('a')
      expect(keys).toContain('b')
      expect(keys).toContain('c')
      expect(keys).toContain('d')
    }


async () => {
      await db.open()
      await bazStore.clear()

      const hash = Buffer.from([0x54, 0x57, 0xf6, 0x2c])

      // in a transaction
      await db.transaction([bazStore], 'readwrite', async (tx) => {
        await bazStore.add(hash, 'VALUE', tx)
        const keys = await bazStore.getAllKeys(tx)
        expect(keys.length).toBe(1)
        expect(keys[0]?.equals(hash)).toBe(true)
      })

      // and out of a transaction
      const keys = await bazStore.getAllKeys()
      expect(keys.length).toBe(1)
      expect(keys[0]?.equals(hash)).toBe(true)
    }