() => {
        (async () => {
            if (photos.length === 0) setAutocompleteOptions([]);
            else setAutocompleteOptions((await getPhotoLabels(photos.map((photo) => photo.id))).data);
        })();
    }


async () => {
            if (photos.length === 0) setAutocompleteOptions([]);
            else setAutocompleteOptions((await getPhotoLabels(photos.map((photo) => photo.id))).data);
        }


(photo) => photo.id


() => {
        upload(acceptedFiles, fileRejections);
    }


async () => {
        setShowLoadingBar(true);
        const resp = await getPhotosInAlbum(id, searchTerm);
        if (resp.status === 200) {
            setPhotos(resp.data);
            setShowLoadingBar(false);
        } else {
            window.alert(await resp.data);
        }
    }


async () => {
        const resp = await getAlbums("");
        if (resp.status === 200) {
            setAlbums(resp.data);
        } else {
            window.alert(await resp.data);
        }
    }


() => {
        fetchPhotos();
        fetchAlbums();
    }


async (albumIds: string[]) => {
        topBarButtonFunctions.unselect();
        await addPhotosToAlbums(selected, albumIds, enqueueSnackbar, closeSnackbar);
        await props.refresh();
    }


async (labels: any) => {
        topBarButtonFunctions.unselect();
        await addLabel(selected, labels);
    }


async (pid: string) => {
        setPhotos(photos.filter((p) => p.id !== pid));
        await deletePhotos([pid], enqueueSnackbar, closeSnackbar);
    }


(p) => p.id !== pid


async (pid: string) => {
        setPhotos(photos.filter((p) => p.id !== pid));
        await removePhotosFromAlbum([pid], id, enqueueSnackbar, closeSnackbar);
    }


async (files: File[], fileRejections: FileRejection[]) => {
        if (!files) return;

        const formData = new FormData();
        files.forEach((file) => {
            if (file.size > maxSize) {
                fileRejections.push({ file, errors: [{ message: `File is bigger than ${maxSize / (1024 * 1024 * 1024)} GB`, code: "file-too-large" }] });
            } else {
                formData.append("file", file);
            }
        });

        const snackbar = UploadErrorSnackbar.createInstance(enqueueSnackbar, closeSnackbar);
        snackbar?.begin(fileRejections);

        if (formData.getAll("file").length === 0) return;
        const data = await addPhotos(formData, enqueueSnackbar, closeSnackbar, albums);

        await addPhotosToAlbums(data, [id], enqueueSnackbar, closeSnackbar);
        await fetchPhotos();
        await props.refresh();
    }


(file) => {
            if (file.size > maxSize) {
                fileRejections.push({ file, errors: [{ message: `File is bigger than ${maxSize / (1024 * 1024 * 1024)} GB`, code: "file-too-large" }] });
            } else {
                formData.append("file", file);
            }
        }


(photoId: string) => () => {
        if (anySelected()) {
            clickHandler(photoId)();
        } else {
            history.push(`/albums/open/${id}/view/${photoId}`);
        }
    }


() => {
        if (anySelected()) {
            clickHandler(photoId)();
        } else {
            history.push(`/albums/open/${id}/view/${photoId}`);
        }
    }


(id: string) => () => {
        let copy = selected.slice();
        if (copy.includes(id)) copy = copy.filter((v) => v !== id);
        else copy.push(id);
        setSelected(copy);
        if (copy.length === 0) {
            setSelectable(false);
        }
    }


() => {
        let copy = selected.slice();
        if (copy.includes(id)) copy = copy.filter((v) => v !== id);
        else copy.push(id);
        setSelected(copy);
        if (copy.length === 0) {
            setSelectable(false);
        }
    }


(v) => v !== id


(): boolean => {
        return selected.length !== 0 || selectable;
    }


async (id: string) => {
            await deletePhoto(id);
            // await fetchPhotos();
            await props.refresh();
        }


async (id: string) => {
            await removePhoto(id);
            setPhotos(photos.filter((p) => p.id !== id));
            // await fetchPhotos();
            await props.refresh();
        }


(p) => p.id !== id


(id: string) => {
            setSelected([id]);
            setAlbumDialogOpen(true);
        }


async (photoID: string) => {
            await setCover(id, photoID);
            await props.refresh();
        }


async (id: string) => {
            await download(
                photos.filter((photo) => id === photo.id),
                enqueueSnackbar,
                closeSnackbar
            );
        }


(photo) => id === photo.id


async () => {
            await setCover(id, selected[0]);
            topBarButtonFunctions.unselect();
            await props.refresh();
        }


async () => {
            topBarButtonFunctions.unselect();
            await deletePhotos(selected, enqueueSnackbar, closeSnackbar);
            setPhotos(photos.filter((p) => !selected.includes(p.id)));

            await props.refresh();
        }


(p) => !selected.includes(p.id)


async () => {
            topBarButtonFunctions.unselect();
            await removePhotosFromAlbum(selected, id, enqueueSnackbar, closeSnackbar);
            setPhotos(photos.filter((p) => !selected.includes(p.id)));

            await props.refresh();
        }


() => {
            setSelected([]);
            setSelectable(false);
        }


() => {
            openM();
        }


() => {
            //Nav to settings page
        }


() => {
            setSelectable(!selectable);
        }


() => {
            setAlbumDialogOpen(true);
        }


() => {
            setLabelDialogOpen(true);
        }


async () => {
            topBarButtonFunctions.unselect();
            download(
                photos.filter((photo) => selected.includes(photo.id)),
                enqueueSnackbar,
                closeSnackbar
            );
        }


(photo) => selected.includes(photo.id)


(s: string) => async () => {
            setSearchTerm(s);
        }


async () => {
            setSearchTerm(s);
        }


() => {
            setShowSearchBar(!showSearchBar);
        }


(id: string, buttonFunctions: any) => {
        return <TopRightBar id={id} buttonFunctions={buttonFunctions} />;
    }


(album: AlbumT) => album.id.toString() === id


export class AppStartupBase implements Contracts.IAppStartup {

        public constructor(public appEvents: Contracts.IAppEvents[]) {

        }

        @Log()
        public async configuration(): Promise<void> {

            for (let appEvent of this.appEvents) {
                await appEvent.onAppStartup();
            }

        }
    }


@Log()
        public async configuration(): Promise<void> {

            for (let appEvent of this.appEvents) {
                await appEvent.onAppStartup();
            }

        }


function maybeSerializeListItem(
  item: ListItem | ListItemBuilder | Divider,
  index: number,
  path: SerializePath
): ListItem | Divider {
  if (item instanceof ListItemBuilder) {
    return item.serialize({path, index})
  }

  const listItem = item as ListItem
  if (listItem && listItem.type === 'divider') {
    return item as Divider
  }

  if (!listItem || listItem.type !== 'listItem') {
    const gotWhat = (listItem && listItem.type) || getArgType(listItem)
    const helpText = gotWhat === 'array' ? ' - did you forget to spread (...moreItems)?' : ''
    throw new SerializeError(
      `List items must be of type "listItem", got "${gotWhat}"${helpText}`,
      path,
      index
    ).withHelpUrl(HELP_URL.INVALID_LIST_ITEM)
  }

  return item
}


function isPromise<T>(thing: any): thing is Promise<T> {
  return thing && typeof thing.then === 'function'
}


export function isList(list: Collection): list is List {
  return list.type === 'list'
}


(thing: ListItem) => {
  if (thing instanceof ListBuilder) {
    return 'ListBuilder'
  }

  if (isPromise<ListItem>(thing)) {
    return 'Promise'
  }

  return Array.isArray(thing) ? 'array' : typeof thing
}


(item: ListItem | Divider): item is ListItem => {
  return item.type === 'listItem'
}


(intentName: string, params, context) => {
  const pane = context.pane as List
  const items = pane.items || []
  return (
    items
      .filter(isDocumentListItem)
      .some(item => item.schemaType.name === params.type && item._id === params.id) ||
    shallowIntentChecker(intentName, params, context)
  )
}


item => item.schemaType.name === params.type && item._id === params.id


(itemId: string, options: ChildResolverOptions) => {
  const parentItem = options.parent as List
  const items = parentItem.items.filter(isListItem)
  const target = (items.find(item => item.id === itemId) || {child: undefined}).child

  if (!target || typeof target !== 'function') {
    return target
  }

  return typeof target === 'function' ? target(itemId, options) : target
}


item => item.id === itemId


(item, index) => maybeSerializeListItem(item, index, path)


(val, i) => find(serializedItems, {id: val.id}, i + 1)


item => item.id


export class ListBuilder extends GenericListBuilder<BuildableList, ListBuilder> {
  protected spec: BuildableList

  constructor(spec?: ListInput) {
    super()
    this.spec = spec ? spec : {}
    this.initialValueTemplatesSpecified = Boolean(spec && spec.initialValueTemplates)
  }

  items(items: (ListItemBuilder | ListItem | Divider)[]): ListBuilder {
    return this.clone({items})
  }

  getItems() {
    return this.spec.items
  }

  serialize(options: SerializeOptions = {path: []}): List {
    const id = this.spec.id
    if (typeof id !== 'string' || !id) {
      throw new SerializeError(
        '`id` is required for lists',
        options.path,
        options.index
      ).withHelpUrl(HELP_URL.ID_REQUIRED)
    }

    const items = typeof this.spec.items === 'undefined' ? [] : this.spec.items
    if (!Array.isArray(items)) {
      throw new SerializeError(
        '`items` must be an array of items',
        options.path,
        options.index
      ).withHelpUrl(HELP_URL.LIST_ITEMS_MUST_BE_ARRAY)
    }

    const path = (options.path || []).concat(id)
    const serializedItems = items.map((item, index) => maybeSerializeListItem(item, index, path))
    const dupes = serializedItems.filter((val, i) => find(serializedItems, {id: val.id}, i + 1))

    if (dupes.length > 0) {
      const dupeIds = dupes.map(item => item.id).slice(0, 5)
      const dupeDesc = dupes.length > 5 ? `${dupeIds.join(', ')}...` : dupeIds.join(', ')
      throw new SerializeError(
        `List items with same ID found (${dupeDesc})`,
        options.path,
        options.index
      ).withHelpUrl(HELP_URL.LIST_ITEM_IDS_MUST_BE_UNIQUE)
    }

    return {
      ...super.serialize(options),
      type: 'list',
      canHandleIntent: this.spec.canHandleIntent || defaultCanHandleIntent,
      child: this.spec.child || resolveChildForItem,
      items: serializedItems
    }
  }

  clone(withSpec?: BuildableList) {
    const builder = new ListBuilder()
    builder.spec = {...this.spec, ...(withSpec || {})}
    return builder
  }
}


export interface List extends GenericList {
  items: (ListItem | Divider)[]
}


export interface ListInput extends GenericListInput {
  items?: (ListItem | ListItemBuilder | Divider)[]
}


export interface BuildableList extends BuildableGenericList {
  items?: (ListItem | ListItemBuilder | Divider)[]
}


items(items: (ListItemBuilder | ListItem | Divider)[]): ListBuilder {
    return this.clone({items})
  }


getItems() {
    return this.spec.items
  }


serialize(options: SerializeOptions = {path: []}): List {
    const id = this.spec.id
    if (typeof id !== 'string' || !id) {
      throw new SerializeError(
        '`id` is required for lists',
        options.path,
        options.index
      ).withHelpUrl(HELP_URL.ID_REQUIRED)
    }

    const items = typeof this.spec.items === 'undefined' ? [] : this.spec.items
    if (!Array.isArray(items)) {
      throw new SerializeError(
        '`items` must be an array of items',
        options.path,
        options.index
      ).withHelpUrl(HELP_URL.LIST_ITEMS_MUST_BE_ARRAY)
    }

    const path = (options.path || []).concat(id)
    const serializedItems = items.map((item, index) => maybeSerializeListItem(item, index, path))
    const dupes = serializedItems.filter((val, i) => find(serializedItems, {id: val.id}, i + 1))

    if (dupes.length > 0) {
      const dupeIds = dupes.map(item => item.id).slice(0, 5)
      const dupeDesc = dupes.length > 5 ? `${dupeIds.join(', ')}...` : dupeIds.join(', ')
      throw new SerializeError(
        `List items with same ID found (${dupeDesc})`,
        options.path,
        options.index
      ).withHelpUrl(HELP_URL.LIST_ITEM_IDS_MUST_BE_UNIQUE)
    }

    return {
      ...super.serialize(options),
      type: 'list',
      canHandleIntent: this.spec.canHandleIntent || defaultCanHandleIntent,
      child: this.spec.child || resolveChildForItem,
      items: serializedItems
    }
  }


clone(withSpec?: BuildableList) {
    const builder = new ListBuilder()
    builder.spec = {...this.spec, ...(withSpec || {})}
    return builder
  }


() => {
				utils.logger(logGroup, 'ready');
				this.sendEvent();
			}


class Nativo {
	call(): Promise<void> {
		if (!this.isEnabled()) {
			utils.logger(logGroup, 'disabled');

			return Promise.resolve();
		}

		return utils.scriptLoader
			.loadScript(libraryUrl, 'text/javascript', true, null, {}, { ntvSetNoAutoStart: '' })
			.then(() => {
				utils.logger(logGroup, 'ready');
				this.sendEvent();
			});
	}

	start(): void {
		this.displayTestAd();
	}

	private sendEvent(): void {
		communicationService.dispatch(nativoLoadedEvent({ isLoaded: true }));
	}

	private isEnabled(): boolean {
		return context.get('services.nativo.enabled') && context.get('wiki.opts.enableNativeAds');
	}

	private displayTestAd(): void {
		if (utils.queryString.get('native_ads_test') !== '1') {
			return;
		}

		const nativeAdIncontentPlaceholder = document.getElementById('ntv-ad');
		nativeAdIncontentPlaceholder.innerHTML = `

AD · best buy

Buy Opla: Very good Astra 1.0 TDI

Available from komis for $213.7

						<button class="ntv-ad-button">buy now</button>

`;
	}
}


call(): Promise<void> {
		if (!this.isEnabled()) {
			utils.logger(logGroup, 'disabled');

			return Promise.resolve();
		}

		return utils.scriptLoader
			.loadScript(libraryUrl, 'text/javascript', true, null, {}, { ntvSetNoAutoStart: '' })
			.then(() => {
				utils.logger(logGroup, 'ready');
				this.sendEvent();
			});
	}


start(): void {
		this.displayTestAd();
	}


private sendEvent(): void {
		communicationService.dispatch(nativoLoadedEvent({ isLoaded: true }));
	}


private isEnabled(): boolean {
		return context.get('services.nativo.enabled') && context.get('wiki.opts.enableNativeAds');
	}


private displayTestAd(): void {
		if (utils.queryString.get('native_ads_test') !== '1') {
			return;
		}

		const nativeAdIncontentPlaceholder = document.getElementById('ntv-ad');
		nativeAdIncontentPlaceholder.innerHTML = `

AD · best buy

Buy Opla: Very good Astra 1.0 TDI

Available from komis for $213.7

						<button class="ntv-ad-button">buy now</button>

`;
	}


export async function on_get_plots(daemon: TDaemon, callback: (e: GetMessageType<chia_harvester_service, get_plots_command, TGetPlotsBroadCast>) => unknown){
  await daemon.subscribe(wallet_ui_service);
  const messageListener = (e: WsMessage) => {
    if(e.origin === chia_harvester_service && e.command === get_plots_command){
      callback(e);
    }
  };
  return daemon.addMessageListener(chia_harvester_service, messageListener);
}


export async function on_message_from_harvester(daemon: TDaemon, callback: (e: GetMessageType<chia_harvester_service, chia_harvester_commands, TChiaHarvesterBroadcast>) => unknown){
  await daemon.subscribe(wallet_ui_service);
  const messageListener = (e: WsMessage) => {
    if(e.origin === chia_harvester_service){
      callback(e);
    }
  };
  return daemon.addMessageListener(chia_harvester_service, messageListener);
}


(e: WsMessage) => {
    if(e.origin === chia_harvester_service && e.command === get_plots_command){
      callback(e);
    }
  }


(e: WsMessage) => {
    if(e.origin === chia_harvester_service){
      callback(e);
    }
  }


export type chia_harvester_service = typeof chia_harvester_service;


export type get_plots_command = typeof get_plots_command;


export type TGetPlotsBroadCast = {
  plots: Plot[];
  failed_to_open_filenames: string[];
  not_found_filenames: string[];
};


// Whole commands for the service
export type chia_harvester_commands = get_plots_command;


export type TChiaHarvesterBroadcast = TGetPlotsBroadCast;


({ onSelectChange }) => {
  const { selectedAccount, extensionStatus, setSelectedAccount, deactivate } =
    useContext(ParachainContext);
  const { accounts } = usePicassoProvider();
  const theme = useTheme();
  const dispatch = useAppDispatch();

  const handleConfirm = () => {
    // dispatch(setSelectedAccount(selected));
    dispatch(closePolkadotModal());
  };

  const handleDisconnect = () => {
    if (deactivate) deactivate();
  };

  let currAccount = accounts.find((v, i) => i === selectedAccount);
  currAccount = !!currAccount ? currAccount : { name: "", address: "" };

  return (
    <Box
      sx={{
        marginTop: theme.spacing(5),
        display: "flex",
        flexDirection: "column",
        gap: 4,
        width: "100%",
      }}


() => {
    // dispatch(setSelectedAccount(selected));
    dispatch(closePolkadotModal());
  }


() => {
    if (deactivate) deactivate();
  }


(v, i) => i === selectedAccount


(account, index) => (
          <Button
            key={index}


// setSelected(account);
if (setSelectedAccount) {
                setSelectedAccount(index);
              }


export default function PhoneMaskedInput(props: TextMaskCustomProps) {
    const { inputRef, ...other } = props;
    return (
        <MaskedInput
        {...other}
        ref={(ref: any) => {
            inputRef(ref ? ref.inputElement : null);
        }}


export function unMaskPhone(phoneNumber:string) {
    return phoneNumber.slice(1, 4) + phoneNumber.slice(6, 9) + phoneNumber.slice(10)
}


interface TextMaskCustomProps {
    inputRef: (ref: HTMLInputElement | null) => void;
}


() => {
  beforeEach(() => {
    // reset mock client
    ec2ClientMock.reset();
  });

  it('should return nat gateways associated with passed vpc', async () => {
    ec2ClientMock.on(DescribeNatGatewaysCommand).resolves({
      NatGateways: [
        {
          NatGatewayId: 'natgw1',
          State: 'associated',
        },
      ],
    });
    const gw: NatGateway[] = await getNatGateways(
      'us-east-1',
      'default',
      'vpc-12345678'
    );
    expect(gw.length).toBe(1);
    expect(gw[0].id).toBe('natgw1');
  });

  it('should not return nat gateways not associated with passed vpc', async () => {
    ec2ClientMock.on(DescribeNatGatewaysCommand).resolves({
      NatGateways: [],
    });
    const gw: NatGateway[] = await getNatGateways(
      'us-east-1',
      'default',
      'vpc-11111111'
    );
    expect(gw.length).toBe(0);
  });

  it('should not return nat gateways when nat gateway fetch fails', async () => {
    ec2ClientMock.on(DescribeNatGatewaysCommand).rejects({
      message: 'failed',
    });
    await expect(
      getNatGateways('us-east-1', 'default', 'vpc-11111111')
    ).rejects.toThrow('Error getting the NAT gateways of vpc vpc-11111111');
  });
}


() => {
    // reset mock client
    ec2ClientMock.reset();
  }


async () => {
    ec2ClientMock.on(DescribeNatGatewaysCommand).resolves({
      NatGateways: [
        {
          NatGatewayId: 'natgw1',
          State: 'associated',
        },
      ],
    });
    const gw: NatGateway[] = await getNatGateways(
      'us-east-1',
      'default',
      'vpc-12345678'
    );
    expect(gw.length).toBe(1);
    expect(gw[0].id).toBe('natgw1');
  }


async () => {
    ec2ClientMock.on(DescribeNatGatewaysCommand).resolves({
      NatGateways: [],
    });
    const gw: NatGateway[] = await getNatGateways(
      'us-east-1',
      'default',
      'vpc-11111111'
    );
    expect(gw.length).toBe(0);
  }


async () => {
    ec2ClientMock.on(DescribeNatGatewaysCommand).rejects({
      message: 'failed',
    });
    await expect(
      getNatGateways('us-east-1', 'default', 'vpc-11111111')
    ).rejects.toThrow('Error getting the NAT gateways of vpc vpc-11111111');
  }


data => {
        console.log(data)
        this.employee = data;
      }


data => {
        console.log(data);
        this.employee = new Employee();
        this.gotoList();
      }


@Component({
  selector: 'app-update-employee',
  templateUrl: './update-employee.component.html',
  styleUrls: ['./update-employee.component.css']
})
export class UpdateEmployeeComponent implements OnInit {

  id: number;
  employee: Employee;

  constructor(private route: ActivatedRoute,private router: Router,
    private employeeService: EmployeeService) { }

  ngOnInit() {
    this.employee = new Employee();

    this.id = this.route.snapshot.params['id'];

    this.employeeService.getEmployee(this.id)
      .subscribe(data => {
        console.log(data)
        this.employee = data;
      }, error => console.log(error));
  }

  updateEmployee() {
    this.employeeService.updateEmployee(this.id, this.employee)
      .subscribe(data => {
        console.log(data);
        this.employee = new Employee();
        this.gotoList();
      }, error => console.log(error));
  }

  onSubmit() {
    this.updateEmployee();
  }

  gotoList() {
    this.router.navigate(['/employees']);
  }
}


ngOnInit() {
    this.employee = new Employee();

    this.id = this.route.snapshot.params['id'];

    this.employeeService.getEmployee(this.id)
      .subscribe(data => {
        console.log(data)
        this.employee = data;
      }, error => console.log(error));
  }


updateEmployee() {
    this.employeeService.updateEmployee(this.id, this.employee)
      .subscribe(data => {
        console.log(data);
        this.employee = new Employee();
        this.gotoList();
      }, error => console.log(error));
  }


onSubmit() {
    this.updateEmployee();
  }


gotoList() {
    this.router.navigate(['/employees']);
  }


() => {
  it("allows comparisons of objects", () => {
    const example = { 1: 1, 2: 2 };
    const hashedObject = hashValue(example);
    expect(hashValue(example)).toBe(hashedObject);
  });

  it("allows comparisons of arrays", () => {
    const example = [1, 2];
    const hashedArray = hashValue(example);
    expect(hashValue(example)).toBe(hashedArray);
  });

  it("allows comparisons of arrays of objects", () => {
    const example = [
      { 1: 1, 2: 2 },
      { 3: 3, 4: 4 },
    ];
    const hashedValue = hashValue(example);
    expect(hashValue(example)).toBe(hashedValue);
  });
}


() => {
    const example = { 1: 1, 2: 2 };
    const hashedObject = hashValue(example);
    expect(hashValue(example)).toBe(hashedObject);
  }


() => {
    const example = [1, 2];
    const hashedArray = hashValue(example);
    expect(hashValue(example)).toBe(hashedArray);
  }


() => {
    const example = [
      { 1: 1, 2: 2 },
      { 3: 3, 4: 4 },
    ];
    const hashedValue = hashValue(example);
    expect(hashValue(example)).toBe(hashedValue);
  }


(
  req: Request,
  payload: ObjectShape
) => {
  return Yup.object().shape(payload).validate(req.body, { abortEarly: false })
}


(error: any, res: Response) => {
  const errors: any = {}
  error.inner.forEach((item: any) => {
    errors[item.path] = item.message
  })

  return res.status(422).json({
    error: {
      statusCode: StatusCodes.UNPROCESSABLE_ENTITY,
      message: ReasonPhrases.UNPROCESSABLE_ENTITY,
      errors,
    },
  })

  // if (Object.keys(errors).length > 0) {
  //   return false
  // }

  // return true
}


(item: any) => {
    errors[item.path] = item.message
  }


// AoT requires an exported function for factories
export function createTranslateLoader(http: HttpClient) {
    // for development
    // return new TranslateHttpLoader(http, '/start-angular/SB-Admin-BS4-Angular-5/master/dist/assets/i18n/', '.json');
    return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}


@NgModule({
    imports: [
        CommonModule,
        BrowserModule,
        BrowserAnimationsModule,
        HttpClientModule,
        TranslateModule.forRoot({
            loader: {
                provide: TranslateLoader,
                useFactory: createTranslateLoader,
                deps: [HttpClient]
            }
        }),
     AngularFireAuthModule,
     AngularFirestoreModule,
        AngularFireModule.initializeApp(environment.firebaseConfig),
        AppRoutingModule
    ],
    declarations: [AppComponent],
    providers: [AuthGuard,MeliService,AngularFireDatabase],
    bootstrap: [AppComponent]
})
export class AppModule {}


export class Shader extends GLShader {
    constructor(gl: WebGL2RenderingContext, vertexSrc?: string, fragmentSrc?: string) {
        super(gl, vertexSrc, fragmentSrc);
    }

    apply(): void {}
    applyMaterial(material: Material): void {}
    applyMesh(mesh: Mesh): void {}
    applyNode(node: SceneNode): void {}
    applyScene(scene: Scene): void {}
}


apply(): void {}


applyMaterial(material: Material): void {}


applyMesh(mesh: Mesh): void {}


applyNode(node: SceneNode): void {}


applyScene(scene: Scene): void {}


export class NewsDTO {
  constructor(
      public information: string,
      public dateTime: Date,
      public culturalSiteName: string,
      public images: Image[],
      public id: number
  ) {}
}


async function runTestApp (name: string, ...args: any[]) {
  const appPath = path.join(fixturesPath, 'api', name);
  const electronPath = process.execPath;
  const appProcess = cp.spawn(electronPath, [appPath, ...args]);

  let output = '';
  appProcess.stdout.on('data', (data) => { output += data; });

  await emittedOnce(appProcess.stdout, 'end');

  return JSON.parse(output);
}


() => {
  it('does not expose internal modules to require', () => {
    expect(() => {
      require('clipboard');
    }).to.throw(/Cannot find module 'clipboard'/);
  });

  describe('require("electron")', () => {
    it('always returns the internal electron module', () => {
      require('electron');
    });
  });
}


() => {
    expect(() => {
      require('clipboard');
    }).to.throw(/Cannot find module 'clipboard'/);
  }


() => {
      require('clipboard');
    }


() => {
    it('always returns the internal electron module', () => {
      require('electron');
    });
  }


() => {
      require('electron');
    }


(done) => {
    const options = {
      key: fs.readFileSync(path.join(certPath, 'server.key')),
      cert: fs.readFileSync(path.join(certPath, 'server.pem')),
      ca: [
        fs.readFileSync(path.join(certPath, 'rootCA.pem')),
        fs.readFileSync(path.join(certPath, 'intermediateCA.pem'))
      ],
      requestCert: true,
      rejectUnauthorized: false
    };

    server = https.createServer(options, (req, res) => {
      if ((req as any).client.authorized) {
        res.writeHead(200);
        res.end('<title>authorized</title>');
      } else {
        res.writeHead(401);
        res.end('<title>denied</title>');
      }
    });

    server.listen(0, '127.0.0.1', () => {
      const port = (server.address() as net.AddressInfo).port;
      secureUrl = `https://127.0.0.1:${port}`;
      done();
    });
  }


(req, res) => {
      if ((req as any).client.authorized) {
        res.writeHead(200);
        res.end('<title>authorized</title>');
      } else {
        res.writeHead(401);
        res.end('<title>denied</title>');
      }
    }


() => {
      const port = (server.address() as net.AddressInfo).port;
      secureUrl = `https://127.0.0.1:${port}`;
      done();
    }


done => {
    server.close(() => done());
  }


() => done()


() => {
    it('returns the version field of package.json', () => {
      expect(app.getVersion()).to.equal('0.1.0');
    });
  }


() => {
      expect(app.getVersion()).to.equal('0.1.0');
    }


() => {
    it('overrides the version', () => {
      expect(app.getVersion()).to.equal('0.1.0');
      app.setVersion('test-version');

      expect(app.getVersion()).to.equal('test-version');
      app.setVersion('0.1.0');
    });
  }


() => {
      expect(app.getVersion()).to.equal('0.1.0');
      app.setVersion('test-version');

      expect(app.getVersion()).to.equal('test-version');
      app.setVersion('0.1.0');
    }


() => {
    it('with properties', () => {
      it('returns the name field of package.json', () => {
        expect(app.name).to.equal('Electron Test Main');
      });

      it('overrides the name', () => {
        expect(app.name).to.equal('Electron Test Main');
        app.name = 'test-name';

        expect(app.name).to.equal('test-name');
        app.name = 'Electron Test Main';
      });
    });

    it('with functions', () => {
      it('returns the name field of package.json', () => {
        expect(app.getName()).to.equal('Electron Test Main');
      });

      it('overrides the name', () => {
        expect(app.getName()).to.equal('Electron Test Main');
        app.setName('test-name');

        expect(app.getName()).to.equal('test-name');
        app.setName('Electron Test Main');
      });
    });
  }


() => {
      it('returns the name field of package.json', () => {
        expect(app.name).to.equal('Electron Test Main');
      });

      it('overrides the name', () => {
        expect(app.name).to.equal('Electron Test Main');
        app.name = 'test-name';

        expect(app.name).to.equal('test-name');
        app.name = 'Electron Test Main';
      });
    }


() => {
        expect(app.name).to.equal('Electron Test Main');
      }


() => {
        expect(app.name).to.equal('Electron Test Main');
        app.name = 'test-name';

        expect(app.name).to.equal('test-name');
        app.name = 'Electron Test Main';
      }


() => {
      it('returns the name field of package.json', () => {
        expect(app.getName()).to.equal('Electron Test Main');
      });

      it('overrides the name', () => {
        expect(app.getName()).to.equal('Electron Test Main');
        app.setName('test-name');

        expect(app.getName()).to.equal('test-name');
        app.setName('Electron Test Main');
      });
    }


() => {
        expect(app.getName()).to.equal('Electron Test Main');
      }


() => {
        expect(app.getName()).to.equal('Electron Test Main');
        app.setName('test-name');

        expect(app.getName()).to.equal('test-name');
        app.setName('Electron Test Main');
      }


() => {
    it('should not be empty', () => {
      expect(app.getLocale()).to.not.equal('');
    });
  }


() => {
      expect(app.getLocale()).to.not.equal('');
    }


() => {
    it('should be empty or have length of two', () => {
      let expectedLength = 2;
      if (process.platform === 'linux') {
        // Linux CI machines have no locale.
        expectedLength = 0;
      }
      expect(app.getLocaleCountryCode()).to.be.a('string').and.have.lengthOf(expectedLength);
    });
  }


() => {
      let expectedLength = 2;
      if (process.platform === 'linux') {
        // Linux CI machines have no locale.
        expectedLength = 0;
      }
      expect(app.getLocaleCountryCode()).to.be.a('string').and.have.lengthOf(expectedLength);
    }


() => {
    it('should be false durings tests', () => {
      expect(app.isPackaged).to.equal(false);
    });
  }


() => {
      expect(app.isPackaged).to.equal(false);
    }


() => {
    it('should be false during tests', () => {
      expect(app.isInApplicationsFolder()).to.equal(false);
    });
  }


() => {
      expect(app.isInApplicationsFolder()).to.equal(false);
    }


() => {
    let appProcess: cp.ChildProcess | null = null;

    afterEach(() => {
      if (appProcess) appProcess.kill();
    });

    it('emits a process exit event with the code', async () => {
      const appPath = path.join(fixturesPath, 'api', 'quit-app');
      const electronPath = process.execPath;
      let output = '';

      appProcess = cp.spawn(electronPath, [appPath]);
      if (appProcess && appProcess.stdout) {
        appProcess.stdout.on('data', data => { output += data; });
      }
      const [code] = await emittedOnce(appProcess, 'exit');

      if (process.platform !== 'win32') {
        expect(output).to.include('Exit event with code: 123');
      }
      expect(code).to.equal(123);
    });

    it('closes all windows', async function () {
      const appPath = path.join(fixturesPath, 'api', 'exit-closes-all-windows-app');
      const electronPath = process.execPath;

      appProcess = cp.spawn(electronPath, [appPath]);
      const [code, signal] = await emittedOnce(appProcess, 'exit');

      expect(signal).to.equal(null, 'exit signal should be null, if you see this please tag @MarshallOfSound');
      expect(code).to.equal(123, 'exit code should be 123, if you see this please tag @MarshallOfSound');
    });

    it('exits gracefully', async function () {
      if (!['darwin', 'linux'].includes(process.platform)) {
        this.skip();
        return;
      }

      const electronPath = process.execPath;
      const appPath = path.join(fixturesPath, 'api', 'singleton');
      appProcess = cp.spawn(electronPath, [appPath]);

      // Singleton will send us greeting data to let us know it's running.
      // After that, ask it to exit gracefully and confirm that it does.
      if (appProcess && appProcess.stdout) {
        appProcess.stdout.on('data', () => appProcess!.kill());
      }
      const [code, signal] = await emittedOnce(appProcess, 'exit');

      const message = `code:\n${code}\nsignal:\n${signal}`;
      expect(code).to.equal(0, message);
      expect(signal).to.equal(null, message);
    });
  }


() => {
      if (appProcess) appProcess.kill();
    }


async () => {
      const appPath = path.join(fixturesPath, 'api', 'quit-app');
      const electronPath = process.execPath;
      let output = '';

      appProcess = cp.spawn(electronPath, [appPath]);
      if (appProcess && appProcess.stdout) {
        appProcess.stdout.on('data', data => { output += data; });
      }
      const [code] = await emittedOnce(appProcess, 'exit');

      if (process.platform !== 'win32') {
        expect(output).to.include('Exit event with code: 123');
      }
      expect(code).to.equal(123);
    }


data => { output += data; }


() => appProcess!.kill()


() => {
    it('throws an error on invalid application policies', () => {
      expect(() => {
        app.setActivationPolicy('terrible' as any);
      }).to.throw(/Invalid activation policy: must be one of 'regular', 'accessory', or 'prohibited'/);
    });
  }


() => {
      expect(() => {
        app.setActivationPolicy('terrible' as any);
      }).to.throw(/Invalid activation policy: must be one of 'regular', 'accessory', or 'prohibited'/);
    }


() => {
        app.setActivationPolicy('terrible' as any);
      }


() => {
    it('prevents the second launch of app', async function () {
      this.timeout(120000);
      const appPath = path.join(fixturesPath, 'api', 'singleton');
      const first = cp.spawn(process.execPath, [appPath]);
      await emittedOnce(first.stdout, 'data');
      // Start second app when received output.
      const second = cp.spawn(process.execPath, [appPath]);
      const [code2] = await emittedOnce(second, 'exit');
      expect(code2).to.equal(1);
      const [code1] = await emittedOnce(first, 'exit');
      expect(code1).to.equal(0);
    });

    it('passes arguments to the second-instance event', async () => {
      const appPath = path.join(fixturesPath, 'api', 'singleton');
      const first = cp.spawn(process.execPath, [appPath]);
      const firstExited = emittedOnce(first, 'exit');

      // Wait for the first app to boot.
      const firstStdoutLines = first.stdout.pipe(split());
      while ((await emittedOnce(firstStdoutLines, 'data')).toString() !== 'started') {
        // wait.
      }
      const data2Promise = emittedOnce(firstStdoutLines, 'data');

      const secondInstanceArgs = [process.execPath, appPath, '--some-switch', 'some-arg'];
      const second = cp.spawn(secondInstanceArgs[0], secondInstanceArgs.slice(1));
      const [code2] = await emittedOnce(second, 'exit');
      expect(code2).to.equal(1);
      const [code1] = await firstExited;
      expect(code1).to.equal(0);
      const data2 = (await data2Promise)[0].toString('ascii');
      const secondInstanceArgsReceived: string[] = JSON.parse(data2.toString('ascii'));
      const expected = process.platform === 'win32'
        ? [process.execPath, '--some-switch', '--allow-file-access-from-files', appPath, 'some-arg']
        : secondInstanceArgs;
      expect(secondInstanceArgsReceived).to.eql(expected,
        `expected ${JSON.stringify(expected)} but got ${data2.toString('ascii')}`);
    });
  }


async () => {
      const appPath = path.join(fixturesPath, 'api', 'singleton');
      const first = cp.spawn(process.execPath, [appPath]);
      const firstExited = emittedOnce(first, 'exit');

      // Wait for the first app to boot.
      const firstStdoutLines = first.stdout.pipe(split());
      while ((await emittedOnce(firstStdoutLines, 'data')).toString() !== 'started') {
        // wait.
      }
      const data2Promise = emittedOnce(firstStdoutLines, 'data');

      const secondInstanceArgs = [process.execPath, appPath, '--some-switch', 'some-arg'];
      const second = cp.spawn(secondInstanceArgs[0], secondInstanceArgs.slice(1));
      const [code2] = await emittedOnce(second, 'exit');
      expect(code2).to.equal(1);
      const [code1] = await firstExited;
      expect(code1).to.equal(0);
      const data2 = (await data2Promise)[0].toString('ascii');
      const secondInstanceArgsReceived: string[] = JSON.parse(data2.toString('ascii'));
      const expected = process.platform === 'win32'
        ? [process.execPath, '--some-switch', '--allow-file-access-from-files', appPath, 'some-arg']
        : secondInstanceArgs;
      expect(secondInstanceArgsReceived).to.eql(expected,
        `expected ${JSON.stringify(expected)} but got ${data2.toString('ascii')}`);
    }


() => {
    let server: net.Server | null = null;
    const socketPath = process.platform === 'win32' ? '\\\\.\\pipe\\electron-app-relaunch' : '/tmp/electron-app-relaunch';

    beforeEach(done => {
      fs.unlink(socketPath, () => {
        server = net.createServer();
        server.listen(socketPath);
        done();
      });
    });

    afterEach((done) => {
      server!.close(() => {
        if (process.platform === 'win32') {
          done();
        } else {
          fs.unlink(socketPath, () => done());
        }
      });
    });

    it('relaunches the app', function (done) {
      this.timeout(120000);

      let state = 'none';
      server!.once('error', error => done(error));
      server!.on('connection', client => {
        client.once('data', data => {
          if (String(data) === 'false' && state === 'none') {
            state = 'first-launch';
          } else if (String(data) === 'true' && state === 'first-launch') {
            done();
          } else {
            done(`Unexpected state: ${state}`);
          }
        });
      });

      const appPath = path.join(fixturesPath, 'api', 'relaunch');
      cp.spawn(process.execPath, [appPath]);
    });
  }


done => {
      fs.unlink(socketPath, () => {
        server = net.createServer();
        server.listen(socketPath);
        done();
      });
    }


() => {
        server = net.createServer();
        server.listen(socketPath);
        done();
      }


(done) => {
      server!.close(() => {
        if (process.platform === 'win32') {
          done();
        } else {
          fs.unlink(socketPath, () => done());
        }
      });
    }


() => {
        if (process.platform === 'win32') {
          done();
        } else {
          fs.unlink(socketPath, () => done());
        }
      }


error => done(error)


client => {
        client.once('data', data => {
          if (String(data) === 'false' && state === 'none') {
            state = 'first-launch';
          } else if (String(data) === 'true' && state === 'first-launch') {
            done();
          } else {
            done(`Unexpected state: ${state}`);
          }
        });
      }


data => {
          if (String(data) === 'false' && state === 'none') {
            state = 'first-launch';
          } else if (String(data) === 'true' && state === 'first-launch') {
            done();
          } else {
            done(`Unexpected state: ${state}`);
          }
        }


() => {
    before(function () {
      if (process.platform !== 'darwin') {
        this.skip();
      }
    });

    it('sets the current activity', () => {
      app.setUserActivity('com.electron.testActivity', { testData: '123' });
      expect(app.getCurrentActivityType()).to.equal('com.electron.testActivity');
    });
  }


() => {
      app.setUserActivity('com.electron.testActivity', { testData: '123' });
      expect(app.getCurrentActivityType()).to.equal('com.electron.testActivity');
    }


() => {
    afterEach(closeAllWindows);
    it('is emitted when visiting a server with a self-signed cert', async () => {
      const w = new BrowserWindow({ show: false });
      w.loadURL(secureUrl);
      await emittedOnce(app, 'certificate-error');
    });
  }


async () => {
      const w = new BrowserWindow({ show: false });
      w.loadURL(secureUrl);
      await emittedOnce(app, 'certificate-error');
    }


() => {
    let w: BrowserWindow = null as any;

    afterEach(() => closeWindow(w).then(() => { w = null as any; }));

    it('should emit browser-window-focus event when window is focused', async () => {
      const emitted = emittedOnce(app, 'browser-window-focus');
      w = new BrowserWindow({ show: false });
      w.emit('focus');
      const [, window] = await emitted;
      expect(window.id).to.equal(w.id);
    });

    it('should emit browser-window-blur event when window is blured', async () => {
      const emitted = emittedOnce(app, 'browser-window-blur');
      w = new BrowserWindow({ show: false });
      w.emit('blur');
      const [, window] = await emitted;
      expect(window.id).to.equal(w.id);
    });

    it('should emit browser-window-created event when window is created', async () => {
      const emitted = emittedOnce(app, 'browser-window-created');
      w = new BrowserWindow({ show: false });
      const [, window] = await emitted;
      expect(window.id).to.equal(w.id);
    });

    it('should emit web-contents-created event when a webContents is created', async () => {
      const emitted = emittedOnce(app, 'web-contents-created');
      w = new BrowserWindow({ show: false });
      const [, webContents] = await emitted;
      expect(webContents.id).to.equal(w.webContents.id);
    });

    // FIXME: re-enable this test on win32.
    ifit(process.platform !== 'win32')('should emit renderer-process-crashed event when renderer crashes', async () => {
      w = new BrowserWindow({
        show: false,
        webPreferences: {
          nodeIntegration: true,
          contextIsolation: false
        }
      });
      await w.loadURL('about:blank');

      const emitted = emittedOnce(app, 'renderer-process-crashed');
      w.webContents.executeJavaScript('process.crash()');

      const [, webContents] = await emitted;
      expect(webContents).to.equal(w.webContents);
    });

    // FIXME: re-enable this test on win32.
    ifit(process.platform !== 'win32')('should emit render-process-gone event when renderer crashes', async () => {
      w = new BrowserWindow({
        show: false,
        webPreferences: {
          nodeIntegration: true,
          contextIsolation: false
        }
      });
      await w.loadURL('about:blank');

      const emitted = emittedOnce(app, 'render-process-gone');
      w.webContents.executeJavaScript('process.crash()');

      const [, webContents, details] = await emitted;
      expect(webContents).to.equal(w.webContents);
      expect(details.reason).to.be.oneOf(['crashed', 'abnormal-exit']);
    });

    ifdescribe(features.isDesktopCapturerEnabled())('desktopCapturer module filtering', () => {
      it('should emit desktop-capturer-get-sources event when desktopCapturer.getSources() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'desktop-capturer-get-sources');
        w.webContents.executeJavaScript('require(\'electron\').desktopCapturer.getSources({ types: [\'screen\'] })');

        const [, webContents] = await promise;
        expect(webContents).to.equal(w.webContents);
      });
    });

    ifdescribe(features.isRemoteModuleEnabled())('remote module filtering', () => {
      it('should emit remote-require event when remote.require() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-require');
        w.webContents.executeJavaScript('require(\'electron\').remote.require(\'test\')');

        const [, webContents, moduleName] = await promise;
        expect(webContents).to.equal(w.webContents);
        expect(moduleName).to.equal('test');
      });

      it('should emit remote-get-global event when remote.getGlobal() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-global');
        w.webContents.executeJavaScript('require(\'electron\').remote.getGlobal(\'test\')');

        const [, webContents, globalName] = await promise;
        expect(webContents).to.equal(w.webContents);
        expect(globalName).to.equal('test');
      });

      it('should emit remote-get-builtin event when remote.getBuiltin() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-builtin');
        w.webContents.executeJavaScript('require(\'electron\').remote.app');

        const [, webContents, moduleName] = await promise;
        expect(webContents).to.equal(w.webContents);
        expect(moduleName).to.equal('app');
      });

      it('should emit remote-get-current-window event when remote.getCurrentWindow() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-current-window');
        w.webContents.executeJavaScript('{ require(\'electron\').remote.getCurrentWindow() }');

        const [, webContents] = await promise;
        expect(webContents).to.equal(w.webContents);
      });

      it('should emit remote-get-current-web-contents event when remote.getCurrentWebContents() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-current-web-contents');
        w.webContents.executeJavaScript('{ require(\'electron\').remote.getCurrentWebContents() }');

        const [, webContents] = await promise;
        expect(webContents).to.equal(w.webContents);
      });
    });
  }


() => closeWindow(w).then(() => { w = null as any; })


() => { w = null as any; }


async () => {
      const emitted = emittedOnce(app, 'browser-window-focus');
      w = new BrowserWindow({ show: false });
      w.emit('focus');
      const [, window] = await emitted;
      expect(window.id).to.equal(w.id);
    }


async () => {
      const emitted = emittedOnce(app, 'browser-window-blur');
      w = new BrowserWindow({ show: false });
      w.emit('blur');
      const [, window] = await emitted;
      expect(window.id).to.equal(w.id);
    }


async () => {
      const emitted = emittedOnce(app, 'browser-window-created');
      w = new BrowserWindow({ show: false });
      const [, window] = await emitted;
      expect(window.id).to.equal(w.id);
    }


async () => {
      const emitted = emittedOnce(app, 'web-contents-created');
      w = new BrowserWindow({ show: false });
      const [, webContents] = await emitted;
      expect(webContents.id).to.equal(w.webContents.id);
    }


async () => {
      w = new BrowserWindow({
        show: false,
        webPreferences: {
          nodeIntegration: true,
          contextIsolation: false
        }
      });
      await w.loadURL('about:blank');

      const emitted = emittedOnce(app, 'renderer-process-crashed');
      w.webContents.executeJavaScript('process.crash()');

      const [, webContents] = await emitted;
      expect(webContents).to.equal(w.webContents);
    }


async () => {
      w = new BrowserWindow({
        show: false,
        webPreferences: {
          nodeIntegration: true,
          contextIsolation: false
        }
      });
      await w.loadURL('about:blank');

      const emitted = emittedOnce(app, 'render-process-gone');
      w.webContents.executeJavaScript('process.crash()');

      const [, webContents, details] = await emitted;
      expect(webContents).to.equal(w.webContents);
      expect(details.reason).to.be.oneOf(['crashed', 'abnormal-exit']);
    }


() => {
      it('should emit desktop-capturer-get-sources event when desktopCapturer.getSources() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'desktop-capturer-get-sources');
        w.webContents.executeJavaScript('require(\'electron\').desktopCapturer.getSources({ types: [\'screen\'] })');

        const [, webContents] = await promise;
        expect(webContents).to.equal(w.webContents);
      });
    }


async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'desktop-capturer-get-sources');
        w.webContents.executeJavaScript('require(\'electron\').desktopCapturer.getSources({ types: [\'screen\'] })');

        const [, webContents] = await promise;
        expect(webContents).to.equal(w.webContents);
      }


() => {
      it('should emit remote-require event when remote.require() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-require');
        w.webContents.executeJavaScript('require(\'electron\').remote.require(\'test\')');

        const [, webContents, moduleName] = await promise;
        expect(webContents).to.equal(w.webContents);
        expect(moduleName).to.equal('test');
      });

      it('should emit remote-get-global event when remote.getGlobal() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-global');
        w.webContents.executeJavaScript('require(\'electron\').remote.getGlobal(\'test\')');

        const [, webContents, globalName] = await promise;
        expect(webContents).to.equal(w.webContents);
        expect(globalName).to.equal('test');
      });

      it('should emit remote-get-builtin event when remote.getBuiltin() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-builtin');
        w.webContents.executeJavaScript('require(\'electron\').remote.app');

        const [, webContents, moduleName] = await promise;
        expect(webContents).to.equal(w.webContents);
        expect(moduleName).to.equal('app');
      });

      it('should emit remote-get-current-window event when remote.getCurrentWindow() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-current-window');
        w.webContents.executeJavaScript('{ require(\'electron\').remote.getCurrentWindow() }');

        const [, webContents] = await promise;
        expect(webContents).to.equal(w.webContents);
      });

      it('should emit remote-get-current-web-contents event when remote.getCurrentWebContents() is invoked', async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-current-web-contents');
        w.webContents.executeJavaScript('{ require(\'electron\').remote.getCurrentWebContents() }');

        const [, webContents] = await promise;
        expect(webContents).to.equal(w.webContents);
      });
    }


async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-require');
        w.webContents.executeJavaScript('require(\'electron\').remote.require(\'test\')');

        const [, webContents, moduleName] = await promise;
        expect(webContents).to.equal(w.webContents);
        expect(moduleName).to.equal('test');
      }


async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-global');
        w.webContents.executeJavaScript('require(\'electron\').remote.getGlobal(\'test\')');

        const [, webContents, globalName] = await promise;
        expect(webContents).to.equal(w.webContents);
        expect(globalName).to.equal('test');
      }


async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-builtin');
        w.webContents.executeJavaScript('require(\'electron\').remote.app');

        const [, webContents, moduleName] = await promise;
        expect(webContents).to.equal(w.webContents);
        expect(moduleName).to.equal('app');
      }


async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-current-window');
        w.webContents.executeJavaScript('{ require(\'electron\').remote.getCurrentWindow() }');

        const [, webContents] = await promise;
        expect(webContents).to.equal(w.webContents);
      }


async () => {
        w = new BrowserWindow({
          show: false,
          webPreferences: {
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false
          }
        });
        await w.loadURL('about:blank');

        const promise = emittedOnce(app, 'remote-get-current-web-contents');
        w.webContents.executeJavaScript('{ require(\'electron\').remote.getCurrentWebContents() }');

        const [, webContents] = await promise;
        expect(webContents).to.equal(w.webContents);
      }


() => {
    const platformIsNotSupported =
        (process.platform === 'win32') ||
        (process.platform === 'linux' && !app.isUnityRunning());

    const expectedBadgeCount = 42;

    after(() => { app.badgeCount = 0; });

    ifdescribe(!platformIsNotSupported)('on supported platform', () => {
      describe('with properties', () => {
        it('sets a badge count', function () {
          app.badgeCount = expectedBadgeCount;
          expect(app.badgeCount).to.equal(expectedBadgeCount);
        });
      });

      describe('with functions', () => {
        it('sets a numerical badge count', function () {
          app.setBadgeCount(expectedBadgeCount);
          expect(app.getBadgeCount()).to.equal(expectedBadgeCount);
        });
        it('sets an non numeric (dot) badge count', function () {
          app.setBadgeCount();
          // Badge count should be zero when non numeric (dot) is requested
          expect(app.getBadgeCount()).to.equal(0);
        });
      });
    });

    ifdescribe(process.platform !== 'win32' && platformIsNotSupported)('on unsupported platform', () => {
      describe('with properties', () => {
        it('does not set a badge count', function () {
          app.badgeCount = 9999;
          expect(app.badgeCount).to.equal(0);
        });
      });

      describe('with functions', () => {
        it('does not set a badge count)', function () {
          app.setBadgeCount(9999);
          expect(app.getBadgeCount()).to.equal(0);
        });
      });
    });
  }


() => { app.badgeCount = 0; }


() => {
      describe('with properties', () => {
        it('sets a badge count', function () {
          app.badgeCount = expectedBadgeCount;
          expect(app.badgeCount).to.equal(expectedBadgeCount);
        });
      });

      describe('with functions', () => {
        it('sets a numerical badge count', function () {
          app.setBadgeCount(expectedBadgeCount);
          expect(app.getBadgeCount()).to.equal(expectedBadgeCount);
        });
        it('sets an non numeric (dot) badge count', function () {
          app.setBadgeCount();
          // Badge count should be zero when non numeric (dot) is requested
          expect(app.getBadgeCount()).to.equal(0);
        });
      });
    }


() => {
        it('sets a badge count', function () {
          app.badgeCount = expectedBadgeCount;
          expect(app.badgeCount).to.equal(expectedBadgeCount);
        });
      }


() => {
        it('sets a numerical badge count', function () {
          app.setBadgeCount(expectedBadgeCount);
          expect(app.getBadgeCount()).to.equal(expectedBadgeCount);
        });
        it('sets an non numeric (dot) badge count', function () {
          app.setBadgeCount();
          // Badge count should be zero when non numeric (dot) is requested
          expect(app.getBadgeCount()).to.equal(0);
        });
      }


() => {
      describe('with properties', () => {
        it('does not set a badge count', function () {
          app.badgeCount = 9999;
          expect(app.badgeCount).to.equal(0);
        });
      });

      describe('with functions', () => {
        it('does not set a badge count)', function () {
          app.setBadgeCount(9999);
          expect(app.getBadgeCount()).to.equal(0);
        });
      });
    }


() => {
        it('does not set a badge count', function () {
          app.badgeCount = 9999;
          expect(app.badgeCount).to.equal(0);
        });
      }


() => {
        it('does not set a badge count)', function () {
          app.setBadgeCount(9999);
          expect(app.getBadgeCount()).to.equal(0);
        });
      }


() => {
      app.setLoginItemSettings({ openAtLogin: false });
      app.setLoginItemSettings({ openAtLogin: false, path: updateExe, args: processStartArgs });
      app.setLoginItemSettings({ name: 'additionalEntry', openAtLogin: false });
    }


() => {
    it('with properties', () => {
      it('can set accessibility support enabled', () => {
        expect(app.accessibilitySupportEnabled).to.eql(false);

        app.accessibilitySupportEnabled = true;
        expect(app.accessibilitySupportEnabled).to.eql(true);
      });
    });

    it('with functions', () => {
      it('can set accessibility support enabled', () => {
        expect(app.isAccessibilitySupportEnabled()).to.eql(false);

        app.setAccessibilitySupportEnabled(true);
        expect(app.isAccessibilitySupportEnabled()).to.eql(true);
      });
    });
  }


() => {
      it('can set accessibility support enabled', () => {
        expect(app.accessibilitySupportEnabled).to.eql(false);

        app.accessibilitySupportEnabled = true;
        expect(app.accessibilitySupportEnabled).to.eql(true);
      });
    }


() => {
        expect(app.accessibilitySupportEnabled).to.eql(false);

        app.accessibilitySupportEnabled = true;
        expect(app.accessibilitySupportEnabled).to.eql(true);
      }


() => {
      it('can set accessibility support enabled', () => {
        expect(app.isAccessibilitySupportEnabled()).to.eql(false);

        app.setAccessibilitySupportEnabled(true);
        expect(app.isAccessibilitySupportEnabled()).to.eql(true);
      });
    }


() => {
        expect(app.isAccessibilitySupportEnabled()).to.eql(false);

        app.setAccessibilitySupportEnabled(true);
        expect(app.isAccessibilitySupportEnabled()).to.eql(true);
      }


() => {
    it('works for directories with package.json', async () => {
      const { appPath } = await runTestApp('app-path');
      expect(appPath).to.equal(path.resolve(fixturesPath, 'api/app-path'));
    });

    it('works for directories with index.js', async () => {
      const { appPath } = await runTestApp('app-path/lib');
      expect(appPath).to.equal(path.resolve(fixturesPath, 'api/app-path/lib'));
    });

    it('works for files without extension', async () => {
      const { appPath } = await runTestApp('app-path/lib/index');
      expect(appPath).to.equal(path.resolve(fixturesPath, 'api/app-path/lib'));
    });

    it('works for files', async () => {
      const { appPath } = await runTestApp('app-path/lib/index.js');
      expect(appPath).to.equal(path.resolve(fixturesPath, 'api/app-path/lib'));
    });
  }


async () => {
      const { appPath } = await runTestApp('app-path');
      expect(appPath).to.equal(path.resolve(fixturesPath, 'api/app-path'));
    }


async () => {
      const { appPath } = await runTestApp('app-path/lib');
      expect(appPath).to.equal(path.resolve(fixturesPath, 'api/app-path/lib'));
    }


async () => {
      const { appPath } = await runTestApp('app-path/lib/index');
      expect(appPath).to.equal(path.resolve(fixturesPath, 'api/app-path/lib'));
    }


async () => {
      const { appPath } = await runTestApp('app-path/lib/index.js');
      expect(appPath).to.equal(path.resolve(fixturesPath, 'api/app-path/lib'));
    }


() => {
    it('returns paths that exist', () => {
      const paths = [
        fs.existsSync(app.getPath('exe')),
        fs.existsSync(app.getPath('home')),
        fs.existsSync(app.getPath('temp'))
      ];
      expect(paths).to.deep.equal([true, true, true]);
    });

    it('throws an error when the name is invalid', () => {
      expect(() => {
        app.getPath('does-not-exist' as any);
      }).to.throw(/Failed to get 'does-not-exist' path/);
    });

    it('returns the overridden path', () => {
      app.setPath('music', __dirname);
      expect(app.getPath('music')).to.equal(__dirname);
    });

    if (process.platform === 'win32') {
      it('gets the folder for recent files', () => {
        const recent = app.getPath('recent');

        // We expect that one of our test machines have overriden this
        // to be something crazy, it'll always include the word "Recent"
        // unless people have been registry-hacking like crazy
        expect(recent).to.include('Recent');
      });

      it('can override the recent files path', () => {
        app.setPath('recent', 'C:\\fake-path');
        expect(app.getPath('recent')).to.equal('C:\\fake-path');
      });
    }
  }


() => {
      const paths = [
        fs.existsSync(app.getPath('exe')),
        fs.existsSync(app.getPath('home')),
        fs.existsSync(app.getPath('temp'))
      ];
      expect(paths).to.deep.equal([true, true, true]);
    }


() => {
      expect(() => {
        app.getPath('does-not-exist' as any);
      }).to.throw(/Failed to get 'does-not-exist' path/);
    }


() => {
        app.getPath('does-not-exist' as any);
      }


() => {
      app.setPath('music', __dirname);
      expect(app.getPath('music')).to.equal(__dirname);
    }


() => {
        const recent = app.getPath('recent');

        // We expect that one of our test machines have overriden this
        // to be something crazy, it'll always include the word "Recent"
        // unless people have been registry-hacking like crazy
        expect(recent).to.include('Recent');
      }


() => {
        app.setPath('recent', 'C:\\fake-path');
        expect(app.getPath('recent')).to.equal('C:\\fake-path');
      }


() => {
    it('throws when a relative path is passed', () => {
      const badPath = 'hey/hi/hello';

      expect(() => {
        app.setPath('music', badPath);
      }).to.throw(/Path must be absolute/);
    });

    it('does not create a new directory by default', () => {
      const badPath = path.join(__dirname, 'music');

      expect(fs.existsSync(badPath)).to.be.false();
      app.setPath('music', badPath);
      expect(fs.existsSync(badPath)).to.be.false();

      expect(() => { app.getPath(badPath as any); }).to.throw();
    });
  }


() => {
      const badPath = 'hey/hi/hello';

      expect(() => {
        app.setPath('music', badPath);
      }).to.throw(/Path must be absolute/);
    }


() => {
        app.setPath('music', badPath);
      }


() => {
      const badPath = path.join(__dirname, 'music');

      expect(fs.existsSync(badPath)).to.be.false();
      app.setPath('music', badPath);
      expect(fs.existsSync(badPath)).to.be.false();

      expect(() => { app.getPath(badPath as any); }).to.throw();
    }


() => { app.getPath(badPath as any); }


() => {
    it('throws when a relative path is passed', () => {
      const badPath = 'hey/hi/hello';

      expect(() => {
        app.setAppLogsPath(badPath);
      }).to.throw(/Path must be absolute/);
    });
  }


() => {
      const badPath = 'hey/hi/hello';

      expect(() => {
        app.setAppLogsPath(badPath);
      }).to.throw(/Path must be absolute/);
    }


() => {
        app.setAppLogsPath(badPath);
      }


() => {
    let w: BrowserWindow;

    before(function () {
      if (process.platform === 'linux') {
        this.skip();
      }
      session.fromPartition('empty-certificate').setCertificateVerifyProc((req, cb) => { cb(0); });
    });

    beforeEach(() => {
      w = new BrowserWindow({
        show: false,
        webPreferences: {
          nodeIntegration: true,
          partition: 'empty-certificate'
        }
      });
    });

    afterEach(() => closeWindow(w).then(() => { w = null as any; }));

    after(() => session.fromPartition('empty-certificate').setCertificateVerifyProc(null));

    it('can respond with empty certificate list', async () => {
      app.once('select-client-certificate', function (event, webContents, url, list, callback) {
        console.log('select-client-certificate emitted');
        event.preventDefault();
        callback();
      });
      await w.webContents.loadURL(secureUrl);
      expect(w.webContents.getTitle()).to.equal('denied');
    });
  }


(req, cb) => { cb(0); }


() => {
      w = new BrowserWindow({
        show: false,
        webPreferences: {
          nodeIntegration: true,
          partition: 'empty-certificate'
        }
      });
    }


() => session.fromPartition('empty-certificate').setCertificateVerifyProc(null)


async () => {
      app.once('select-client-certificate', function (event, webContents, url, list, callback) {
        console.log('select-client-certificate emitted');
        event.preventDefault();
        callback();
      });
      await w.webContents.loadURL(secureUrl);
      expect(w.webContents.getTitle()).to.equal('denied');
    }


() => {
    const protocol = 'electron-test';
    const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe');
    const processStartArgs = [
      '--processStart', `"${path.basename(process.execPath)}"`,
      '--process-start-args', '"--hidden"'
    ];

    let Winreg: any;
    let classesKey: any;

    before(function () {
      if (process.platform !== 'win32') {
        this.skip();
      } else {
        Winreg = require('winreg');

        classesKey = new Winreg({
          hive: Winreg.HKCU,
          key: '\\Software\\Classes\\'
        });
      }
    });

    after(function (done) {
      if (process.platform !== 'win32') {
        done();
      } else {
        const protocolKey = new Winreg({
          hive: Winreg.HKCU,
          key: `\\Software\\Classes\\${protocol}`
        });

        // The last test leaves the registry dirty,
        // delete the protocol key for those of us who test at home
        protocolKey.destroy(() => done());
      }
    });

    beforeEach(() => {
      app.removeAsDefaultProtocolClient(protocol);
      app.removeAsDefaultProtocolClient(protocol, updateExe, processStartArgs);
    });

    afterEach(() => {
      app.removeAsDefaultProtocolClient(protocol);
      expect(app.isDefaultProtocolClient(protocol)).to.equal(false);

      app.removeAsDefaultProtocolClient(protocol, updateExe, processStartArgs);
      expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.equal(false);
    });

    it('sets the app as the default protocol client', () => {
      expect(app.isDefaultProtocolClient(protocol)).to.equal(false);
      app.setAsDefaultProtocolClient(protocol);
      expect(app.isDefaultProtocolClient(protocol)).to.equal(true);
    });

    it('allows a custom path and args to be specified', () => {
      expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.equal(false);
      app.setAsDefaultProtocolClient(protocol, updateExe, processStartArgs);

      expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.equal(true);
      expect(app.isDefaultProtocolClient(protocol)).to.equal(false);
    });

    it('creates a registry entry for the protocol class', async () => {
      app.setAsDefaultProtocolClient(protocol);

      const keys = await promisify(classesKey.keys).call(classesKey) as any[];
      const exists = !!keys.find(key => key.key.includes(protocol));
      expect(exists).to.equal(true);
    });

    it('completely removes a registry entry for the protocol class', async () => {
      app.setAsDefaultProtocolClient(protocol);
      app.removeAsDefaultProtocolClient(protocol);

      const keys = await promisify(classesKey.keys).call(classesKey) as any[];
      const exists = !!keys.find(key => key.key.includes(protocol));
      expect(exists).to.equal(false);
    });

    it('only unsets a class registry key if it contains other data', async () => {
      app.setAsDefaultProtocolClient(protocol);

      const protocolKey = new Winreg({
        hive: Winreg.HKCU,
        key: `\\Software\\Classes\\${protocol}`
      });

      await promisify(protocolKey.set).call(protocolKey, 'test-value', 'REG_BINARY', '123');
      app.removeAsDefaultProtocolClient(protocol);

      const keys = await promisify(classesKey.keys).call(classesKey) as any[];
      const exists = !!keys.find(key => key.key.includes(protocol));
      expect(exists).to.equal(true);
    });

    it('sets the default client such that getApplicationNameForProtocol returns Electron', () => {
      app.setAsDefaultProtocolClient(protocol);
      expect(app.getApplicationNameForProtocol(`${protocol}://`)).to.equal('Electron');
    });
  }


() => {
      app.removeAsDefaultProtocolClient(protocol);
      app.removeAsDefaultProtocolClient(protocol, updateExe, processStartArgs);
    }


() => {
      app.removeAsDefaultProtocolClient(protocol);
      expect(app.isDefaultProtocolClient(protocol)).to.equal(false);

      app.removeAsDefaultProtocolClient(protocol, updateExe, processStartArgs);
      expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.equal(false);
    }


() => {
      expect(app.isDefaultProtocolClient(protocol)).to.equal(false);
      app.setAsDefaultProtocolClient(protocol);
      expect(app.isDefaultProtocolClient(protocol)).to.equal(true);
    }


() => {
      expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.equal(false);
      app.setAsDefaultProtocolClient(protocol, updateExe, processStartArgs);

      expect(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs)).to.equal(true);
      expect(app.isDefaultProtocolClient(protocol)).to.equal(false);
    }


async () => {
      app.setAsDefaultProtocolClient(protocol);

      const keys = await promisify(classesKey.keys).call(classesKey) as any[];
      const exists = !!keys.find(key => key.key.includes(protocol));
      expect(exists).to.equal(true);
    }


key => key.key.includes(protocol)


async () => {
      app.setAsDefaultProtocolClient(protocol);
      app.removeAsDefaultProtocolClient(protocol);

      const keys = await promisify(classesKey.keys).call(classesKey) as any[];
      const exists = !!keys.find(key => key.key.includes(protocol));
      expect(exists).to.equal(false);
    }


async () => {
      app.setAsDefaultProtocolClient(protocol);

      const protocolKey = new Winreg({
        hive: Winreg.HKCU,
        key: `\\Software\\Classes\\${protocol}`
      });

      await promisify(protocolKey.set).call(protocolKey, 'test-value', 'REG_BINARY', '123');
      app.removeAsDefaultProtocolClient(protocol);

      const keys = await promisify(classesKey.keys).call(classesKey) as any[];
      const exists = !!keys.find(key => key.key.includes(protocol));
      expect(exists).to.equal(true);
    }


() => {
      app.setAsDefaultProtocolClient(protocol);
      expect(app.getApplicationNameForProtocol(`${protocol}://`)).to.equal('Electron');
    }


() => {
    it('returns application names for common protocols', function () {
      // We can't expect particular app names here, but these protocols should
      // at least have _something_ registered. Except on our Linux CI
      // environment apparently.
      if (process.platform === 'linux') {
        this.skip();
      }

      const protocols = [
        'http://',
        'https://'
      ];
      protocols.forEach((protocol) => {
        expect(app.getApplicationNameForProtocol(protocol)).to.not.equal('');
      });
    });

    it('returns an empty string for a bogus protocol', () => {
      expect(app.getApplicationNameForProtocol('bogus-protocol://')).to.equal('');
    });
  }


(protocol) => {
        expect(app.getApplicationNameForProtocol(protocol)).to.not.equal('');
      }


() => {
      expect(app.getApplicationNameForProtocol('bogus-protocol://')).to.equal('');
    }


() => {
    it('returns promise rejection for a bogus protocol', async function () {
      await expect(
        app.getApplicationInfoForProtocol('bogus-protocol://')
      ).to.eventually.be.rejectedWith(
        'Unable to retrieve installation path to app'
      );
    });

    it('returns resolved promise with appPath, displayName and icon', async function () {
      const appInfo = await app.getApplicationInfoForProtocol('https://');
      expect(appInfo.path).not.to.be.undefined();
      expect(appInfo.name).not.to.be.undefined();
      expect(appInfo.icon).not.to.be.undefined();
    });
  }


() => {
    it('returns false for a bogus protocol', () => {
      expect(app.isDefaultProtocolClient('bogus-protocol://')).to.equal(false);
    });
  }


() => {
      expect(app.isDefaultProtocolClient('bogus-protocol://')).to.equal(false);
    }


() => {
    before(function () {
      if (process.platform !== 'win32') {
        this.skip();
      }
    });

    it('does not launch for argument following a URL', async () => {
      const appPath = path.join(fixturesPath, 'api', 'quit-app');
      // App should exit with non 123 code.
      const first = cp.spawn(process.execPath, [appPath, 'electron-test:?', 'abc']);
      const [code] = await emittedOnce(first, 'exit');
      expect(code).to.not.equal(123);
    });

    it('launches successfully for argument following a file path', async () => {
      const appPath = path.join(fixturesPath, 'api', 'quit-app');
      // App should exit with code 123.
      const first = cp.spawn(process.execPath, [appPath, 'e:\\abc', 'abc']);
      const [code] = await emittedOnce(first, 'exit');
      expect(code).to.equal(123);
    });

    it('launches successfully for multiple URIs following --', async () => {
      const appPath = path.join(fixturesPath, 'api', 'quit-app');
      // App should exit with code 123.
      const first = cp.spawn(process.execPath, [appPath, '--', 'http://electronjs.org', 'electron-test://testdata']);
      const [code] = await emittedOnce(first, 'exit');
      expect(code).to.equal(123);
    });
  }


async () => {
      const appPath = path.join(fixturesPath, 'api', 'quit-app');
      // App should exit with non 123 code.
      const first = cp.spawn(process.execPath, [appPath, 'electron-test:?', 'abc']);
      const [code] = await emittedOnce(first, 'exit');
      expect(code).to.not.equal(123);
    }


async () => {
      const appPath = path.join(fixturesPath, 'api', 'quit-app');
      // App should exit with code 123.
      const first = cp.spawn(process.execPath, [appPath, 'e:\\abc', 'abc']);
      const [code] = await emittedOnce(first, 'exit');
      expect(code).to.equal(123);
    }


async () => {
      const appPath = path.join(fixturesPath, 'api', 'quit-app');
      // App should exit with code 123.
      const first = cp.spawn(process.execPath, [appPath, '--', 'http://electronjs.org', 'electron-test://testdata']);
      const [code] = await emittedOnce(first, 'exit');
      expect(code).to.equal(123);
    }


() => {
    const iconPath = path.join(__dirname, 'fixtures/assets/icon.ico');
    const sizes = {
      small: 16,
      normal: 32,
      large: process.platform === 'win32' ? 32 : 48
    };

    it('fetches a non-empty icon', async () => {
      const icon = await app.getFileIcon(iconPath);
      expect(icon.isEmpty()).to.equal(false);
    });

    it('fetches normal icon size by default', async () => {
      const icon = await app.getFileIcon(iconPath);
      const size = icon.getSize();

      expect(size.height).to.equal(sizes.normal);
      expect(size.width).to.equal(sizes.normal);
    });

    describe('size option', () => {
      it('fetches a small icon', async () => {
        const icon = await app.getFileIcon(iconPath, { size: 'small' });
        const size = icon.getSize();

        expect(size.height).to.equal(sizes.small);
        expect(size.width).to.equal(sizes.small);
      });

      it('fetches a normal icon', async () => {
        const icon = await app.getFileIcon(iconPath, { size: 'normal' });
        const size = icon.getSize();

        expect(size.height).to.equal(sizes.normal);
        expect(size.width).to.equal(sizes.normal);
      });

      it('fetches a large icon', async () => {
        // macOS does not support large icons
        if (process.platform === 'darwin') return;

        const icon = await app.getFileIcon(iconPath, { size: 'large' });
        const size = icon.getSize();

        expect(size.height).to.equal(sizes.large);
        expect(size.width).to.equal(sizes.large);
      });
    });
  }


async () => {
      const icon = await app.getFileIcon(iconPath);
      expect(icon.isEmpty()).to.equal(false);
    }


async () => {
      const icon = await app.getFileIcon(iconPath);
      const size = icon.getSize();

      expect(size.height).to.equal(sizes.normal);
      expect(size.width).to.equal(sizes.normal);
    }


() => {
      it('fetches a small icon', async () => {
        const icon = await app.getFileIcon(iconPath, { size: 'small' });
        const size = icon.getSize();

        expect(size.height).to.equal(sizes.small);
        expect(size.width).to.equal(sizes.small);
      });

      it('fetches a normal icon', async () => {
        const icon = await app.getFileIcon(iconPath, { size: 'normal' });
        const size = icon.getSize();

        expect(size.height).to.equal(sizes.normal);
        expect(size.width).to.equal(sizes.normal);
      });

      it('fetches a large icon', async () => {
        // macOS does not support large icons
        if (process.platform === 'darwin') return;

        const icon = await app.getFileIcon(iconPath, { size: 'large' });
        const size = icon.getSize();

        expect(size.height).to.equal(sizes.large);
        expect(size.width).to.equal(sizes.large);
      });
    }


async () => {
        const icon = await app.getFileIcon(iconPath, { size: 'small' });
        const size = icon.getSize();

        expect(size.height).to.equal(sizes.small);
        expect(size.width).to.equal(sizes.small);
      }


async () => {
        const icon = await app.getFileIcon(iconPath, { size: 'normal' });
        const size = icon.getSize();

        expect(size.height).to.equal(sizes.normal);
        expect(size.width).to.equal(sizes.normal);
      }


async () => {
        // macOS does not support large icons
        if (process.platform === 'darwin') return;

        const icon = await app.getFileIcon(iconPath, { size: 'large' });
        const size = icon.getSize();

        expect(size.height).to.equal(sizes.large);
        expect(size.width).to.equal(sizes.large);
      }


() => {
    it('returns memory and cpu stats of all running electron processes', () => {
      const appMetrics = app.getAppMetrics();
      expect(appMetrics).to.be.an('array').and.have.lengthOf.at.least(1, 'App memory info object is not > 0');

      const types = [];
      for (const entry of appMetrics) {
        expect(entry.pid).to.be.above(0, 'pid is not > 0');
        expect(entry.type).to.be.a('string').that.does.not.equal('');
        expect(entry.creationTime).to.be.a('number').that.is.greaterThan(0);

        types.push(entry.type);
        expect(entry.cpu).to.have.ownProperty('percentCPUUsage').that.is.a('number');
        expect(entry.cpu).to.have.ownProperty('idleWakeupsPerSecond').that.is.a('number');

        expect(entry.memory).to.have.property('workingSetSize').that.is.greaterThan(0);
        expect(entry.memory).to.have.property('peakWorkingSetSize').that.is.greaterThan(0);

        if (entry.type === 'Utility' || entry.type === 'GPU') {
          expect(entry.serviceName).to.be.a('string').that.does.not.equal('');
        }

        if (entry.type === 'Utility') {
          expect(entry).to.have.property('name').that.is.a('string');
        }

        if (process.platform === 'win32') {
          expect(entry.memory).to.have.property('privateBytes').that.is.greaterThan(0);
        }

        if (process.platform !== 'linux') {
          expect(entry.sandboxed).to.be.a('boolean');
        }

        if (process.platform === 'win32') {
          expect(entry.integrityLevel).to.be.a('string');
        }
      }

      if (process.platform === 'darwin') {
        expect(types).to.include('GPU');
      }

      expect(types).to.include('Browser');
    });
  }


() => {
      const appMetrics = app.getAppMetrics();
      expect(appMetrics).to.be.an('array').and.have.lengthOf.at.least(1, 'App memory info object is not > 0');

      const types = [];
      for (const entry of appMetrics) {
        expect(entry.pid).to.be.above(0, 'pid is not > 0');
        expect(entry.type).to.be.a('string').that.does.not.equal('');
        expect(entry.creationTime).to.be.a('number').that.is.greaterThan(0);

        types.push(entry.type);
        expect(entry.cpu).to.have.ownProperty('percentCPUUsage').that.is.a('number');
        expect(entry.cpu).to.have.ownProperty('idleWakeupsPerSecond').that.is.a('number');

        expect(entry.memory).to.have.property('workingSetSize').that.is.greaterThan(0);
        expect(entry.memory).to.have.property('peakWorkingSetSize').that.is.greaterThan(0);

        if (entry.type === 'Utility' || entry.type === 'GPU') {
          expect(entry.serviceName).to.be.a('string').that.does.not.equal('');
        }

        if (entry.type === 'Utility') {
          expect(entry).to.have.property('name').that.is.a('string');
        }

        if (process.platform === 'win32') {
          expect(entry.memory).to.have.property('privateBytes').that.is.greaterThan(0);
        }

        if (process.platform !== 'linux') {
          expect(entry.sandboxed).to.be.a('boolean');
        }

        if (process.platform === 'win32') {
          expect(entry.integrityLevel).to.be.a('string');
        }
      }

      if (process.platform === 'darwin') {
        expect(types).to.include('GPU');
      }

      expect(types).to.include('Browser');
    }


() => {
    it('returns the graphic features statuses', () => {
      const features = app.getGPUFeatureStatus();
      expect(features).to.have.ownProperty('webgl').that.is.a('string');
      expect(features).to.have.ownProperty('gpu_compositing').that.is.a('string');
    });
  }


() => {
      const features = app.getGPUFeatureStatus();
      expect(features).to.have.ownProperty('webgl').that.is.a('string');
      expect(features).to.have.ownProperty('gpu_compositing').that.is.a('string');
    }


() => {
    const appPath = path.join(fixturesPath, 'api', 'gpu-info.js');

    const getGPUInfo = async (type: string) => {
      const appProcess = cp.spawn(process.execPath, [appPath, type]);
      let gpuInfoData = '';
      let errorData = '';
      appProcess.stdout.on('data', (data) => {
        gpuInfoData += data;
      });
      appProcess.stderr.on('data', (data) => {
        errorData += data;
      });
      const [exitCode] = await emittedOnce(appProcess, 'exit');
      if (exitCode === 0) {
        // return info data on successful exit
        return JSON.parse(gpuInfoData);
      } else {
        // return error if not clean exit
        return Promise.reject(new Error(errorData));
      }
    };
    const verifyBasicGPUInfo = async (gpuInfo: any) => {
      // Devices information is always present in the available info.
      expect(gpuInfo).to.have.ownProperty('gpuDevice')
        .that.is.an('array')
        .and.does.not.equal([]);

      const device = gpuInfo.gpuDevice[0];
      expect(device).to.be.an('object')
        .and.to.have.property('deviceId')
        .that.is.a('number')
        .not.lessThan(0);
    };

    it('succeeds with basic GPUInfo', async () => {
      const gpuInfo = await getGPUInfo('basic');
      await verifyBasicGPUInfo(gpuInfo);
    });

    it('succeeds with complete GPUInfo', async () => {
      const completeInfo = await getGPUInfo('complete');
      if (process.platform === 'linux') {
        // For linux and macOS complete info is same as basic info
        await verifyBasicGPUInfo(completeInfo);
        const basicInfo = await getGPUInfo('basic');
        expect(completeInfo).to.deep.equal(basicInfo);
      } else {
        // Gl version is present in the complete info.
        expect(completeInfo).to.have.ownProperty('auxAttributes')
          .that.is.an('object');
        if (completeInfo.gpuDevice.active) {
          expect(completeInfo.auxAttributes).to.have.ownProperty('glVersion')
            .that.is.a('string')
            .and.does.not.equal([]);
        }
      }
    });

    it('fails for invalid info_type', () => {
      const invalidType = 'invalid';
      const expectedErrorMessage = "Invalid info type. Use 'basic' or 'complete'";
      return expect(app.getGPUInfo(invalidType as any)).to.eventually.be.rejectedWith(expectedErrorMessage);
    });
  }


async (type: string) => {
      const appProcess = cp.spawn(process.execPath, [appPath, type]);
      let gpuInfoData = '';
      let errorData = '';
      appProcess.stdout.on('data', (data) => {
        gpuInfoData += data;
      });
      appProcess.stderr.on('data', (data) => {
        errorData += data;
      });
      const [exitCode] = await emittedOnce(appProcess, 'exit');
      if (exitCode === 0) {
        // return info data on successful exit
        return JSON.parse(gpuInfoData);
      } else {
        // return error if not clean exit
        return Promise.reject(new Error(errorData));
      }
    }


(data) => {
        gpuInfoData += data;
      }


(data) => {
        errorData += data;
      }


async (gpuInfo: any) => {
      // Devices information is always present in the available info.
      expect(gpuInfo).to.have.ownProperty('gpuDevice')
        .that.is.an('array')
        .and.does.not.equal([]);

      const device = gpuInfo.gpuDevice[0];
      expect(device).to.be.an('object')
        .and.to.have.property('deviceId')
        .that.is.a('number')
        .not.lessThan(0);
    }


async () => {
      const gpuInfo = await getGPUInfo('basic');
      await verifyBasicGPUInfo(gpuInfo);
    }


async () => {
      const completeInfo = await getGPUInfo('complete');
      if (process.platform === 'linux') {
        // For linux and macOS complete info is same as basic info
        await verifyBasicGPUInfo(completeInfo);
        const basicInfo = await getGPUInfo('basic');
        expect(completeInfo).to.deep.equal(basicInfo);
      } else {
        // Gl version is present in the complete info.
        expect(completeInfo).to.have.ownProperty('auxAttributes')
          .that.is.an('object');
        if (completeInfo.gpuDevice.active) {
          expect(completeInfo.auxAttributes).to.have.ownProperty('glVersion')
            .that.is.a('string')
            .and.does.not.equal([]);
        }
      }
    }


() => {
      const invalidType = 'invalid';
      const expectedErrorMessage = "Invalid info type. Use 'basic' or 'complete'";
      return expect(app.getGPUInfo(invalidType as any)).to.eventually.be.rejectedWith(expectedErrorMessage);
    }


() => {
    let appProcess: cp.ChildProcess = null as any;
    let server: net.Server = null as any;
    const socketPath = process.platform === 'win32' ? '\\\\.\\pipe\\electron-mixed-sandbox' : '/tmp/electron-mixed-sandbox';

    beforeEach(function (done) {
      if (process.platform === 'linux' && (process.arch === 'arm64' || process.arch === 'arm')) {
        // Our ARM tests are run on VSTS rather than CircleCI, and the Docker
        // setup on VSTS disallows syscalls that Chrome requires for setting up
        // sandboxing.
        // See:
        // - https://docs.docker.com/engine/security/seccomp/#significant-syscalls-blocked-by-the-default-profile
        // - https://chromium.googlesource.com/chromium/src/+/70.0.3538.124/sandbox/linux/services/credentials.cc#292
        // - https://github.com/docker/docker-ce/blob/ba7dfc59ccfe97c79ee0d1379894b35417b40bca/components/engine/profiles/seccomp/seccomp_default.go#L497
        // - https://blog.jessfraz.com/post/how-to-use-new-docker-seccomp-profiles/
        //
        // Adding `--cap-add SYS_ADMIN` or `--security-opt seccomp=unconfined`
        // to the Docker invocation allows the syscalls that Chrome needs, but
        // are probably more permissive than we'd like.
        this.skip();
      }
      fs.unlink(socketPath, () => {
        server = net.createServer();
        server.listen(socketPath);
        done();
      });
    });

    afterEach(done => {
      if (appProcess != null) appProcess.kill();

      server.close(() => {
        if (process.platform === 'win32') {
          done();
        } else {
          fs.unlink(socketPath, () => done());
        }
      });
    });

    describe('when app.enableSandbox() is called', () => {
      // TODO(jeremy): figure out why this times out under ASan
      ifit(!process.env.IS_ASAN)('adds --enable-sandbox to all renderer processes', done => {
        const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app');
        appProcess = cp.spawn(process.execPath, [appPath, '--app-enable-sandbox']);

        server.once('error', error => { done(error); });

        server.on('connection', client => {
          client.once('data', (data) => {
            const argv = JSON.parse(data.toString());
            expect(argv.sandbox).to.include('--enable-sandbox');
            expect(argv.sandbox).to.not.include('--no-sandbox');

            expect(argv.noSandbox).to.include('--enable-sandbox');
            expect(argv.noSandbox).to.not.include('--no-sandbox');

            expect(argv.noSandboxDevtools).to.equal(true);
            expect(argv.sandboxDevtools).to.equal(true);

            done();
          });
        });
      });
    });

    describe('when the app is launched with --enable-sandbox', () => {
      // TODO(jeremy): figure out why this times out under ASan
      ifit(!process.env.IS_ASAN)('adds --enable-sandbox to all renderer processes', done => {
        const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app');
        appProcess = cp.spawn(process.execPath, [appPath, '--enable-sandbox']);

        server.once('error', error => { done(error); });

        server.on('connection', client => {
          client.once('data', data => {
            const argv = JSON.parse(data.toString());
            expect(argv.sandbox).to.include('--enable-sandbox');
            expect(argv.sandbox).to.not.include('--no-sandbox');

            expect(argv.noSandbox).to.include('--enable-sandbox');
            expect(argv.noSandbox).to.not.include('--no-sandbox');

            expect(argv.noSandboxDevtools).to.equal(true);
            expect(argv.sandboxDevtools).to.equal(true);

            done();
          });
        });
      });
    });
  }


done => {
      if (appProcess != null) appProcess.kill();

      server.close(() => {
        if (process.platform === 'win32') {
          done();
        } else {
          fs.unlink(socketPath, () => done());
        }
      });
    }


() => {
      // TODO(jeremy): figure out why this times out under ASan
      ifit(!process.env.IS_ASAN)('adds --enable-sandbox to all renderer processes', done => {
        const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app');
        appProcess = cp.spawn(process.execPath, [appPath, '--app-enable-sandbox']);

        server.once('error', error => { done(error); });

        server.on('connection', client => {
          client.once('data', (data) => {
            const argv = JSON.parse(data.toString());
            expect(argv.sandbox).to.include('--enable-sandbox');
            expect(argv.sandbox).to.not.include('--no-sandbox');

            expect(argv.noSandbox).to.include('--enable-sandbox');
            expect(argv.noSandbox).to.not.include('--no-sandbox');

            expect(argv.noSandboxDevtools).to.equal(true);
            expect(argv.sandboxDevtools).to.equal(true);

            done();
          });
        });
      });
    }


done => {
        const appPath = path.join(fixturesPath, 'api', 'mixed-sandbox-app');
        appProcess = cp.spawn(process.execPath, [appPath, '--app-enable-sandbox']);

        server.once('error', error => { done(error); });

        server.on('connection', client => {
          client.once('data', (data) => {
            const argv = JSON.parse(data.toString());
            expect(argv.sandbox).to.include('--enable-sandbox');
            expect(argv.sandbox).to.not.include('--no-sandbox');

            expect(argv.noSandbox).to.include('--enable-sandbox');
            expect(argv.noSandbox).to.not.include('--no-sandbox');

            expect(argv.noSandboxDevtools).to.equal(true);
            expect(argv.sandboxDevtools).to.equal(true);

            done();
          });
        });
      }


error => { done(error); }


client => {
          client.once('data', (data) => {
            const argv = JSON.parse(data.toString());
            expect(argv.sandbox).to.include('--enable-sandbox');
            expect(argv.sandbox).to.not.include('--no-sandbox');

            expect(argv.noSandbox).to.include('--enable-sandbox');
            expect(argv.noSandbox).to.not.include('--no-sandbox');

            expect(argv.noSandboxDevtools).to.equal(true);
            expect(argv.sandboxDevtools).to.equal(true);

            done();
          });
        }


(data) => {
            const argv = JSON.parse(data.toString());
            expect(argv.sandbox).to.include('--enable-sandbox');
            expect(argv.sandbox).to.not.include('--no-sandbox');

            expect(argv.noSandbox).to.include('--enable-sandbox');
            expect(argv.noSandbox).to.not.include('--no-sandbox');

            expect(argv.noSandboxDevtools).to.equal(true);
            expect(argv.sandboxDevtools).to.equal(true);

            done();
          }