(player, playerId) => {
                    if (player.socketId == id) {
                        console.log('BABYLON: disconnect player - ' + player.id);
                        player.dispose(room);
                        delete room.players[playerId];
                        if (!Object.keys(room.players).length) {
                            console.log('remove room');
                            room.removeRoom();
                            delete self.rooms[player.roomId];

                        }
                    }
                }


updatedPlayer => {
            const characterId = updatedPlayer.activePlayerId;

            console.log('BABYLON: update player - ' + characterId);
            if (updatedPlayer.activePlayerAttack == true) {
                console.log('BABYLON: player attack - ' + characterId);

                return;
            }

            const roomId = updatedPlayer.activeRoomId;
            const room = self.getRoomById(roomId);
            const player = room.players[characterId];
            const scene = room.scene;
            if(player) {
                PlayerActionManager.goToTarget(scene, player, updatedPlayer.targetPoint, roomId, self);
            }
        }


export class AIServer {
    public engine: BABYLON.Engine;
    protected scene: BABYLON.Scene;
    public socket;
    protected rooms: Room[] = [];

    constructor(canvas, socket) {
        this.socket = socket.connect('http://127.0.0.1:' + 5000, {query: 'monsterServer=1'});
        this.initEngine(canvas);
    }

    getRoomById(roomId: string, createNewIfNotExists: boolean = true): Room {
        if ((this.rooms[roomId] == undefined)) {
            if (!createNewIfNotExists) {
                return null;
            }

            this.rooms[roomId] = new Room(this);
        }

        return this.rooms[roomId];
    }

    public initEngine(canvas) {
        let self = this;
        this.engine = (canvas) ? new BABYLON.Engine(canvas) : new BABYLON.NullEngine();
        this
            .socketShowEnemies()
            .socketUpdateEnemy()
            .socketPlayerConnected()
            .socketUpdatePlayer()
            .removePlayer()
            .socketCreateRoom();

        this.engine.runRenderLoop(() => {
            for (let key in self.rooms) {
                self.getRoomById(key).scene.render();
            }
        });
    }

    public socketUpdateEnemy() {
        let self = this;
        this.socket.on('updateEnemy', data => {
            let roomId = data.roomId;
            let remoteEnemy = data.enemy;
            let remoteEnemyId = data.enemyKey;
            let room = self.getRoomById(roomId);
            let localEnemy = room.enemies[remoteEnemyId];
            console.log('BABYLON: update enemy - ' + remoteEnemyId);
            if (remoteEnemy.statistics.hp <= 0) {
                localEnemy.clearActiveTarget(room);
                delete room.enemies[remoteEnemyId];
            }
        });

        return this;
    }

    public socketShowEnemies() {
        let self = this;
        this.socket.on('createEnemies', data => {
            let roomId = data.roomId;
            let room = self.getRoomById(roomId);
            let scene = room.scene;
            if(room.sceneType != data.sceneType) {
                console.log('BABYLON: clear enemies - ' + roomId);

                room.enemies.forEach((enemy) => {
                    enemy.clearActiveTarget(room);
                });
                room.enemies = [];
            }

            room.sceneType = data.sceneType;
            if (!room.enemies.length) {
                console.log('BABYLON: create enemies - ' + roomId);
                data.enemies.forEach((enemyData, key) => {
                    let enemy = room.enemies[key];
                    if (enemyData.statistics.hp > 0 && !enemy) {
                        room.enemies[key] = new Enemy(key, enemyData.statistics.walkSpeed, new BABYLON.Vector3(enemyData.position.x, enemyData.position.y, enemyData.position.z), scene);
                    }
                });
            } else {
                console.log('BABYLON: enemies exists - ' + roomId);
            }

        });

        return this;
    }

    public socketCreateRoom() {
        let self = this;
        this.socket.on('createRoom', roomId => {
            let room = self.getRoomById(roomId, false);
            if (!room) {
                console.log('BABYLON: crate new room with scene - ' + roomId);
                self.rooms[roomId] = new Room(self);
            } else {
                console.log('BABYLON: room exists - ' + roomId);
            }
        });

        return this;
    }

    public socketPlayerConnected() {
        let self = this;
        this.socket.on('showPlayer', playerData => {
            console.log('BABYLON: connected new player - ' + playerData.connectionId);
            let activeCharacter = playerData.activePlayer;
            let roomId = playerData.activeRoom.id;
            let room = self.getRoomById(roomId);
            let scene = room.scene;

            if (playerData.connectionId !== self.socket.id) {
                let remotePlayer = new RemotePlayer(
                    activeCharacter.id,
                    playerData.connectionId,
                    activeCharacter.statistics.walkSpeed,
                    roomId,
                    scene,
                    new BABYLON.Vector3(playerData.position.x, playerData.position.y, playerData.position.z)
                );

                room.players[activeCharacter.id] = remotePlayer;
                EnemyActionManager.registerPlayerInEnemyActionManager(self, remotePlayer);
            }
        });

        return this;
    }

    protected removePlayer() {
        let self = this;
        this.socket.on('removePlayer', id => {
            Object.keys(self.rooms).forEach((roomId) => {
                let room = self.rooms[roomId];
                room.players.forEach((player, playerId) => {
                    if (player.socketId == id) {
                        console.log('BABYLON: disconnect player - ' + player.id);
                        player.dispose(room);
                        delete room.players[playerId];
                        if (!Object.keys(room.players).length) {
                            console.log('remove room');
                            room.removeRoom();
                            delete self.rooms[player.roomId];

                        }
                    }
                });
            });
        });

        return this;
    }

    public socketUpdatePlayer() {
        let self = this;
        this.socket.on('updatePlayer', updatedPlayer => {
            const characterId = updatedPlayer.activePlayerId;

            console.log('BABYLON: update player - ' + characterId);
            if (updatedPlayer.activePlayerAttack == true) {
                console.log('BABYLON: player attack - ' + characterId);

                return;
            }

            const roomId = updatedPlayer.activeRoomId;
            const room = self.getRoomById(roomId);
            const player = room.players[characterId];
            const scene = room.scene;
            if(player) {
                PlayerActionManager.goToTarget(scene, player, updatedPlayer.targetPoint, roomId, self);
            }
        });

        return this;
    }
}


getRoomById(roomId: string, createNewIfNotExists: boolean = true): Room {
        if ((this.rooms[roomId] == undefined)) {
            if (!createNewIfNotExists) {
                return null;
            }

            this.rooms[roomId] = new Room(this);
        }

        return this.rooms[roomId];
    }


public initEngine(canvas) {
        let self = this;
        this.engine = (canvas) ? new BABYLON.Engine(canvas) : new BABYLON.NullEngine();
        this
            .socketShowEnemies()
            .socketUpdateEnemy()
            .socketPlayerConnected()
            .socketUpdatePlayer()
            .removePlayer()
            .socketCreateRoom();

        this.engine.runRenderLoop(() => {
            for (let key in self.rooms) {
                self.getRoomById(key).scene.render();
            }
        });
    }


public socketUpdateEnemy() {
        let self = this;
        this.socket.on('updateEnemy', data => {
            let roomId = data.roomId;
            let remoteEnemy = data.enemy;
            let remoteEnemyId = data.enemyKey;
            let room = self.getRoomById(roomId);
            let localEnemy = room.enemies[remoteEnemyId];
            console.log('BABYLON: update enemy - ' + remoteEnemyId);
            if (remoteEnemy.statistics.hp <= 0) {
                localEnemy.clearActiveTarget(room);
                delete room.enemies[remoteEnemyId];
            }
        });

        return this;
    }


public socketShowEnemies() {
        let self = this;
        this.socket.on('createEnemies', data => {
            let roomId = data.roomId;
            let room = self.getRoomById(roomId);
            let scene = room.scene;
            if(room.sceneType != data.sceneType) {
                console.log('BABYLON: clear enemies - ' + roomId);

                room.enemies.forEach((enemy) => {
                    enemy.clearActiveTarget(room);
                });
                room.enemies = [];
            }

            room.sceneType = data.sceneType;
            if (!room.enemies.length) {
                console.log('BABYLON: create enemies - ' + roomId);
                data.enemies.forEach((enemyData, key) => {
                    let enemy = room.enemies[key];
                    if (enemyData.statistics.hp > 0 && !enemy) {
                        room.enemies[key] = new Enemy(key, enemyData.statistics.walkSpeed, new BABYLON.Vector3(enemyData.position.x, enemyData.position.y, enemyData.position.z), scene);
                    }
                });
            } else {
                console.log('BABYLON: enemies exists - ' + roomId);
            }

        });

        return this;
    }


public socketCreateRoom() {
        let self = this;
        this.socket.on('createRoom', roomId => {
            let room = self.getRoomById(roomId, false);
            if (!room) {
                console.log('BABYLON: crate new room with scene - ' + roomId);
                self.rooms[roomId] = new Room(self);
            } else {
                console.log('BABYLON: room exists - ' + roomId);
            }
        });

        return this;
    }


public socketPlayerConnected() {
        let self = this;
        this.socket.on('showPlayer', playerData => {
            console.log('BABYLON: connected new player - ' + playerData.connectionId);
            let activeCharacter = playerData.activePlayer;
            let roomId = playerData.activeRoom.id;
            let room = self.getRoomById(roomId);
            let scene = room.scene;

            if (playerData.connectionId !== self.socket.id) {
                let remotePlayer = new RemotePlayer(
                    activeCharacter.id,
                    playerData.connectionId,
                    activeCharacter.statistics.walkSpeed,
                    roomId,
                    scene,
                    new BABYLON.Vector3(playerData.position.x, playerData.position.y, playerData.position.z)
                );

                room.players[activeCharacter.id] = remotePlayer;
                EnemyActionManager.registerPlayerInEnemyActionManager(self, remotePlayer);
            }
        });

        return this;
    }


protected removePlayer() {
        let self = this;
        this.socket.on('removePlayer', id => {
            Object.keys(self.rooms).forEach((roomId) => {
                let room = self.rooms[roomId];
                room.players.forEach((player, playerId) => {
                    if (player.socketId == id) {
                        console.log('BABYLON: disconnect player - ' + player.id);
                        player.dispose(room);
                        delete room.players[playerId];
                        if (!Object.keys(room.players).length) {
                            console.log('remove room');
                            room.removeRoom();
                            delete self.rooms[player.roomId];

                        }
                    }
                });
            });
        });

        return this;
    }


public socketUpdatePlayer() {
        let self = this;
        this.socket.on('updatePlayer', updatedPlayer => {
            const characterId = updatedPlayer.activePlayerId;

            console.log('BABYLON: update player - ' + characterId);
            if (updatedPlayer.activePlayerAttack == true) {
                console.log('BABYLON: player attack - ' + characterId);

                return;
            }

            const roomId = updatedPlayer.activeRoomId;
            const room = self.getRoomById(roomId);
            const player = room.players[characterId];
            const scene = room.scene;
            if(player) {
                PlayerActionManager.goToTarget(scene, player, updatedPlayer.targetPoint, roomId, self);
            }
        });

        return this;
    }


function Proposal ({ approvedIds, id, scheduled }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api } = useApi();
  const { allAccounts } = useAccounts();
  const { hasSudoKey, sudoKey } = useSudo();
  const [isQueried, toggleIsQueried] = useToggle();
  const proposal = useProposal(id, approvedIds, scheduled, isQueried);
  const endpoints = useParaEndpoints(id);

  const chainLink = useMemo(
    () => getChainLink(endpoints),
    [endpoints]
  );

  const cancelTx = useMemo(
    () => api.tx.sudo && hasSudoKey
      ? api.tx.sudo.sudo(api.tx.proposeParachain.cancelProposal(id))
      : allAccounts.some((a) => proposal.proposal?.proposer.eq(a))
        ? api.tx.proposeParachain.cancelProposal(id)
        : null,
    [api, allAccounts, hasSudoKey, id, proposal]
  );

  const approveTx = useMemo(
    () => api.tx.sudo && api.tx.sudo.sudo(api.tx.proposeParachain.approveProposal(id)),
    [api, id]
  );

  const initialHex = useMemo(
    () => proposal?.proposal && sliceHex(proposal.proposal.genesisHead, 8),
    [proposal]
  );

  const validationHex = useMemo(
    () => proposal?.proposal && sliceHex(proposal.proposal.validationCode, 8),
    [proposal]
  );

  return (

{formatNumber(id)}

        {(proposal.isApproved || proposal.isScheduled) && (
          <Badge
            color='green'
            icon={proposal.isScheduled ? 'clock' : 'check'}
          />
        )}


() => getChainLink(endpoints)


() => api.tx.sudo && hasSudoKey
      ? api.tx.sudo.sudo(api.tx.proposeParachain.cancelProposal(id))
      : allAccounts.some((a) => proposal.proposal?.proposer.eq(a))
        ? api.tx.proposeParachain.cancelProposal(id)
        : null


(a) => proposal.proposal?.proposer.eq(a)


() => api.tx.sudo && api.tx.sudo.sudo(api.tx.proposeParachain.approveProposal(id))


() => proposal?.proposal && sliceHex(proposal.proposal.genesisHead, 8)


() => proposal?.proposal && sliceHex(proposal.proposal.validationCode, 8)


(validatorId) => (
              <AddressMini
                key={validatorId.toString()}


interface Props {
  approvedIds: ParaId[];
  id: ParaId;
  scheduled: ScheduledProposals[];
}


formatNumber(id)


t<string>('Approve')


t<string>('Cancel')


export declare class GridOptionsWrapper {
    private static MIN_COL_WIDTH;
    static PROP_HEADER_HEIGHT: string;
    private gridOptions;
    private columnController;
    private eventService;
    private enterprise;
    private frameworkFactory;
    private propertyEventService;
    private fullWidthCellRenderer;
    private groupRowRenderer;
    private groupRowInnerRenderer;
    private domDataKey;
    private agWire(gridApi, columnApi);
    private destroy();
    init(): void;
    private setupCellRenderers();
    getDomDataKey(): string;
    getFullWidthCellRenderer(): {
        new (): ICellRenderer;
    } | ICellRendererFunc | string;
    getGroupRowRenderer(): {
        new (): ICellRenderer;
    } | ICellRendererFunc | string;
    getGroupRowInnerRenderer(): {
        new (): ICellRenderer;
    } | ICellRendererFunc | string;
    isEnterprise(): boolean;
    isRowSelection(): boolean;
    isRowDeselection(): boolean;
    isRowSelectionMulti(): boolean;
    getContext(): any;
    isPivotMode(): boolean;
    isRowModelPagination(): boolean;
    isRowModelVirtual(): boolean;
    isRowModelViewport(): boolean;
    isRowModelDefault(): boolean;
    isFullRowEdit(): boolean;
    isSuppressFocusAfterRefresh(): boolean;
    isShowToolPanel(): boolean;
    isToolPanelSuppressRowGroups(): boolean;
    isToolPanelSuppressValues(): boolean;
    isToolPanelSuppressPivots(): boolean;
    isToolPanelSuppressPivotMode(): boolean;
    isSuppressTouch(): boolean;
    isEnableCellChangeFlash(): boolean;
    isGroupSelectsChildren(): boolean;
    isGroupSelectsFiltered(): boolean;
    isGroupRemoveSingleChildren(): boolean;
    isGroupIncludeFooter(): boolean;
    isGroupSuppressBlankHeader(): boolean;
    isSuppressRowClickSelection(): boolean;
    isSuppressCellSelection(): boolean;
    isSuppressMultiSort(): boolean;
    isGroupSuppressAutoColumn(): boolean;
    isSuppressDragLeaveHidesColumns(): boolean;
    isForPrint(): boolean;
    isSuppressHorizontalScroll(): boolean;
    isSuppressLoadingOverlay(): boolean;
    isSuppressNoRowsOverlay(): boolean;
    isSuppressFieldDotNotation(): boolean;
    getFloatingTopRowData(): any[];
    getFloatingBottomRowData(): any[];
    isFunctionsPassive(): boolean;
    isSuppressRowHoverClass(): boolean;
    getQuickFilterText(): string;
    isUnSortIcon(): boolean;
    isSuppressMenuHide(): boolean;
    getRowStyle(): any;
    getRowClass(): any;
    getRowStyleFunc(): Function;
    getRowClassFunc(): Function;
    getDoesDataFlowerFunc(): (data: any) => boolean;
    getScrollbarWidth(): number;
    getIsFullWidthCellFunc(): (rowNode: RowNode) => boolean;
    getFullWidthCellRendererParams(): any;
    getBusinessKeyForNodeFunc(): (node: RowNode) => string;
    getHeaderCellRenderer(): any;
    getApi(): GridApi;
    getColumnApi(): ColumnApi;
    isEnableColResize(): boolean;
    isSingleClickEdit(): boolean;
    getGroupDefaultExpanded(): number;
    getAutoSizePadding(): number;
    getMaxConcurrentDatasourceRequests(): number;
    getMaxPagesInCache(): number;
    getPaginationOverflowSize(): number;
    getPaginationPageSize(): number;
    getPaginationInitialRowCount(): number;
    getRowData(): any[];
    isGroupUseEntireRow(): boolean;
    isEnableRtlSupport(): boolean;
    getGroupColumnDef(): ColDef;
    isGroupSuppressRow(): boolean;
    getRowGroupPanelShow(): string;
    getPivotPanelShow(): string;
    isAngularCompileRows(): boolean;
    isAngularCompileFilters(): boolean;
    isAngularCompileHeaders(): boolean;
    isDebug(): boolean;
    getColumnDefs(): (ColDef | ColGroupDef)[];
    getDatasource(): IDatasource;
    getViewportDatasource(): IViewportDatasource;
    isEnableSorting(): boolean;
    isEnableCellExpressions(): boolean;
    isSuppressMiddleClickScrolls(): boolean;
    isSuppressPreventDefaultOnMouseWheel(): boolean;
    isEnableServerSideSorting(): boolean;
    isSuppressColumnVirtualisation(): boolean;
    isSuppressContextMenu(): boolean;
    isSuppressCopyRowsToClipboard(): boolean;
    isEnableFilter(): boolean;
    isEnableServerSideFilter(): boolean;
    isSuppressScrollLag(): boolean;
    isSuppressMovableColumns(): boolean;
    isAnimateRows(): boolean;
    isSuppressColumnMoveAnimation(): boolean;
    isSuppressMenuColumnPanel(): boolean;
    isSuppressMenuFilterPanel(): boolean;
    isSuppressUseColIdForGroups(): boolean;
    isSuppressAggFuncInHeader(): boolean;
    isSuppressMenuMainPanel(): boolean;
    isEnableRangeSelection(): boolean;
    isRememberGroupStateWhenNewData(): boolean;
    getIcons(): any;
    getAggFuncs(): {
        [key: string]: IAggFunc;
    };
    getIsScrollLag(): () => boolean;
    getSortingOrder(): string[];
    getSlaveGrids(): GridOptions[];
    getGroupRowRendererParams(): any;
    getOverlayLoadingTemplate(): string;
    getOverlayNoRowsTemplate(): string;
    getCheckboxSelection(): (params: any) => boolean;
    isSuppressAutoSize(): boolean;
    isSuppressParentsInRowNodes(): boolean;
    isEnableStatusBar(): boolean;
    isFunctionsReadOnly(): boolean;
    getDefaultColDef(): ColDef;
    getDefaultColGroupDef(): ColGroupDef;
    getHeaderCellTemplate(): string;
    getHeaderCellTemplateFunc(): (params: any) => string | HTMLElement;
    getNodeChildDetailsFunc(): ((dataItem: any) => NodeChildDetails);
    getGroupRowAggNodesFunc(): (nodes: RowNode[]) => any;
    getContextMenuItemsFunc(): GetContextMenuItems;
    getMainMenuItemsFunc(): GetMainMenuItems;
    getRowNodeIdFunc(): GetRowNodeIdFunc;
    getProcessSecondaryColDefFunc(): (colDef: ColDef) => void;
    getProcessSecondaryColGroupDefFunc(): (colGroupDef: ColGroupDef) => void;
    getProcessCellForClipboardFunc(): (params: ProcessCellForExportParams) => any;
    getProcessCellFromClipboardFunc(): (params: ProcessCellForExportParams) => any;
    getViewportRowModelPageSize(): number;
    getViewportRowModelBufferSize(): number;
    setProperty(key: string, value: any): void;
    addEventListener(key: string, listener: Function): void;
    removeEventListener(key: string, listener: Function): void;
    executeProcessRowPostCreateFunc(params: ProcessRowParams): void;
    getHeaderHeight(): number;
    isExternalFilterPresent(): boolean;
    doesExternalFilterPass(node: RowNode): boolean;
    getLayoutInterval(): number;
    getMinColWidth(): number;
    getMaxColWidth(): number;
    getColWidth(): number;
    getRowBuffer(): number;
    private checkForDeprecated();
    getLocaleTextFunc(): Function;
    globalEventHandler(eventName: string, event?: any): void;
    getRowHeightAsNumber(): number;
    getRowHeightForNode(rowNode: RowNode): number;
}


private agWire(gridApi, columnApi);


private destroy();


private setupCellRenderers();


getDomDataKey(): string;


getFullWidthCellRenderer(): {
        new (): ICellRenderer;
    } | ICellRendererFunc | string;


getGroupRowRenderer(): {
        new (): ICellRenderer;
    } | ICellRendererFunc | string;


getGroupRowInnerRenderer(): {
        new (): ICellRenderer;
    } | ICellRendererFunc | string;


isEnterprise(): boolean;


isRowSelection(): boolean;


isRowDeselection(): boolean;


isRowSelectionMulti(): boolean;


getContext(): any;


isRowModelPagination(): boolean;


isRowModelVirtual(): boolean;


isRowModelViewport(): boolean;


isRowModelDefault(): boolean;


isFullRowEdit(): boolean;


isSuppressFocusAfterRefresh(): boolean;


isShowToolPanel(): boolean;


isToolPanelSuppressRowGroups(): boolean;


isToolPanelSuppressValues(): boolean;


isToolPanelSuppressPivots(): boolean;


isToolPanelSuppressPivotMode(): boolean;


isSuppressTouch(): boolean;


isEnableCellChangeFlash(): boolean;


isGroupSelectsChildren(): boolean;


isGroupSelectsFiltered(): boolean;


isGroupRemoveSingleChildren(): boolean;


isGroupIncludeFooter(): boolean;


isGroupSuppressBlankHeader(): boolean;


isSuppressRowClickSelection(): boolean;


isSuppressCellSelection(): boolean;


isSuppressMultiSort(): boolean;


isGroupSuppressAutoColumn(): boolean;


isSuppressDragLeaveHidesColumns(): boolean;


isForPrint(): boolean;


isSuppressHorizontalScroll(): boolean;


isSuppressLoadingOverlay(): boolean;


isSuppressNoRowsOverlay(): boolean;


isSuppressFieldDotNotation(): boolean;


getFloatingTopRowData(): any[];


getFloatingBottomRowData(): any[];


isFunctionsPassive(): boolean;


isSuppressRowHoverClass(): boolean;


getQuickFilterText(): string;


isUnSortIcon(): boolean;


isSuppressMenuHide(): boolean;


getRowStyle(): any;


getRowClass(): any;


getRowStyleFunc(): Function;


getRowClassFunc(): Function;


getDoesDataFlowerFunc(): (data: any) => boolean;


getScrollbarWidth(): number;


getIsFullWidthCellFunc(): (rowNode: RowNode) => boolean;


getFullWidthCellRendererParams(): any;


getBusinessKeyForNodeFunc(): (node: RowNode) => string;


getHeaderCellRenderer(): any;


getApi(): GridApi;


getColumnApi(): ColumnApi;


isEnableColResize(): boolean;


isSingleClickEdit(): boolean;


getGroupDefaultExpanded(): number;


getAutoSizePadding(): number;


getMaxConcurrentDatasourceRequests(): number;


getMaxPagesInCache(): number;


getPaginationOverflowSize(): number;


getPaginationPageSize(): number;


getPaginationInitialRowCount(): number;


getRowData(): any[];


isGroupUseEntireRow(): boolean;


isEnableRtlSupport(): boolean;


getGroupColumnDef(): ColDef;


isGroupSuppressRow(): boolean;


getRowGroupPanelShow(): string;


getPivotPanelShow(): string;


isAngularCompileRows(): boolean;


isAngularCompileFilters(): boolean;


isAngularCompileHeaders(): boolean;


isDebug(): boolean;


getColumnDefs(): (ColDef | ColGroupDef)[];


getDatasource(): IDatasource;


getViewportDatasource(): IViewportDatasource;


isEnableSorting(): boolean;


isEnableCellExpressions(): boolean;


isSuppressMiddleClickScrolls(): boolean;


isSuppressPreventDefaultOnMouseWheel(): boolean;


isEnableServerSideSorting(): boolean;


isSuppressColumnVirtualisation(): boolean;


isSuppressContextMenu(): boolean;


isSuppressCopyRowsToClipboard(): boolean;


isEnableFilter(): boolean;


isEnableServerSideFilter(): boolean;


isSuppressScrollLag(): boolean;


isSuppressMovableColumns(): boolean;


isAnimateRows(): boolean;


isSuppressColumnMoveAnimation(): boolean;


isSuppressMenuColumnPanel(): boolean;


isSuppressMenuFilterPanel(): boolean;


isSuppressUseColIdForGroups(): boolean;


isSuppressAggFuncInHeader(): boolean;


isSuppressMenuMainPanel(): boolean;


isEnableRangeSelection(): boolean;


isRememberGroupStateWhenNewData(): boolean;


getIcons(): any;


getAggFuncs(): {
        [key: string]: IAggFunc;
    };


getIsScrollLag(): () => boolean;


getSortingOrder(): string[];


getSlaveGrids(): GridOptions[];


getGroupRowRendererParams(): any;


getOverlayLoadingTemplate(): string;


getOverlayNoRowsTemplate(): string;


getCheckboxSelection(): (params: any) => boolean;


isSuppressAutoSize(): boolean;


isSuppressParentsInRowNodes(): boolean;


isEnableStatusBar(): boolean;


isFunctionsReadOnly(): boolean;


getDefaultColDef(): ColDef;


getDefaultColGroupDef(): ColGroupDef;


getHeaderCellTemplate(): string;


getHeaderCellTemplateFunc(): (params: any) => string | HTMLElement;


getNodeChildDetailsFunc(): ((dataItem: any) => NodeChildDetails);


getGroupRowAggNodesFunc(): (nodes: RowNode[]) => any;


getContextMenuItemsFunc(): GetContextMenuItems;


getMainMenuItemsFunc(): GetMainMenuItems;


getRowNodeIdFunc(): GetRowNodeIdFunc;


getProcessSecondaryColDefFunc(): (colDef: ColDef) => void;


getProcessSecondaryColGroupDefFunc(): (colGroupDef: ColGroupDef) => void;


getProcessCellForClipboardFunc(): (params: ProcessCellForExportParams) => any;


getProcessCellFromClipboardFunc(): (params: ProcessCellForExportParams) => any;


getViewportRowModelPageSize(): number;


getViewportRowModelBufferSize(): number;


setProperty(key: string, value: any): void;


addEventListener(key: string, listener: Function): void;


removeEventListener(key: string, listener: Function): void;


executeProcessRowPostCreateFunc(params: ProcessRowParams): void;


getHeaderHeight(): number;


isExternalFilterPresent(): boolean;


doesExternalFilterPass(node: RowNode): boolean;


getLayoutInterval(): number;


getMinColWidth(): number;


getMaxColWidth(): number;


getColWidth(): number;


getRowBuffer(): number;


private checkForDeprecated();


getLocaleTextFunc(): Function;


globalEventHandler(eventName: string, event?: any): void;


getRowHeightAsNumber(): number;


getRowHeightForNode(rowNode: RowNode): number;


export function getBaseUrl() {
    return document.getElementsByTagName('base')[0].href;
}


@NgModule({
    bootstrap: [ AppComponent ],
    imports: [
        BrowserModule,
        AppModuleShared
    ],
    providers: [
        { provide: 'BASE_URL', useFactory: getBaseUrl }
    ]
})
export class AppModule {
}


export interface SuperMemoItemProps {
  memo: SuperMemo;
}


export class MetaRepository implements IMetaRepository {
	private readonly dataSource: MetaBaseDataSource

	constructor (dataSource: MetaBaseDataSource) {
		this.dataSource = dataSource
	}

	async search (search: string) {
		const questionTransformer = new QuestionTransformer()
		const answerTransformer = new AnswerTransformer()
		const userTransformer = new UserTransformer()
		const models = await this.dataSource.search(search)
		return {
			questions: {
				...models.questions,
				results: models.questions.results.map(questionTransformer.fromJSON)
			},
			answers: {
				...models.answers,
				results: models.answers.results.map(answerTransformer.fromJSON)
			},
			users: {
				...models.users,
				results: models.users.results.map(userTransformer.fromJSON)
			}
		}
	}

	async buyCoinsWithStripe (data: { amount: number; currency: string; gold: number; bronze: number }) {
		return await this.dataSource.buyCoinsWithStripe(data)
	}

	async verifyStripePayment (data: { intentId: string }) {
		return await this.dataSource.verifyStripePayment(data)
	}
}


async search (search: string) {
		const questionTransformer = new QuestionTransformer()
		const answerTransformer = new AnswerTransformer()
		const userTransformer = new UserTransformer()
		const models = await this.dataSource.search(search)
		return {
			questions: {
				...models.questions,
				results: models.questions.results.map(questionTransformer.fromJSON)
			},
			answers: {
				...models.answers,
				results: models.answers.results.map(answerTransformer.fromJSON)
			},
			users: {
				...models.users,
				results: models.users.results.map(userTransformer.fromJSON)
			}
		}
	}


async buyCoinsWithStripe (data: { amount: number; currency: string; gold: number; bronze: number }) {
		return await this.dataSource.buyCoinsWithStripe(data)
	}


async verifyStripePayment (data: { intentId: string }) {
		return await this.dataSource.verifyStripePayment(data)
	}


interface Window {
        env: any
    }


type EnvType = {
    REACT_APP_BASE_API_URL: string
}


(isAuthenticated) => console.log('app authenticated', isAuthenticated)


@Component({
    selector: 'app-component',
    templateUrl: 'app.component.html',
    styleUrls: ['./app.component.scss'],
})

export class AppComponent implements OnInit {

    title = '';
    userDataChanged$: Observable<OidcClientNotification<any>>;
    userData$: Observable<any>;
    isAuthenticated$: Observable<boolean | ConfigAuthenticatedResult[]>;
    checkSessionChanged$: Observable<boolean>;
    checkSessionChanged: any;

    constructor(
        public oidcSecurityService: OidcSecurityService
    ) {
        console.log('AppComponent STARTING');
    }

    ngOnInit() {
        this.userData$ = this.oidcSecurityService.userData$;
        this.isAuthenticated$ = this.oidcSecurityService.isAuthenticated$;
        this.checkSessionChanged$ = this.oidcSecurityService.checkSessionChanged$;

        this.oidcSecurityService.checkAuth().subscribe((isAuthenticated) => console.log('app authenticated', isAuthenticated));
    }

    login() {
        console.log('start login');
        this.oidcSecurityService.authorize();
    }

    refreshSession() {
        console.log('start refreshSession');
        this.oidcSecurityService.authorize();
    }

    logout() {
        console.log('start logoff');
        this.oidcSecurityService.logoff();
    }

}


ngOnInit() {
        this.userData$ = this.oidcSecurityService.userData$;
        this.isAuthenticated$ = this.oidcSecurityService.isAuthenticated$;
        this.checkSessionChanged$ = this.oidcSecurityService.checkSessionChanged$;

        this.oidcSecurityService.checkAuth().subscribe((isAuthenticated) => console.log('app authenticated', isAuthenticated));
    }


login() {
        console.log('start login');
        this.oidcSecurityService.authorize();
    }


refreshSession() {
        console.log('start refreshSession');
        this.oidcSecurityService.authorize();
    }


logout() {
        console.log('start logoff');
        this.oidcSecurityService.logoff();
    }


class SpeedMonitor extends React.PureComponent<Props> {
  constructor(props: Props) {
    super(props);
    this.selectColor = this.selectColor.bind(this);
    this.state = {};
  }

  private showLocation(location?: GeolocationResponse) {
    if (!location) {
      return;
    }

    return (
      <View style={{ flex: 1 }}


interface Props {
  whereAmI: () => void;
  currentLocation?: GeolocationResponse;
  unit: SpeedUnit;
  selectUnit: (newUnit: SpeedUnit) => void;
  selectSpeedLimit: (newLimit: string) => void;
  speedLimit: string;
  speedLimits: string[];
  currentSpeed: number;
  toggleSpeedMonitor: () => void;
  isMonitoringSpeed: boolean;
}


private showLocation(location?: GeolocationResponse) {
    if (!location) {
      return;
    }

    return (
      <View style={{ flex: 1 }}


strings('speedMonitor.lat')


strings('speedMonitor.lon')


strings('speedMonitor.alt')


strings('speedMonitor.timestamp')


strings('speedMonitor.selectLimit')


strings('speedMonitor.selectUnit')


strings('speedMonitor.getLocationButton')


function cauldronApi({
  cauldronDocument,
  storePath,
}: {
  cauldronDocument?: any
  storePath?: string
} = {}) {
  cauldronDocument = cauldronDocument || getCauldronFixtureClone()
  documentStore = new InMemoryDocumentStore(cauldronDocument)
  fileStore = new EphemeralFileStore({ storePath })

  return new CauldronApi(documentStore, fileStore)
}


function getCauldronFixtureClone() {
  return JSON.parse(JSON.stringify(fixtures.defaultCauldron))
}


() => {
    sandbox.restore()
  }


() => {
    it('should properly upgrade a cauldron [schema 0.0.0 => 3.0.0]', async () => {
      sandbox.stub(utils, 'isGitBranch').resolves(true)
      const fixture = JSON.parse(
        fs
          .readFileSync(path.join(__dirname, 'fixtures/cauldron-0.0.0.json'))
          .toString()
      )
      const api = cauldronApi({ cauldronDocument: fixture })
      await api.upgradeCauldronSchema()
      const expectedCauldronDoc = JSON.parse(
        fs
          .readFileSync(path.join(__dirname, 'fixtures/cauldron-3.0.0.json'))
          .toString()
      )
      const cauldronDoc = await api.getCauldron()
      expect(cauldronDoc).eql(expectedCauldronDoc)
    })
  }


async () => {
      sandbox.stub(utils, 'isGitBranch').resolves(true)
      const fixture = JSON.parse(
        fs
          .readFileSync(path.join(__dirname, 'fixtures/cauldron-0.0.0.json'))
          .toString()
      )
      const api = cauldronApi({ cauldronDocument: fixture })
      await api.upgradeCauldronSchema()
      const expectedCauldronDoc = JSON.parse(
        fs
          .readFileSync(path.join(__dirname, 'fixtures/cauldron-3.0.0.json'))
          .toString()
      )
      const cauldronDoc = await api.getCauldron()
      expect(cauldronDoc).eql(expectedCauldronDoc)
    }


() => {
    it('should call commit on the document store', async () => {
      const api = cauldronApi()
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.commit('commit-message')
      sinon.assert.calledOnce(commitStub)
    })

    it('should call commit with the proper commit message', async () => {
      const api = cauldronApi()
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.commit('commit-message')
      sinon.assert.calledWith(commitStub, 'commit-message')
    })
  }


async () => {
      const api = cauldronApi()
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.commit('commit-message')
      sinon.assert.calledOnce(commitStub)
    }


async () => {
      const api = cauldronApi()
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.commit('commit-message')
      sinon.assert.calledWith(commitStub, 'commit-message')
    }


() => {
    it('should return the Cauldron document', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const cauldron = await cauldronApi().getCauldron()
      expect(cauldron).eql(tmpFixture)
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const cauldron = await cauldronApi().getCauldron()
      expect(cauldron).eql(tmpFixture)
    }


() => {
    it('should return the Cauldron schema version', async () => {
      const schemaVersion = await cauldronApi().getCauldronSchemaVersion()
      expect(schemaVersion).eql('3.0.0')
    })

    it('should return 0.0.0 if schemaVersion property is missing', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      delete tmpFixture.schemaVersion
      const schemaVersion = await cauldronApi({
        cauldronDocument: tmpFixture,
      }).getCauldronSchemaVersion()
      expect(schemaVersion).eql('0.0.0')
    })
  }


async () => {
      const schemaVersion = await cauldronApi().getCauldronSchemaVersion()
      expect(schemaVersion).eql('3.0.0')
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      delete tmpFixture.schemaVersion
      const schemaVersion = await cauldronApi({
        cauldronDocument: tmpFixture,
      }).getCauldronSchemaVersion()
      expect(schemaVersion).eql('0.0.0')
    }


() => {
    it('should call beginTransaction on the document store', async () => {
      const api = cauldronApi()
      const beginTransactionStub = sandbox.stub(
        documentStore,
        'beginTransaction'
      )
      await api.beginTransaction()
      sinon.assert.calledOnce(beginTransactionStub)
    })

    it('should call beginTransaction on the file store', async () => {
      const api = cauldronApi()
      const beginTransactionStub = sandbox.stub(fileStore, 'beginTransaction')
      await api.beginTransaction()
      sinon.assert.calledOnce(beginTransactionStub)
    })
  }


async () => {
      const api = cauldronApi()
      const beginTransactionStub = sandbox.stub(
        documentStore,
        'beginTransaction'
      )
      await api.beginTransaction()
      sinon.assert.calledOnce(beginTransactionStub)
    }


async () => {
      const api = cauldronApi()
      const beginTransactionStub = sandbox.stub(fileStore, 'beginTransaction')
      await api.beginTransaction()
      sinon.assert.calledOnce(beginTransactionStub)
    }


() => {
    it('should call discardTransaction on the document store', async () => {
      const api = cauldronApi()
      const discardTransactionStub = sandbox.stub(
        documentStore,
        'discardTransaction'
      )
      await api.discardTransaction()
      sinon.assert.calledOnce(discardTransactionStub)
    })

    it('should call discardTransaction on the file store', async () => {
      const api = cauldronApi()
      const discardTransactionStub = sandbox.stub(
        fileStore,
        'discardTransaction'
      )
      await api.discardTransaction()
      sinon.assert.calledOnce(discardTransactionStub)
    })
  }


async () => {
      const api = cauldronApi()
      const discardTransactionStub = sandbox.stub(
        documentStore,
        'discardTransaction'
      )
      await api.discardTransaction()
      sinon.assert.calledOnce(discardTransactionStub)
    }


async () => {
      const api = cauldronApi()
      const discardTransactionStub = sandbox.stub(
        fileStore,
        'discardTransaction'
      )
      await api.discardTransaction()
      sinon.assert.calledOnce(discardTransactionStub)
    }


() => {
    it('should call commitTransaction on the document store', async () => {
      const api = cauldronApi()
      const commitTransactionStub = sandbox.stub(
        documentStore,
        'commitTransaction'
      )
      await api.commitTransaction('commit-message')
      sinon.assert.calledOnce(commitTransactionStub)
    })

    it('should call commitTransaction on the document store with the right commit message', async () => {
      const api = cauldronApi()
      const commitTransactionStub = sandbox.stub(
        documentStore,
        'commitTransaction'
      )
      await api.commitTransaction('commit-message')
      sinon.assert.calledWith(commitTransactionStub, 'commit-message')
    })

    it('should call commitTransaction on the file store ', async () => {
      const api = cauldronApi()
      const commitTransactionStub = sandbox.stub(fileStore, 'commitTransaction')
      await api.commitTransaction('commit-message')
      sinon.assert.calledOnce(commitTransactionStub)
    })

    it('should call commitTransaction on the file store with the right commit message', async () => {
      const api = cauldronApi()
      const commitTransactionStub = sandbox.stub(fileStore, 'commitTransaction')
      await api.commitTransaction('commit-message')
      sinon.assert.calledWith(commitTransactionStub, 'commit-message')
    })
  }


async () => {
      const api = cauldronApi()
      const commitTransactionStub = sandbox.stub(
        documentStore,
        'commitTransaction'
      )
      await api.commitTransaction('commit-message')
      sinon.assert.calledOnce(commitTransactionStub)
    }


async () => {
      const api = cauldronApi()
      const commitTransactionStub = sandbox.stub(
        documentStore,
        'commitTransaction'
      )
      await api.commitTransaction('commit-message')
      sinon.assert.calledWith(commitTransactionStub, 'commit-message')
    }


async () => {
      const api = cauldronApi()
      const commitTransactionStub = sandbox.stub(fileStore, 'commitTransaction')
      await api.commitTransaction('commit-message')
      sinon.assert.calledOnce(commitTransactionStub)
    }


async () => {
      const api = cauldronApi()
      const commitTransactionStub = sandbox.stub(fileStore, 'commitTransaction')
      await api.commitTransaction('commit-message')
      sinon.assert.calledWith(commitTransactionStub, 'commit-message')
    }


() => {
    it('should return the native applications', async () => {
      const nativeApps = await cauldronApi().getNativeApplications()
      expect(nativeApps).eql(fixtures.defaultCauldron.nativeApps)
    })
  }


async () => {
      const nativeApps = await cauldronApi().getNativeApplications()
      expect(nativeApps).eql(fixtures.defaultCauldron.nativeApps)
    }


() => {
    it('should return the native applications array', async () => {
      const nativeApp = await cauldronApi().getNativeApplication(
        'test'.toAppDescriptor()
      )
      const nativeAppsObj = jp.query(
        fixtures.defaultCauldron,
        '$.nativeApps[?(@.name=="test")]'
      )[0]
      expect(nativeApp).eql(nativeAppsObj)
    })

    it('should throw if the application name is not found', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getNativeApplication,
          api,
          'unexisting'.toAppDescriptor()
        )
      )
    })
  }


async () => {
      const nativeApp = await cauldronApi().getNativeApplication(
        'test'.toAppDescriptor()
      )
      const nativeAppsObj = jp.query(
        fixtures.defaultCauldron,
        '$.nativeApps[?(@.name=="test")]'
      )[0]
      expect(nativeApp).eql(nativeAppsObj)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getNativeApplication,
          api,
          'unexisting'.toAppDescriptor()
        )
      )
    }


() => {
    it('should return the platforms array', async () => {
      const platforms = await cauldronApi().getPlatforms(
        'test'.toAppDescriptor()
      )
      expect(platforms)
        .to.be.an('array')
        .of.length(1)
    })

    it('should throw if the application name is not found', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(api.getPlatforms, api, 'unexisting'.toAppDescriptor())
      )
    })
  }


async () => {
      const platforms = await cauldronApi().getPlatforms(
        'test'.toAppDescriptor()
      )
      expect(platforms)
        .to.be.an('array')
        .of.length(1)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(api.getPlatforms, api, 'unexisting'.toAppDescriptor())
      )
    }


() => {
    it('should return the platform object given its name', async () => {
      const platformObj = await cauldronApi().getPlatform(
        AppPlatformDescriptor.fromString('test:android')
      )
      const platform = jp.query(
        fixtures.defaultCauldron,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")]'
      )[0]
      expect(platform).eql(platformObj)
    })

    it('should throw if the platform is not found', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getPlatform,
          api,
          AppPlatformDescriptor.fromString('test:ios')
        )
      )
    })

    it('should throw if the native application is not found', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getPlatform,
          api,
          AppPlatformDescriptor.fromString('unexisting:android')
        )
      )
    })
  }


async () => {
      const platformObj = await cauldronApi().getPlatform(
        AppPlatformDescriptor.fromString('test:android')
      )
      const platform = jp.query(
        fixtures.defaultCauldron,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")]'
      )[0]
      expect(platform).eql(platformObj)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getPlatform,
          api,
          AppPlatformDescriptor.fromString('test:ios')
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getPlatform,
          api,
          AppPlatformDescriptor.fromString('unexisting:android')
        )
      )
    }


() => {
    it('should return the versions array', async () => {
      const versionsArr = await cauldronApi().getVersions(
        AppPlatformDescriptor.fromString('test:android')
      )
      const versions = jp.query(
        fixtures.defaultCauldron,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions'
      )[0]
      expect(versionsArr).eql(versions)
    })

    it('should throw if the native application platform does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getVersions,
          api,
          AppPlatformDescriptor.fromString('test:ios')
        )
      )
    })

    it('should throw if the native application name does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getVersions,
          api,
          AppPlatformDescriptor.fromString('unexisting:android')
        )
      )
    })
  }


async () => {
      const versionsArr = await cauldronApi().getVersions(
        AppPlatformDescriptor.fromString('test:android')
      )
      const versions = jp.query(
        fixtures.defaultCauldron,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions'
      )[0]
      expect(versionsArr).eql(versions)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getVersions,
          api,
          AppPlatformDescriptor.fromString('test:ios')
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getVersions,
          api,
          AppPlatformDescriptor.fromString('unexisting:android')
        )
      )
    }


() => {
    it('should return the version object', async () => {
      const versionObj = await cauldronApi().getVersion(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      const version = jp.query(
        fixtures.defaultCauldron,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")]'
      )[0]
      expect(versionObj).eql(version)
    })

    it('should throw if the native application version does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getVersion,
          api,
          AppVersionDescriptor.fromString('test:android:0.1.0')
        )
      )
    })

    it('should throw if the native application platform does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getVersion,
          api,
          AppVersionDescriptor.fromString('test:ios:0.1.0')
        )
      )
    })

    it('should throw if the native application name does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getVersion,
          api,
          AppVersionDescriptor.fromString('unexisting:android:17.7.0')
        )
      )
    })
  }


async () => {
      const versionObj = await cauldronApi().getVersion(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      const version = jp.query(
        fixtures.defaultCauldron,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")]'
      )[0]
      expect(versionObj).eql(version)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getVersion,
          api,
          AppVersionDescriptor.fromString('test:android:0.1.0')
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getVersion,
          api,
          AppVersionDescriptor.fromString('test:ios:0.1.0')
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getVersion,
          api,
          AppVersionDescriptor.fromString('unexisting:android:17.7.0')
        )
      )
    }


() => {
    it('should return the code push Production entries', async () => {
      const entries = await cauldronApi().getCodePushEntries(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'Production'
      )
      expect(entries)
        .to.be.an('array')
        .of.length(2)
    })

    it('should return the code push QA entries', async () => {
      const entries = await cauldronApi().getCodePushEntries(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'QA'
      )
      expect(entries)
        .to.be.an('array')
        .of.length(1)
    })

    it('should throw if native application version is not found', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getCodePushEntries,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0'),
          'QA'
        )
      )
    })

    it('should throw if native application platform does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getCodePushEntries,
          api,
          AppVersionDescriptor.fromString('test:ios:1.0.0'),
          'QA'
        )
      )
    })

    it('should throw if native application name does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getCodePushEntries,
          api,
          AppVersionDescriptor.fromString('unexisting:android:17.7.0'),
          'QA'
        )
      )
    })
  }


async () => {
      const entries = await cauldronApi().getCodePushEntries(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'Production'
      )
      expect(entries)
        .to.be.an('array')
        .of.length(2)
    }


async () => {
      const entries = await cauldronApi().getCodePushEntries(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'QA'
      )
      expect(entries)
        .to.be.an('array')
        .of.length(1)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getCodePushEntries,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0'),
          'QA'
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getCodePushEntries,
          api,
          AppVersionDescriptor.fromString('test:ios:1.0.0'),
          'QA'
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getCodePushEntries,
          api,
          AppVersionDescriptor.fromString('unexisting:android:17.7.0'),
          'QA'
        )
      )
    }


() => {
    it('should set the code push entries', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).setCodePushEntries(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'QA',
        [codePushNewEntryFixture]
      )
      const codePushEntries = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")].codePush["QA"]'
      )[0]
      expect(codePushEntries).eql([codePushNewEntryFixture])
    })

    it('should throw if the native application version does not exists', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.setCodePushEntries,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0'),
          'QA',
          [codePushNewEntryFixture]
        )
      )
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).setCodePushEntries(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'QA',
        [codePushNewEntryFixture]
      )
      const codePushEntries = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")].codePush["QA"]'
      )[0]
      expect(codePushEntries).eql([codePushNewEntryFixture])
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.setCodePushEntries,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0'),
          'QA',
          [codePushNewEntryFixture]
        )
      )
    }


() => {
    it('should return the MiniApps array of a native application version Container', async () => {
      const containerMiniApps = await cauldronApi().getContainerMiniApps(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      expect(containerMiniApps)
        .to.be.an('array')
        .of.length(2)
    })

    it('should throw if native application version does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerMiniApps,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0')
        )
      )
    })

    it('should throw if native application platform does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerMiniApps,
          api,
          AppVersionDescriptor.fromString('test:ios:17.7.0')
        )
      )
    })

    it('should throw if native application name does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerMiniApps,
          api,
          AppVersionDescriptor.fromString('unexisting:android:17.7.0')
        )
      )
    })
  }


async () => {
      const containerMiniApps = await cauldronApi().getContainerMiniApps(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      expect(containerMiniApps)
        .to.be.an('array')
        .of.length(2)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerMiniApps,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0')
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerMiniApps,
          api,
          AppVersionDescriptor.fromString('test:ios:17.7.0')
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerMiniApps,
          api,
          AppVersionDescriptor.fromString('unexisting:android:17.7.0')
        )
      )
    }


() => {
    it('should return the native dependencies of a native application version Container', async () => {
      const containerDependencies = await cauldronApi().getNativeDependencies(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      expect(containerDependencies)
        .to.be.an('array')
        .of.length(4)
    })

    it('should throw if native application version does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getNativeDependencies,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0')
        )
      )
    })

    it('should throw if native application platform does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getNativeDependencies,
          api,
          AppVersionDescriptor.fromString('test:ios:17.7.0')
        )
      )
    })

    it('should throw if native application name does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getNativeDependencies,
          api,
          AppVersionDescriptor.fromString('unexisting:android:17.7.0')
        )
      )
    })
  }


async () => {
      const containerDependencies = await cauldronApi().getNativeDependencies(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      expect(containerDependencies)
        .to.be.an('array')
        .of.length(4)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getNativeDependencies,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0')
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getNativeDependencies,
          api,
          AppVersionDescriptor.fromString('test:ios:17.7.0')
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getNativeDependencies,
          api,
          AppVersionDescriptor.fromString('unexisting:android:17.7.0')
        )
      )
    }


() => {
    it('should throw an error if the native application version does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerJsApiImpls,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0')
        )
      )
    })

    it('should return the JavaScript API implementations package paths', async () => {
      const result = await cauldronApi().getContainerJsApiImpls(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      expect(result)
        .to.be.an('array')
        .of.length(1)
      expect(result[0]).eql('react-native-my-api-impl@1.0.0')
    })
  }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerJsApiImpls,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0')
        )
      )
    }


async () => {
      const result = await cauldronApi().getContainerJsApiImpls(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      expect(result)
        .to.be.an('array')
        .of.length(1)
      expect(result[0]).eql('react-native-my-api-impl@1.0.0')
    }


() => {
    it('should throw an error if the native application version does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerJsApiImpl,
          api,
          AppVersionDescriptor.fromString('test:android:17.10.0'),
          'react-native-my-api-impl'
        )
      )
    })

    it('should return the JavaScript API implementation package path [1]', async () => {
      const result = await cauldronApi().getContainerJsApiImpl(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'react-native-my-api-impl'
      )
      expect(result).eql('react-native-my-api-impl@1.0.0')
    })

    it('should return the JavaScript API implementation package path [2]', async () => {
      const result = await cauldronApi().getContainerJsApiImpl(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'react-native-my-api-impl@1.0.0'
      )
      expect(result).eql('react-native-my-api-impl@1.0.0')
    })
  }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerJsApiImpl,
          api,
          AppVersionDescriptor.fromString('test:android:17.10.0'),
          'react-native-my-api-impl'
        )
      )
    }


async () => {
      const result = await cauldronApi().getContainerJsApiImpl(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'react-native-my-api-impl'
      )
      expect(result).eql('react-native-my-api-impl@1.0.0')
    }


async () => {
      const result = await cauldronApi().getContainerJsApiImpl(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'react-native-my-api-impl@1.0.0'
      )
      expect(result).eql('react-native-my-api-impl@1.0.0')
    }


() => {
    it('should return the native dependency string if no version is provided', async () => {
      const dependency = await cauldronApi().getContainerNativeDependency(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'react-native-electrode-bridge'
      )
      expect(dependency).eql('react-native-electrode-bridge@1.4.9')
    })

    it('should return the native dependency string if version is provided', async () => {
      const dependency = await cauldronApi().getContainerNativeDependency(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'react-native-electrode-bridge@1.4.9'
      )
      expect(dependency).eql('react-native-electrode-bridge@1.4.9')
    })

    it('should throw if incorrect version is provided', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerNativeDependency,
          api,
          AppVersionDescriptor.fromString('test:android:17.7.0'),
          'react-native-electrode-bridge@0.1.0'
        )
      )
    })

    it('should throw if dependency does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerNativeDependency,
          api,
          AppVersionDescriptor.fromString('test:android:17.7.0'),
          'unexisting'
        )
      )
    })

    it('should throw if native application version does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerNativeDependency,
          api,
          AppVersionDescriptor.fromString('test:android:0.1.0'),
          'react-native-electrode-bridge'
        )
      )
    })

    it('should throw if native application platform does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerNativeDependency,
          api,
          AppVersionDescriptor.fromString('test:ios:17.7.0'),
          'react-native-electrode-bridge'
        )
      )
    })

    it('should throw if native application name does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerNativeDependency,
          api,
          AppVersionDescriptor.fromString('unexisting:android:17.7.0'),
          'react-native-electrode-bridge'
        )
      )
    })
  }


async () => {
      const dependency = await cauldronApi().getContainerNativeDependency(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'react-native-electrode-bridge'
      )
      expect(dependency).eql('react-native-electrode-bridge@1.4.9')
    }


async () => {
      const dependency = await cauldronApi().getContainerNativeDependency(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'react-native-electrode-bridge@1.4.9'
      )
      expect(dependency).eql('react-native-electrode-bridge@1.4.9')
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerNativeDependency,
          api,
          AppVersionDescriptor.fromString('test:android:17.7.0'),
          'react-native-electrode-bridge@0.1.0'
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerNativeDependency,
          api,
          AppVersionDescriptor.fromString('test:android:17.7.0'),
          'unexisting'
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerNativeDependency,
          api,
          AppVersionDescriptor.fromString('test:android:0.1.0'),
          'react-native-electrode-bridge'
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerNativeDependency,
          api,
          AppVersionDescriptor.fromString('test:ios:17.7.0'),
          'react-native-electrode-bridge'
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getContainerNativeDependency,
          api,
          AppVersionDescriptor.fromString('unexisting:android:17.7.0'),
          'react-native-electrode-bridge'
        )
      )
    }


() => {
    it('[get application version config] should return the native application version config', async () => {
      const configObj = await cauldronApi({
        storePath: fixtureFileStorePath,
      }).getConfig(AppVersionDescriptor.fromString('test:android:17.7.0'))
      const config = fs.readFileSync(
        path.join(fixtureFileStorePath, 'config/test-android-17.7.0.json')
      )
      expect(configObj).eql(JSON.parse(config.toString()))
    })

    it('[get application version config] should throw if the native application version does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getConfig,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0')
        )
      )
    })

    it('[get application platform config] should return the native application platform config', async () => {
      const configObj = await cauldronApi({
        storePath: fixtureFileStorePath,
      }).getConfig(AppPlatformDescriptor.fromString('test:android'))
      const config = fs.readFileSync(
        path.join(fixtureFileStorePath, 'config/test-android.json')
      )
      expect(configObj).eql(JSON.parse(config.toString()))
    })

    it('[get application platform config] should throw if the native application platform does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getConfig,
          api,
          AppPlatformDescriptor.fromString('test:ios')
        )
      )
    })

    it('[get application config] should return the native application name config', async () => {
      const configObj = await cauldronApi({
        storePath: fixtureFileStorePath,
      }).getConfig(AppNameDescriptor.fromString('test'))
      const config = fs.readFileSync(
        path.join(fixtureFileStorePath, 'config/test.json')
      )
      expect(configObj).eql(JSON.parse(config.toString()))
    })

    it('[get application config] should throw if native application does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getConfig,
          api,
          AppNameDescriptor.fromString('unexisting')
        )
      )
    })
  }


async () => {
      const configObj = await cauldronApi({
        storePath: fixtureFileStorePath,
      }).getConfig(AppVersionDescriptor.fromString('test:android:17.7.0'))
      const config = fs.readFileSync(
        path.join(fixtureFileStorePath, 'config/test-android-17.7.0.json')
      )
      expect(configObj).eql(JSON.parse(config.toString()))
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getConfig,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0')
        )
      )
    }


async () => {
      const configObj = await cauldronApi({
        storePath: fixtureFileStorePath,
      }).getConfig(AppPlatformDescriptor.fromString('test:android'))
      const config = fs.readFileSync(
        path.join(fixtureFileStorePath, 'config/test-android.json')
      )
      expect(configObj).eql(JSON.parse(config.toString()))
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getConfig,
          api,
          AppPlatformDescriptor.fromString('test:ios')
        )
      )
    }


async () => {
      const configObj = await cauldronApi({
        storePath: fixtureFileStorePath,
      }).getConfig(AppNameDescriptor.fromString('test'))
      const config = fs.readFileSync(
        path.join(fixtureFileStorePath, 'config/test.json')
      )
      expect(configObj).eql(JSON.parse(config.toString()))
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.getConfig,
          api,
          AppNameDescriptor.fromString('unexisting')
        )
      )
    }


() => {
    it('should empty the Cauldron', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).clearCauldron()
      expect(tmpFixture.nativeApps).empty
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).clearCauldron()
      expect(tmpFixture.nativeApps).empty
    }


() => {
    it('should add a native application entry', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).addDescriptor(
        AppNameDescriptor.fromString('newapp')
      )
      const app = jp.query(tmpFixture, '$.nativeApps[?(@.name=="newapp")]')[0]
      expect(app).not.undefined
    })

    it('should add a native application and platform entry', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).addDescriptor(
        AppPlatformDescriptor.fromString('newapp:android')
      )
      const platform = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="newapp")].platforms[?(@.name=="android")]'
      )[0]
      expect(platform).not.undefined
    })

    it('should add a native application and platform and version entry', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).addDescriptor(
        AppVersionDescriptor.fromString('newapp:android:1.0.0')
      )
      const platform = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="newapp")].platforms[?(@.name=="android")].versions[?(@.name=="1.0.0")]'
      )[0]
      expect(platform).not.undefined
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).addDescriptor(
        AppNameDescriptor.fromString('newapp')
      )
      const app = jp.query(tmpFixture, '$.nativeApps[?(@.name=="newapp")]')[0]
      expect(app).not.undefined
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).addDescriptor(
        AppPlatformDescriptor.fromString('newapp:android')
      )
      const platform = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="newapp")].platforms[?(@.name=="android")]'
      )[0]
      expect(platform).not.undefined
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).addDescriptor(
        AppVersionDescriptor.fromString('newapp:android:1.0.0')
      )
      const platform = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="newapp")].platforms[?(@.name=="android")].versions[?(@.name=="1.0.0")]'
      )[0]
      expect(platform).not.undefined
    }


() => {
    it('should remove a top level native app', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).removeDescriptor(
        AppNameDescriptor.fromString('test')
      )
      const result = jp.query(tmpFixture, '$.nativeApps[?(@.name=="test")]')[0]
      expect(result).undefined
    })

    it('should remove a native application platform', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).removeDescriptor(
        AppPlatformDescriptor.fromString('test:android')
      )
      const result = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")]'
      )[0]
      expect(result).undefined
    })

    it('should remove a native application version', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).removeDescriptor(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      const result = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")]'
      )[0]
      expect(result).undefined
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).removeDescriptor(
        AppNameDescriptor.fromString('test')
      )
      const result = jp.query(tmpFixture, '$.nativeApps[?(@.name=="test")]')[0]
      expect(result).undefined
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).removeDescriptor(
        AppPlatformDescriptor.fromString('test:android')
      )
      const result = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")]'
      )[0]
      expect(result).undefined
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).removeDescriptor(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      const result = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")]'
      )[0]
      expect(result).undefined
    }


() => {
    it('should create the native application object', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).createNativeApplication({ name: 'newapp' })
      const app = jp.query(tmpFixture, '$.nativeApps[?(@.name=="newapp")]')[0]
      expect(app).not.undefined
    })

    it('should commit the document store', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.createNativeApplication({ name: 'newapp' })
      sinon.assert.calledOnce(commitStub)
    })

    it('should throw if the native application name already exists', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      assert(
        await doesThrow(api.createNativeApplication, api, { name: 'test' })
      )
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).createNativeApplication({ name: 'newapp' })
      const app = jp.query(tmpFixture, '$.nativeApps[?(@.name=="newapp")]')[0]
      expect(app).not.undefined
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.createNativeApplication({ name: 'newapp' })
      sinon.assert.calledOnce(commitStub)
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      assert(
        await doesThrow(api.createNativeApplication, api, { name: 'test' })
      )
    }


() => {
    it('should remove the native application given its name', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).removeNativeApplication(AppNameDescriptor.fromString('test'))
      const nativeApp = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")]'
      )[0]
      expect(nativeApp).undefined
    })

    it('should commit the document store', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.removeNativeApplication(AppNameDescriptor.fromString('test'))
      sinon.assert.calledOnce(commitStub)
    })

    it('should throw if the application name does not exists', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removeNativeApplication,
          api,
          AppNameDescriptor.fromString('unexisting')
        )
      )
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).removeNativeApplication(AppNameDescriptor.fromString('test'))
      const nativeApp = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")]'
      )[0]
      expect(nativeApp).undefined
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.removeNativeApplication(AppNameDescriptor.fromString('test'))
      sinon.assert.calledOnce(commitStub)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removeNativeApplication,
          api,
          AppNameDescriptor.fromString('unexisting')
        )
      )
    }


() => {
    it('should create the platform object', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).createPlatform(AppNameDescriptor.fromString('test'), { name: 'ios' })
      const platform = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="ios")]'
      )[0]
      expect(platform).not.undefined
    })

    it('should commit the document store', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.createPlatform(AppNameDescriptor.fromString('test'), {
        name: 'ios',
      })
      sinon.assert.calledOnce(commitStub)
    })

    it('should throw if the application platform already exists', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.createPlatform,
          api,
          AppNameDescriptor.fromString('test'),
          { name: 'android' }
        )
      )
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).createPlatform(AppNameDescriptor.fromString('test'), { name: 'ios' })
      const platform = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="ios")]'
      )[0]
      expect(platform).not.undefined
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.createPlatform(AppNameDescriptor.fromString('test'), {
        name: 'ios',
      })
      sinon.assert.calledOnce(commitStub)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.createPlatform,
          api,
          AppNameDescriptor.fromString('test'),
          { name: 'android' }
        )
      )
    }


() => {
    it('should remove the native application platform given its name', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).removePlatform(
        AppPlatformDescriptor.fromString('test:android')
      )
      const platform = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")]'
      )[0]
      expect(platform).undefined
    })

    it('should commit the document store', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.removePlatform(AppPlatformDescriptor.fromString('test:android'))
      sinon.assert.calledOnce(commitStub)
    })

    it('should throw if the application name does not exists', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removePlatform,
          api,
          AppPlatformDescriptor.fromString('unexisting:android')
        )
      )
    })

    it('should throw if the application platform does not exists', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removePlatform,
          api,
          AppPlatformDescriptor.fromString('test:ios')
        )
      )
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).removePlatform(
        AppPlatformDescriptor.fromString('test:android')
      )
      const platform = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")]'
      )[0]
      expect(platform).undefined
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.removePlatform(AppPlatformDescriptor.fromString('test:android'))
      sinon.assert.calledOnce(commitStub)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removePlatform,
          api,
          AppPlatformDescriptor.fromString('unexisting:android')
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removePlatform,
          api,
          AppPlatformDescriptor.fromString('test:ios')
        )
      )
    }


() => {
    it('should create the version object', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).createVersion(AppPlatformDescriptor.fromString('test:android'), {
        name: '17.20.0',
      })
      const version = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.20.0")]'
      )[0]
      expect(version).not.undefined
    })

    it('should commit the document store', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.createVersion(
        AppPlatformDescriptor.fromString('test:android'),
        { name: '17.20.0' }
      )
      sinon.assert.calledOnce(commitStub)
    })

    it('should throw if the platform does not exist', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.createVersion,
          api,
          AppPlatformDescriptor.fromString('test:ios'),
          { name: '17.20.0' }
        )
      )
    })

    it('should throw if the version already exists', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.createVersion,
          api,
          AppPlatformDescriptor.fromString('test:android'),
          { name: '17.7.0' }
        )
      )
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).createVersion(AppPlatformDescriptor.fromString('test:android'), {
        name: '17.20.0',
      })
      const version = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.20.0")]'
      )[0]
      expect(version).not.undefined
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.createVersion(
        AppPlatformDescriptor.fromString('test:android'),
        { name: '17.20.0' }
      )
      sinon.assert.calledOnce(commitStub)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.createVersion,
          api,
          AppPlatformDescriptor.fromString('test:ios'),
          { name: '17.20.0' }
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.createVersion,
          api,
          AppPlatformDescriptor.fromString('test:android'),
          { name: '17.7.0' }
        )
      )
    }


() => {
    it('should remove the native application version given its name', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).removeVersion(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      const version = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")]'
      )[0]
      expect(version).undefined
    })

    it('should commit the document store', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.removeVersion(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      sinon.assert.calledOnce(commitStub)
    })

    it('should throw if the platform name does not exists', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removeVersion,
          api,
          AppVersionDescriptor.fromString('test:ios:17.7.0')
        )
      )
    })

    it('should throw if the version does not exists', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removeVersion,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0')
        )
      )
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({ cauldronDocument: tmpFixture }).removeVersion(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      const version = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")]'
      )[0]
      expect(version).undefined
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.removeVersion(
        AppVersionDescriptor.fromString('test:android:17.7.0')
      )
      sinon.assert.calledOnce(commitStub)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removeVersion,
          api,
          AppVersionDescriptor.fromString('test:ios:17.7.0')
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removeVersion,
          api,
          AppVersionDescriptor.fromString('test:android:1.0.0')
        )
      )
    }


() => {
    it('should perform the update', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).updateVersion(AppVersionDescriptor.fromString('test:android:17.7.0'), {
        isReleased: false,
      })
      const version = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")]'
      )[0]
      expect(version.isReleased).false
    })

    it('should commit the document store', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.updateVersion(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        { isReleased: false }
      )
      sinon.assert.calledOnce(commitStub)
    })

    it('should throw if the version does not exists', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.updateVersion,
          api,
          AppVersionDescriptor.fromString('test:android:0.1.0'),
          { isReleased: false }
        )
      )
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).updateVersion(AppVersionDescriptor.fromString('test:android:17.7.0'), {
        isReleased: false,
      })
      const version = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")]'
      )[0]
      expect(version.isReleased).false
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.updateVersion(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        { isReleased: false }
      )
      sinon.assert.calledOnce(commitStub)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.updateVersion,
          api,
          AppVersionDescriptor.fromString('test:android:0.1.0'),
          { isReleased: false }
        )
      )
    }


() => {
    it('should add a description if it does not exist yet', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const newDescription = 'new description'
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).addOrUpdateDescription(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        newDescription
      )
      const version = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")]'
      )[0]
      expect(version.description).eql(newDescription)
    })

    it('should update a description if it already exist', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const updatedDescription = 'updated description'
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).addOrUpdateDescription(
        AppVersionDescriptor.fromString('test:android:17.8.0'),
        updatedDescription
      )
      const version = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.8.0")]'
      )[0]
      expect(version.description).eql(updatedDescription)
    })

    it('should commit the document store', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.addOrUpdateDescription(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'new description'
      )
      sinon.assert.calledOnce(commitStub)
    })

    it('should throw if the descriptor is partial', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.addOrUpdateDescription,
          api,
          AppPlatformDescriptor.fromString('test:android'),
          'new description'
        )
      )
    })

    it('should throw if the version does not exists', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.addOrUpdateDescription,
          api,
          AppVersionDescriptor.fromString('test:android:0.1.0'),
          'new description'
        )
      )
    })
  }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const newDescription = 'new description'
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).addOrUpdateDescription(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        newDescription
      )
      const version = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")]'
      )[0]
      expect(version.description).eql(newDescription)
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const updatedDescription = 'updated description'
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).addOrUpdateDescription(
        AppVersionDescriptor.fromString('test:android:17.8.0'),
        updatedDescription
      )
      const version = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.8.0")]'
      )[0]
      expect(version.description).eql(updatedDescription)
    }


async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.addOrUpdateDescription(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        'new description'
      )
      sinon.assert.calledOnce(commitStub)
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.addOrUpdateDescription,
          api,
          AppPlatformDescriptor.fromString('test:android'),
          'new description'
        )
      )
    }


async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.addOrUpdateDescription,
          api,
          AppVersionDescriptor.fromString('test:android:0.1.0'),
          'new description'
        )
      )
    }


() => {
    it('should remove the native dependency', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      await cauldronApi({
        cauldronDocument: tmpFixture,
      }).removePackageFromContainer(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        PackagePath.fromString('react-native-electrode-bridge'),
        'nativeDeps'
      )
      const dependenciesArr = jp.query(
        tmpFixture,
        '$.nativeApps[?(@.name=="test")].platforms[?(@.name=="android")].versions[?(@.name=="17.7.0")].container.nativeDeps'
      )[0]
      expect(dependenciesArr.includes('react-native-electrode-bridge@1.4.9'))
        .false
    })

    it('should commit the document store', async () => {
      const tmpFixture = JSON.parse(JSON.stringify(fixtures.defaultCauldron))
      const api = cauldronApi({ cauldronDocument: tmpFixture })
      const commitStub = sandbox.stub(documentStore, 'commit')
      await api.removePackageFromContainer(
        AppVersionDescriptor.fromString('test:android:17.7.0'),
        PackagePath.fromString('react-native-electrode-bridge'),
        'nativeDeps'
      )
      sinon.assert.calledOnce(commitStub)
    })

    it('should throw if the dependency is not found', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removePackageFromContainer,
          api,
          AppVersionDescriptor.fromString('test:android:17.7.0'),
          PackagePath.fromString('unexisting'),
          'nativeDeps'
        )
      )
    })

    it('should throw if the native application version is not found', async () => {
      const api = cauldronApi()
      assert(
        await doesThrow(
          api.removePackageFromContainer,
          api,
          AppVersionDescriptor.fromString('test:android:17.20.0'),
          'react-native-electrode-bridge',
          'nativeDeps'
        )
      )
    })
  }