/** Base class for the instances of 'ReadableData' that can also be written. */
export abstract class WritableData extends ReadableData {

    private isRootPath(path: string): boolean {
        return !path || path.trim().length == 0;
    }

    public fake(){
        this.fakeData();
    }

    /**
     * Performs the given write operation to the entry with the given
     * path in data if successful, throws an error otherwise.
     *
     * An error may be thrown in the following cases:
     * - an entry under the given path does not exist
     * - the given operation will lead to incompliance with the schema
     * - the given operation is not allowed on the addressed entry in data
     * - the given operation is invalid
     * - other internal errors happen
     *
     * @param operation A valid read operation. Allowed read operations
     * depend on the type of the entry addressed by the parameter 'path'.
     * @param path A path to an existing entry in data.
     */
    public write(operation: WriteOp, value: any, path: string = ""){

        /**
         * The operation will be first performed on a copy of data, then the
         * copy will be validated. If the copy passes validation, then the
         * operation will be performed on the original data,
         * otherwise an error will be thrown.
         */

        let copy: any = undefined;
        let opStr = this.getOperationString(operation, path, value);

        switch(operation){

            // set reference if object, value if primitive
            case WriteOp.set:

                // Check if the entry exists
                if(this.hasEntry(path, undefined, true, opStr)){

                    // perform operation on a copy of data
                    copy = u.copy(this.data);
                    if(this.isRootPath(path)){
                        copy = value;
                    }else{
                        jsonPointer.set(copy, path, value);
                    }

                    // validate the copy with an error if invaild
                    if(this.validate(copy, true, opStr)){

                        // modify original data after successful validation
                        if(this.isRootPath(path)){
                            this.data = value;
                        }else{
                            jsonPointer.set(this.data, path, value);
                        }
                    }
                }
                break;

            // write a deep copy
            case WriteOp.copy:

                // Check if the entry exists
                if(this.hasEntry(path, undefined, true, opStr)){

                    // perform operation on a copy of data
                    copy = u.copy(this.data);
                    if(this.isRootPath(path)){
                        copy = value;
                    }else{
                        jsonPointer.set(copy, path, value);
                    }

                    // validate the copy with an error if invaild
                    if(this.validate(copy, true, opStr)){

                        // modify original data after successful validation
                        if(this.isRootPath(path)){
                            this.data = u.copy(value);
                        }else{
                            jsonPointer.set(this.data, path, u.copy(value));
                        }
                    }
                }
                break;

            // push the reference if object, value if primitive
            case WriteOp.push:

                // Check if the entry exists and it is an array
                if(this.hasEntry(path, Array, true, opStr)){

                    // perform operation on a copy of data
                    copy = u.copy(this.data);
                    jsonPointer.get(copy, path).push(value);

                    // validate the copy with an error if invaild
                    if(this.validate(copy, true, opStr)){

                        // modify original data after successful validation
                        jsonPointer.get(this.data, path).push(value);
                    }
                }
                break;

            // push a deep copy
            case WriteOp.pushCopy:

                // Check if the entry exists and it is an array
                if(this.hasEntry(path, Array, true, opStr)){

                    // perform operation on a copy of data
                    copy = u.copy(this.data);
                    jsonPointer.get(copy, path).push(value);

                    // validate the copy with an error if invaild
                    if(this.validate(copy, true, opStr)){

                        // modify original data after successful validation
                        jsonPointer.get(this.data, path).push(u.copy(value));
                    }
                }
                break;

            // concatenate to a string
            case WriteOp.concat:

                // Check if the entry exists and it is a string
                if(this.hasEntry(path, String, true, opStr)){

                    // perform operation on a copy of data
                    copy = u.copy(this.data);
                    let targetValue = jsonPointer.get(copy, path) + value;
                    if(this.isRootPath(path)){
                        copy = targetValue;
                    }else{
                        jsonPointer.set(copy, path, targetValue);
                    }

                    // validate the copy with an error if invaild
                    if(this.validate(copy, true, opStr)){

                        // modify original data after successful validation
                        if(this.isRootPath(path)){
                            this.data = targetValue;
                        }else{
                            jsonPointer.set(this.data, path, targetValue);
                        }
                    }
                }
                break;
            default:
                u.fatal("Invalid operation:\n" + opStr, this.getFullPath());
                break;
        }
    }
}


/** Class representing readonly data. */
export class ReadOnlyData extends ReadableData {
    public constructor(name: string, parent: ComponentOwner, schema: IDataSchema){
        super(name, parent, schema);
    }
}


/** Class representing read/write-able data. */
export class Data extends WritableData {
    public constructor(name: string, parent: ComponentOwner, schema: IDataSchema){
        super(name, parent, schema);
    }
}


export enum ReadOp {
    get = "get",
    pop = "pop",
    copy = "copy",
    length = "length",
    parse = "parse"
}


export enum WriteOp {
    set = "set",
    push = "push",
    copy = "copy",
    pushCopy = "pushCopy",
    concat = "concat"
}


//#region Reset/initialize value
/** Resets data to its default value according to the schema. */
public reset(){
        if(DataHolder.hasConst(this.schema)){
            this.data = this.schema.const;
        }else if(DataHolder.hasFakeTrue(this.schema)){
            this.fakeData();
        }else if(this.hasType()){
            this.data = jsonInstantiator.instantiate(this.schema);
        }else if(this.hasDefault()){
            this.data = this.schema.default;
        }else{
            this.data = undefined;
        }
    }


protected isFake(){
        return !DataHolder.hasConst(this.schema) && DataHolder.hasFakeTrue(this.schema);
    }


protected hasDefault(){
        return this.schema.default !== undefined;
    }


protected hasType(){
        return this.schema.type !== undefined;
    }


public static hasFakeTrue(schema: IDataSchema){
        return schema.fake === true;
    }


public static hasConst(schema: IDataSchema){
        return schema.const !== undefined;
    }


public static isReadOnly(schema: IDataSchema){
        return DataHolder.hasConst(schema) || DataHolder.hasFakeTrue(schema);
    }


//#endregion
/** Fakes data using the schema */
protected fakeData(){
        this.data = jsf(this.schema);
    }


/**
     * Validates the given value against the schema.
     *
     * Returns true - if the value is valid, false - otherwise.
     *
     * @param value Value to validate.
     * @param withError If true, then in case of validation failure an error
     * will be thrown.
     * @param opDescr A string descibing in which context validation is performed, e.g.
     * which operation required validation. Will be used in the message of the error
     * in case the latter is thrown.
     */
protected validate(value: any, withError: boolean = false, opDescr: string = undefined): boolean {
        if(this.getModel().getValidator().validate(this.getFullPath(), value)){
            return true;
        }else if(withError){
            u.fatal("Validation failed: " + (opDescr ? "\n" + opDescr : "")
                + "\nReason: " + this.getModel().getValidator().errorsText(),
                this.getFullPath());
        }
        return false;
    }


/**
     * Composes and returns a string describing an operation
     * that is being performed over data.
     *
     * @param operation A valid read or write operation.
     * @param path The relative path of the affected entry in data.
     * @param value The value that is being written in case of a write operation.
     */
protected getOperationString(operation: ReadOp|WriteOp, path: string, value: any = undefined){
        return "Operation: " + operation
                + (value !== undefined ? "\nValue: " + JSON.stringify(value, null, 4) : "")
                + "\nPath: " + (path === '' ? "root" : path);
    }


/**
     * Checks whether data has an entry with the given path.
     *
     * Returns true - if check succeeds (i.e. an entry is present),
     * false - otherwise.
     *
     * @param path The relative path of the entry in data.
     * @param expectedType The expected type of the entry. If this parameter
     * is provided and the entry is of a different type, the check will fail.
     * @param withError If true, then in case of check failure an error
     * will be thrown.
     * @param opDescr A string descibing in which context the check is performed, e.g.
     * which operation required this check. Will be used in the message of the error
     * in case the latter is thrown.
     */
public hasEntry(path: string, expectedType: any = undefined, withError: boolean = false, opDescr: string = undefined): boolean {

        if(!jsonPointer.has(this.data, path)){

            if(withError){
                u.fatal("No such entry."
                        + (opDescr ? "\n" + opDescr : "")
                        + "\nData: \n"
                        + JSON.stringify(this.data, null, 4),
                        this.getFullPath());
            }
            return false;

        }else if(expectedType !== undefined){

            let value = jsonPointer.get(this.data, path);

            if(!u.instanceOf(value, expectedType)){
                if(withError){
                    u.fatal("Incorrect type."
                        + (opDescr ? "\n" + opDescr : "")
                        + "\nExpected type: "
                        + u.getTypeNameFromType(expectedType)
                        + "\nActual type: "
                        + u.getTypeNameFromValue(value),
                        this.getFullPath());
                }
                return false;
            }
        }
        return true;
    }


/**
     * Creates and returns an instance of:
     * - 'ReadOnlyData' in case the given schema contains 'const' or 'fake'
     * - 'Data' - otherwise
     *
     * @param name A name for the instance (name of the node).
     * @param parent A parent for the instance (parent node)
     * @param schema A valid schema object.
     */
public static getInstance(name: string, parent: ComponentOwner, schema: IDataSchema): DataHolder {
        if(this.isReadOnly(schema)){
            return new ReadOnlyData(name, parent, schema);
        }else{
            return new Data(name, parent, schema);
        }
    }


/**
     * Performs the given read operation from the given path in data
     * and returns the result if successful, throws an error otherwise.
     *
     * An error may be thrown in the following cases:
     * - an entry under the given path does not exist
     * - the given operation will lead to incompliance with the schema
     * - the given operation is not allowed on the addressed entry in data
     * - the given operation is invalid
     * - other internal errors happen
     *
     * @param operation A valid read operation. Allowed read operations
     * depend on the type of the entry addressed by the parameter 'path'.
     * @param path A path to an existing entry in data.
     */
public read(operation: ReadOp, path: string = ""){

        /**
         * In case a read operation may lead to changes in data (e.g. 'pop'),
         * the operation will be first performed on a copy of data, then the
         * copy will be validated. If the copy passes validation, then the
         * operation will be performed on the original data,
         * otherwise an error will be thrown.
         */

        // Fake instances generate new fake value on each read.
        if(this.isFake()){
            this.reset();
        }

        let opStr = this.getOperationString(operation, path);

        switch(operation){

            // return reference if object, value if primitive
            case ReadOp.get:
                // Check if the entry exists
                if(this.hasEntry(path, undefined, true, opStr)){
                    return jsonPointer.get(this.data, path);
                }

            // return a deep copy
            case ReadOp.copy:
                // Check if the entry exists
                if(this.hasEntry(path, undefined, true, opStr)){
                    return u.copy(jsonPointer.get(this.data, path));
                }

            // pop from array and return
            case ReadOp.pop:
                // the 'pop' operation on a readonly data is not allowed
                if(this instanceof ReadOnlyData){
                    u.fatal("Invalid operation on a constant:\n" + opStr, this.getFullPath());
                }
                // Check if the entry exists and it is an array
                if(this.hasEntry(path, Array, true, opStr)){
                    let copy = u.copy(this.data);
                    jsonPointer.get(copy, path).pop();
                    // validate the copy with an error if invaild
                    if(this.validate(copy, true, opStr)){
                        // modify original data after successful validation
                        return jsonPointer.get(this.data, path).pop();
                    }
                }

            // return length of an array or string
            case ReadOp.length:
                // Check if the entry exists and it is an array or a string
                if(this.hasEntry(path, Array, false, opStr)
                    || this.hasEntry(path, String, true, opStr)){
                    return jsonPointer.get(this.data, path).length;
                }

            // return value parsed from a string
            case ReadOp.parse:
                // Check if the entry exists and it is a string
                if(this.hasEntry(path, String, true, opStr)){
                    return JSON.parse(jsonPointer.get(this.data, path));
                }
        }
        u.fatal("Invalid operation:\n" + opStr, this.getFullPath());
    }


private isRootPath(path: string): boolean {
        return !path || path.trim().length == 0;
    }


public fake(){
        this.fakeData();
    }


/**
     * Performs the given write operation to the entry with the given
     * path in data if successful, throws an error otherwise.
     *
     * An error may be thrown in the following cases:
     * - an entry under the given path does not exist
     * - the given operation will lead to incompliance with the schema
     * - the given operation is not allowed on the addressed entry in data
     * - the given operation is invalid
     * - other internal errors happen
     *
     * @param operation A valid read operation. Allowed read operations
     * depend on the type of the entry addressed by the parameter 'path'.
     * @param path A path to an existing entry in data.
     */
public write(operation: WriteOp, value: any, path: string = ""){

        /**
         * The operation will be first performed on a copy of data, then the
         * copy will be validated. If the copy passes validation, then the
         * operation will be performed on the original data,
         * otherwise an error will be thrown.
         */

        let copy: any = undefined;
        let opStr = this.getOperationString(operation, path, value);

        switch(operation){

            // set reference if object, value if primitive
            case WriteOp.set:

                // Check if the entry exists
                if(this.hasEntry(path, undefined, true, opStr)){

                    // perform operation on a copy of data
                    copy = u.copy(this.data);
                    if(this.isRootPath(path)){
                        copy = value;
                    }else{
                        jsonPointer.set(copy, path, value);
                    }

                    // validate the copy with an error if invaild
                    if(this.validate(copy, true, opStr)){

                        // modify original data after successful validation
                        if(this.isRootPath(path)){
                            this.data = value;
                        }else{
                            jsonPointer.set(this.data, path, value);
                        }
                    }
                }
                break;

            // write a deep copy
            case WriteOp.copy:

                // Check if the entry exists
                if(this.hasEntry(path, undefined, true, opStr)){

                    // perform operation on a copy of data
                    copy = u.copy(this.data);
                    if(this.isRootPath(path)){
                        copy = value;
                    }else{
                        jsonPointer.set(copy, path, value);
                    }

                    // validate the copy with an error if invaild
                    if(this.validate(copy, true, opStr)){

                        // modify original data after successful validation
                        if(this.isRootPath(path)){
                            this.data = u.copy(value);
                        }else{
                            jsonPointer.set(this.data, path, u.copy(value));
                        }
                    }
                }
                break;

            // push the reference if object, value if primitive
            case WriteOp.push:

                // Check if the entry exists and it is an array
                if(this.hasEntry(path, Array, true, opStr)){

                    // perform operation on a copy of data
                    copy = u.copy(this.data);
                    jsonPointer.get(copy, path).push(value);

                    // validate the copy with an error if invaild
                    if(this.validate(copy, true, opStr)){

                        // modify original data after successful validation
                        jsonPointer.get(this.data, path).push(value);
                    }
                }
                break;

            // push a deep copy
            case WriteOp.pushCopy:

                // Check if the entry exists and it is an array
                if(this.hasEntry(path, Array, true, opStr)){

                    // perform operation on a copy of data
                    copy = u.copy(this.data);
                    jsonPointer.get(copy, path).push(value);

                    // validate the copy with an error if invaild
                    if(this.validate(copy, true, opStr)){

                        // modify original data after successful validation
                        jsonPointer.get(this.data, path).push(u.copy(value));
                    }
                }
                break;

            // concatenate to a string
            case WriteOp.concat:

                // Check if the entry exists and it is a string
                if(this.hasEntry(path, String, true, opStr)){

                    // perform operation on a copy of data
                    copy = u.copy(this.data);
                    let targetValue = jsonPointer.get(copy, path) + value;
                    if(this.isRootPath(path)){
                        copy = targetValue;
                    }else{
                        jsonPointer.set(copy, path, targetValue);
                    }

                    // validate the copy with an error if invaild
                    if(this.validate(copy, true, opStr)){

                        // modify original data after successful validation
                        if(this.isRootPath(path)){
                            this.data = targetValue;
                        }else{
                            jsonPointer.set(this.data, path, targetValue);
                        }
                    }
                }
                break;
            default:
                u.fatal("Invalid operation:\n" + opStr, this.getFullPath());
                break;
        }
    }


() => vnode.attrs.runPipeline(vnode.attrs.pipelineName)


(stage, index) => {
          return

            {ShowForceBuildActionWidget.getStageApprovalIcon(index, stage)}

;
        }


export class ShowForceBuildActionWidget extends MithrilViewComponent<ShowForceBuildActionAttrs> {
  view(vnode: m.Vnode<ShowForceBuildActionAttrs, this>): m.Children {
    return

        <Primary onclick={() => vnode.attrs.runPipeline(vnode.attrs.pipelineName)}
                 small={true}
                 dataTestId="force-trigger-pipeline"
                 disabled={!vnode.attrs.canForce()}


interface ShowForceBuildActionAttrs {
  group: Group;
  canForce: Stream<boolean>;
  pipelineName: string;
  runPipeline: (name: string) => void;
}


view(vnode: m.Vnode<ShowForceBuildActionAttrs, this>): m.Children {
    return

        <Primary onclick={() => vnode.attrs.runPipeline(vnode.attrs.pipelineName)}
                 small={true}
                 dataTestId="force-trigger-pipeline"
                 disabled={!vnode.attrs.canForce()}


resources=>
        {

            this.settings = resources.data[0];
            console.log(this.settings);
            this.profileInfoLabel = this.settings.Labels.find(label=>label.name =='profileInfoLabel').description;
            this.myBusinessLabel = this.settings.Labels.find(label=>label.name =='myBusinessLabel').description;
            this.optionsLeftSideComponentLabel =  this.settings.Labels.find(label=>label.name =='optionsLeftSideComponentLabel').description;

            this.createBusinessUrl = this.settings.Urls.find(url => url.name == 'createBusinessUrl').url;
            this.createBusinessLabel = this.settings.Labels.find(label => label.name == 'createBusinessLabel').description;

            this.listMyBusinessLabel = this.settings.Labels.find(label=>label.name =='listMyBusinessLabel').description;
            this.listMyBusinessUrl =  this.settings.Urls.find(url => url.name == 'listMyBusinessUrl').url;
        }


label=>label.name =='profileInfoLabel'


label=>label.name =='myBusinessLabel'


label=>label.name =='optionsLeftSideComponentLabel'


url => url.name == 'createBusinessUrl'


label => label.name == 'createBusinessLabel'


label=>label.name =='listMyBusinessLabel'


url => url.name == 'listMyBusinessUrl'


error=>{
          console.log(error);
        }


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

export class StarterLeftSideComponent implements OnInit {

  title = 'app';
  profileInfoLabel:string;
  profileInfoUrl:string;

  myBusinessLabel:string;
  myBusinessUrl:string;

  optionsLeftSideComponentLabel: string;
  optionsLeftSideComponentUrl: string;

  createBusinessLabel : string;
  createBusinessUrl : string;

  listMyBusinessLabel:string;
  listMyBusinessUrl : string;

  settings : SettingsDTO;

  constructor(
    private settingsService : SettingsService
    )
  {}

  ngOnInit(): void {
        this.loadComponentsResources();
  }

  private loadComponentsResources(){
    this.loadLabels();
  }
  /**
   * carga los recursos de un componente(ursl, labels, textos)
   */
        /**
      * Obtiene configuracione del componente
      */
    private loadLabels(){
    this.settingsService.componentName = this.constructor.name;
    this.settingsService.list().pipe().subscribe(
        resources=>
        {

            this.settings = resources.data[0];
            console.log(this.settings);
            this.profileInfoLabel = this.settings.Labels.find(label=>label.name =='profileInfoLabel').description;
            this.myBusinessLabel = this.settings.Labels.find(label=>label.name =='myBusinessLabel').description;
            this.optionsLeftSideComponentLabel =  this.settings.Labels.find(label=>label.name =='optionsLeftSideComponentLabel').description;

            this.createBusinessUrl = this.settings.Urls.find(url => url.name == 'createBusinessUrl').url;
            this.createBusinessLabel = this.settings.Labels.find(label => label.name == 'createBusinessLabel').description;

            this.listMyBusinessLabel = this.settings.Labels.find(label=>label.name =='listMyBusinessLabel').description;
            this.listMyBusinessUrl =  this.settings.Urls.find(url => url.name == 'listMyBusinessUrl').url;
        },
        error=>{
          console.log(error);
        }
      );
  }
}


ngOnInit(): void {
        this.loadComponentsResources();
  }


private loadComponentsResources(){
    this.loadLabels();
  }


/**
   * carga los recursos de un componente(ursl, labels, textos)
   */
/**
      * Obtiene configuracione del componente
      */
private loadLabels(){
    this.settingsService.componentName = this.constructor.name;
    this.settingsService.list().pipe().subscribe(
        resources=>
        {

            this.settings = resources.data[0];
            console.log(this.settings);
            this.profileInfoLabel = this.settings.Labels.find(label=>label.name =='profileInfoLabel').description;
            this.myBusinessLabel = this.settings.Labels.find(label=>label.name =='myBusinessLabel').description;
            this.optionsLeftSideComponentLabel =  this.settings.Labels.find(label=>label.name =='optionsLeftSideComponentLabel').description;

            this.createBusinessUrl = this.settings.Urls.find(url => url.name == 'createBusinessUrl').url;
            this.createBusinessLabel = this.settings.Labels.find(label => label.name == 'createBusinessLabel').description;

            this.listMyBusinessLabel = this.settings.Labels.find(label=>label.name =='listMyBusinessLabel').description;
            this.listMyBusinessUrl =  this.settings.Urls.find(url => url.name == 'listMyBusinessUrl').url;
        },
        error=>{
          console.log(error);
        }
      );
  }


export function invariant(condition: any, message: string, ...args: any[]): asserts condition {
  if (!condition) {
    throw new FormattedError(message, ...args);
  }
}


export class FormattedError extends Error {
  constructor(template: string, ...args: any[]) {
    super(util.format(template, ...args));
    this.template = template;
    this.args = args;
  }

  public template: string;
  public args: any[];
}


async function createDummyKeyboardsRepo(gitHubDir: string): Promise<string> {
    fs.mkdirSync(path.join(gitHubDir, 'dummy'));
    const keyboardsDummyRepo = await gitService.createRepo(
      path.join(gitHubDir, 'dummy', 'keyboards'),
    ).toPromise();
    const readme = path.join(keyboardsDummyRepo, 'README.md');
    fs.appendFileSync(readme, 'Readme');
    const kbInfo = path.join(keyboardsDummyRepo, 'dummy.keyboard_info');
    fs.appendFileSync(kbInfo, '{}');
    await gitService.addFile(keyboardsDummyRepo, readme).toPromise();
    await gitService.addFile(keyboardsDummyRepo, kbInfo).toPromise();
    await gitService.commit(keyboardsDummyRepo, 'Initial commit').toPromise();
    return keyboardsDummyRepo;
  }


async function createKeyboardsRepoForUser(
    user: string,
    gitHubDir: string,
  ): Promise<string> {
    // create keyboards repo for user
    const keyboardsDummyRepo = await createDummyKeyboardsRepo(gitHubDir);
    return await gitService.clone(
      keyboardsDummyRepo,
      path.join(gitHubDir, user, 'keyboards.git'),
      true,
    ).toPromise();
  }


async function createGlobalKeyboardsRepo(gitHubDir: string): Promise<void> {
    const keyboardsDummyRepo = await createDummyKeyboardsRepo(gitHubDir);

    await gitService.clone(
      keyboardsDummyRepo,
      path.join(gitHubDir, 'keymanapp', 'keyboards.git'),
      true,
    ).toPromise();
  }


async () => {
    jest.setTimeout(10000 /* 10s */);
    const module: TestingModule = await Test.createTestingModule({
      imports: [HttpModule, ConfigModule, BackendProjectModule],
      controllers: [ProjectsController],
      providers: [
        TokenService,
        {
          provide: GithubService,
          useFactory: (): any => ({
            getRepos: jest.fn(() => true),
            forkRepo: jest.fn(() => of({ name: 'foo' })),
            createPullRequest: jest.fn(() => of()),
            pullRequestExists: jest.fn(() => throwError(new HttpException('Pull request does not exist', 404))),
            pullRequestDetails: jest.fn(() => of()),
          }),
        },
        GitService,
        PullRequestService,
      ],
    }).compile();

    sut = module.get<ProjectsController>(ProjectsController);
    githubService = module.get<GithubService>(GithubService);
    gitService = module.get<GitService>(GitService);
    config = module.get<ConfigService>(ConfigService);
  }


(): any => ({
            getRepos: jest.fn(() => true),
            forkRepo: jest.fn(() => of({ name: 'foo' })),
            createPullRequest: jest.fn(() => of()),
            pullRequestExists: jest.fn(() => throwError(new HttpException('Pull request does not exist', 404))),
            pullRequestDetails: jest.fn(() => of()),
          })


() => of({ name: 'foo' })


() => of()


() => throwError(new HttpException('Pull request does not exist', 404))


() => {
    expect(sut).toBeDefined();
  }


() => {
    it('should return list of repos', async () => {
      jest.spyOn(githubService, 'getRepos').mockImplementationOnce(() => of({
        name: 'foo',
        owner: { login: 'foo' },
      }));

      const session = { login: 'foo' };
      await expect(sut.getRepos(session, 'token 12345', 1).toPromise())
        .resolves.toEqual([{ name: 'foo' }]);
    });

    it('should filter list of repos', async () => {
      jest.spyOn(githubService, 'getRepos').mockImplementationOnce(() =>
        of(
          {
            name: 'foo',
            owner: { login: 'foo' },
          },
          {
            name: 'other',
            owner: { login: 'bar' },
          },
        ),
      );

      const session = { login: 'foo' };
      await expect(
        sut.getRepos(session, 'token 12345', 1).toPromise(),
      ).resolves.toEqual([{ name: 'foo' }]);
    });

    it('should return empty list if requesting behind last page', async () => {
      jest.spyOn(githubService, 'getRepos').mockImplementationOnce(() => empty());

      const session = { login: 'foo' };
      await expect(sut.getRepos(session, 'token 12345', 99).toPromise()).resolves.toEqual([]);
    });
  }


async () => {
      jest.spyOn(githubService, 'getRepos').mockImplementationOnce(() => of({
        name: 'foo',
        owner: { login: 'foo' },
      }));

      const session = { login: 'foo' };
      await expect(sut.getRepos(session, 'token 12345', 1).toPromise())
        .resolves.toEqual([{ name: 'foo' }]);
    }


() => of({
        name: 'foo',
        owner: { login: 'foo' },
      })


async () => {
      jest.spyOn(githubService, 'getRepos').mockImplementationOnce(() =>
        of(
          {
            name: 'foo',
            owner: { login: 'foo' },
          },
          {
            name: 'other',
            owner: { login: 'bar' },
          },
        ),
      );

      const session = { login: 'foo' };
      await expect(
        sut.getRepos(session, 'token 12345', 1).toPromise(),
      ).resolves.toEqual([{ name: 'foo' }]);
    }


() =>
        of(
          {
            name: 'foo',
            owner: { login: 'foo' },
          },
          {
            name: 'other',
            owner: { login: 'bar' },
          },
        )


async () => {
      jest.spyOn(githubService, 'getRepos').mockImplementationOnce(() => empty());

      const session = { login: 'foo' };
      await expect(sut.getRepos(session, 'token 12345', 99).toPromise()).resolves.toEqual([]);
    }


() => empty()


() => {
    let gitHubDir: string;
    let workDir: string;

    beforeEach(async () => {
      workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'workdir-'));
      jest.spyOn(config, 'workDirectory', 'get').mockReturnValue(workDir);

      const prefix = path.join(os.tmpdir(), 'projectstests-');
      gitHubDir = fs.mkdtempSync(prefix);
      jest.spyOn(sut, 'gitHubUrl', 'get').mockReturnValue(gitHubDir);

      // create single keyboard repo
      const repoDir = await gitService.createRepo(path.join(gitHubDir, 'tmpTestRepo')).toPromise();
      const filePath1 = path.join(repoDir, 'somefile1.txt');
      const filePath2 = path.join(repoDir, 'somefile2.txt');
      const kbInfo = path.join(repoDir, 'remoteTestRepo.keyboard_info');
      fs.appendFileSync(filePath1, 'some text');
      fs.appendFileSync(filePath2, 'other text');
      fs.appendFileSync(kbInfo, '{}');
      await Promise.all([
        gitService.addFile(repoDir, filePath1).toPromise(),
        gitService.addFile(repoDir, filePath2).toPromise(),
        gitService.addFile(repoDir, kbInfo).toPromise(),
      ]);
      await gitService.commit(repoDir, 'Initial commit').toPromise();

      await gitService
        .clone(repoDir, path.join(gitHubDir, 'foo', 'remoteTestRepo.git'), true)
        .toPromise();
    });

    afterEach(() => {
      deleteFolderRecursive(gitHubDir);
      deleteFolderRecursive(workDir);
    });

    it('clones single-keyboard and keyboards repos', async () => {
      expect.assertions(4);

      // Setup
      const session = { login: 'foo' };
      await createKeyboardsRepoForUser('foo', gitHubDir);

      // Execute
      const project = await sut.createRepo(session, 'token 12345', 'remoteTestRepo').toPromise();

      // Verify
      // Should clone single-keyboards repo
      const expectedRepo = path.join(workDir, 'foo', 'remoteTestRepo');
      expect(fs.existsSync(path.join(expectedRepo, '.git'))).toBe(true);
      expect(project).toEqual({
        repoUrl: `${gitHubDir}/foo/remoteTestRepo.git`,
        name: 'remoteTestRepo',
        prefix: 'r',
      });

      // Should clone keyboards repo
      const expectedKeyboardsRepo = path.join(workDir, 'keyboards');
      expect(fs.existsSync(path.join(expectedKeyboardsRepo, '.git'))).toBe(true);
      expect(
        await gitService.currentBranch(expectedKeyboardsRepo).toPromise(),
      ).toEqual('foo-remoteTestRepo');
    });

    it('clones single-keyboard repo and forks keyboards repo', async () => {
      expect.assertions(5);

      // Setup
      const session = { login: 'foo' };
      await createGlobalKeyboardsRepo(gitHubDir);

      jest
        .spyOn(githubService, 'forkRepo')
        .mockImplementation(() => {
          return gitService.clone(
              path.join(gitHubDir, 'dummy', 'keyboards'),
              path.join(gitHubDir, 'foo', 'keyboards.git'),
              true,
          ).pipe(
            map(() => ({ name: 'keyboards' })),
          );
        });

      // Execute
      const project = await sut
        .createRepo(session, 'token 12345', 'remoteTestRepo')
        .toPromise();

      // Verify
      // Should clone single-keyboards repo
      const expectedRepo = path.join(workDir, 'foo', 'remoteTestRepo');
      expect(fs.existsSync(path.join(expectedRepo, '.git'))).toBe(true);
      expect(project).toEqual({
        repoUrl: `${gitHubDir}/foo/remoteTestRepo.git`,
        name: 'remoteTestRepo',
        prefix: 'r',
      });

      // should create fork of keyboards repo
      expect(fs.existsSync(path.join(gitHubDir, 'foo', 'keyboards.git'))).toBe(true);

      // Should clone keyboards repo
      const expectedKeyboardsRepo = path.join(workDir, 'keyboards');
      expect(fs.existsSync(path.join(expectedKeyboardsRepo, '.git'))).toBe(true);
      expect(
        await gitService.currentBranch(expectedKeyboardsRepo).toPromise(),
      ).toEqual('foo-remoteTestRepo');
    });
  }


async () => {
      workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'workdir-'));
      jest.spyOn(config, 'workDirectory', 'get').mockReturnValue(workDir);

      const prefix = path.join(os.tmpdir(), 'projectstests-');
      gitHubDir = fs.mkdtempSync(prefix);
      jest.spyOn(sut, 'gitHubUrl', 'get').mockReturnValue(gitHubDir);

      // create single keyboard repo
      const repoDir = await gitService.createRepo(path.join(gitHubDir, 'tmpTestRepo')).toPromise();
      const filePath1 = path.join(repoDir, 'somefile1.txt');
      const filePath2 = path.join(repoDir, 'somefile2.txt');
      const kbInfo = path.join(repoDir, 'remoteTestRepo.keyboard_info');
      fs.appendFileSync(filePath1, 'some text');
      fs.appendFileSync(filePath2, 'other text');
      fs.appendFileSync(kbInfo, '{}');
      await Promise.all([
        gitService.addFile(repoDir, filePath1).toPromise(),
        gitService.addFile(repoDir, filePath2).toPromise(),
        gitService.addFile(repoDir, kbInfo).toPromise(),
      ]);
      await gitService.commit(repoDir, 'Initial commit').toPromise();

      await gitService
        .clone(repoDir, path.join(gitHubDir, 'foo', 'remoteTestRepo.git'), true)
        .toPromise();
    }


() => {
      deleteFolderRecursive(gitHubDir);
      deleteFolderRecursive(workDir);
    }


async () => {
      expect.assertions(4);

      // Setup
      const session = { login: 'foo' };
      await createKeyboardsRepoForUser('foo', gitHubDir);

      // Execute
      const project = await sut.createRepo(session, 'token 12345', 'remoteTestRepo').toPromise();

      // Verify
      // Should clone single-keyboards repo
      const expectedRepo = path.join(workDir, 'foo', 'remoteTestRepo');
      expect(fs.existsSync(path.join(expectedRepo, '.git'))).toBe(true);
      expect(project).toEqual({
        repoUrl: `${gitHubDir}/foo/remoteTestRepo.git`,
        name: 'remoteTestRepo',
        prefix: 'r',
      });

      // Should clone keyboards repo
      const expectedKeyboardsRepo = path.join(workDir, 'keyboards');
      expect(fs.existsSync(path.join(expectedKeyboardsRepo, '.git'))).toBe(true);
      expect(
        await gitService.currentBranch(expectedKeyboardsRepo).toPromise(),
      ).toEqual('foo-remoteTestRepo');
    }


async () => {
      expect.assertions(5);

      // Setup
      const session = { login: 'foo' };
      await createGlobalKeyboardsRepo(gitHubDir);

      jest
        .spyOn(githubService, 'forkRepo')
        .mockImplementation(() => {
          return gitService.clone(
              path.join(gitHubDir, 'dummy', 'keyboards'),
              path.join(gitHubDir, 'foo', 'keyboards.git'),
              true,
          ).pipe(
            map(() => ({ name: 'keyboards' })),
          );
        });

      // Execute
      const project = await sut
        .createRepo(session, 'token 12345', 'remoteTestRepo')
        .toPromise();

      // Verify
      // Should clone single-keyboards repo
      const expectedRepo = path.join(workDir, 'foo', 'remoteTestRepo');
      expect(fs.existsSync(path.join(expectedRepo, '.git'))).toBe(true);
      expect(project).toEqual({
        repoUrl: `${gitHubDir}/foo/remoteTestRepo.git`,
        name: 'remoteTestRepo',
        prefix: 'r',
      });

      // should create fork of keyboards repo
      expect(fs.existsSync(path.join(gitHubDir, 'foo', 'keyboards.git'))).toBe(true);

      // Should clone keyboards repo
      const expectedKeyboardsRepo = path.join(workDir, 'keyboards');
      expect(fs.existsSync(path.join(expectedKeyboardsRepo, '.git'))).toBe(true);
      expect(
        await gitService.currentBranch(expectedKeyboardsRepo).toPromise(),
      ).toEqual('foo-remoteTestRepo');
    }


() => {
          return gitService.clone(
              path.join(gitHubDir, 'dummy', 'keyboards'),
              path.join(gitHubDir, 'foo', 'keyboards.git'),
              true,
          ).pipe(
            map(() => ({ name: 'keyboards' })),
          );
        }


() => ({ name: 'keyboards' })


() => {
    let gitHubDir: string;
    let workDir: string;
    let gitHubKeyboardsRepo: string;
    let localKeyboardsRepo: string;

    beforeEach(async () => {
      workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'workdir-'));
      jest.spyOn(config, 'workDirectory', 'get').mockReturnValue(workDir);

      const prefix = path.join(os.tmpdir(), 'projectstests-');
      gitHubDir = fs.mkdtempSync(prefix);
      jest.spyOn(sut, 'gitHubUrl', 'get').mockReturnValue(gitHubDir);

      // create single keyboard repo
      const repoDir = await gitService
        .createRepo(path.join(workDir, 'tmpTestRepo'))
        .toPromise();
      const filePath1 = path.join(repoDir, 'somefile1.txt');
      fs.appendFileSync(filePath1, 'some text');
      await gitService.addFile(repoDir, filePath1).toPromise();
      await gitService.commit(repoDir, 'Initial commit').toPromise();

      await gitService
        .clone(repoDir, path.join(workDir, 'jdoe', 'myKeyboard'), false)
        .toPromise();

      gitHubKeyboardsRepo = await createKeyboardsRepoForUser('jdoe', gitHubDir);
      localKeyboardsRepo = await gitService
        .clone(
          gitHubKeyboardsRepo,
          path.join(workDir, 'keyboards'),
          false,
          'jdoe',
        )
        .toPromise();
      await gitService
        .checkoutBranch(localKeyboardsRepo, 'jdoe-myKeyboard')
        .toPromise();
    });

    afterEach(() => {
      deleteFolderRecursive(gitHubDir);
      deleteFolderRecursive(workDir);
    });

    it('should apply patches and create PR', async () => {
      // Setup
      expect.assertions(4);
      const session = { login: 'jdoe' };
      const mockImplementation = jest
        .spyOn(githubService, 'createPullRequest')
        .mockImplementationOnce(() => of({
          'number': 42,
          url:
            'https://api.github.com/repos/keymanapp/keyboards/pulls/42',
          state: PrState.Open,
          action: PrAction.Created,
        }));

      // Execute
      await sut.createPullRequest(
        session,
        'token 12345',
        'myKeyboard',
        { name: 'myKeyboard' },
      ).toPromise();

      // Verify
      // should apply patches to keyboards repo
      expect(
        fs.existsSync(path.join(localKeyboardsRepo, 'release', 'm', 'myKeyboard', 'somefile1.txt')),
      ).toBe(true);
      expect(await gitService.currentBranch(localKeyboardsRepo).toPromise())
        .toEqual('jdoe-myKeyboard');

      // should have pushed to keyboards repo on GitHub
      const gitHubCommit = await gitService
        .log(gitHubKeyboardsRepo, { '-1': null, 'jdoe-myKeyboard': null })
        .toPromise();
      const expectedCommit = await gitService
        .log(localKeyboardsRepo, { '-1': null })
        .toPromise();
      expect(gitHubCommit.latest.hash).toEqual(expectedCommit.latest.hash);

      // should have created PR
      expect(mockImplementation).toHaveBeenCalledWith(
        'token 12345',
        'keymanapp',
        'keyboards',
        'jdoe:jdoe-myKeyboard',
        'master',
        '[myKeyboard] Add myKeyboard keyboard',
        'Merge the single keyboard repo myKeyboard into the keyboards repo. Courtesy of Keyman Developer Online.',
      );
    });
  }


async () => {
      workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'workdir-'));
      jest.spyOn(config, 'workDirectory', 'get').mockReturnValue(workDir);

      const prefix = path.join(os.tmpdir(), 'projectstests-');
      gitHubDir = fs.mkdtempSync(prefix);
      jest.spyOn(sut, 'gitHubUrl', 'get').mockReturnValue(gitHubDir);

      // create single keyboard repo
      const repoDir = await gitService
        .createRepo(path.join(workDir, 'tmpTestRepo'))
        .toPromise();
      const filePath1 = path.join(repoDir, 'somefile1.txt');
      fs.appendFileSync(filePath1, 'some text');
      await gitService.addFile(repoDir, filePath1).toPromise();
      await gitService.commit(repoDir, 'Initial commit').toPromise();

      await gitService
        .clone(repoDir, path.join(workDir, 'jdoe', 'myKeyboard'), false)
        .toPromise();

      gitHubKeyboardsRepo = await createKeyboardsRepoForUser('jdoe', gitHubDir);
      localKeyboardsRepo = await gitService
        .clone(
          gitHubKeyboardsRepo,
          path.join(workDir, 'keyboards'),
          false,
          'jdoe',
        )
        .toPromise();
      await gitService
        .checkoutBranch(localKeyboardsRepo, 'jdoe-myKeyboard')
        .toPromise();
    }


async () => {
      // Setup
      expect.assertions(4);
      const session = { login: 'jdoe' };
      const mockImplementation = jest
        .spyOn(githubService, 'createPullRequest')
        .mockImplementationOnce(() => of({
          'number': 42,
          url:
            'https://api.github.com/repos/keymanapp/keyboards/pulls/42',
          state: PrState.Open,
          action: PrAction.Created,
        }));

      // Execute
      await sut.createPullRequest(
        session,
        'token 12345',
        'myKeyboard',
        { name: 'myKeyboard' },
      ).toPromise();

      // Verify
      // should apply patches to keyboards repo
      expect(
        fs.existsSync(path.join(localKeyboardsRepo, 'release', 'm', 'myKeyboard', 'somefile1.txt')),
      ).toBe(true);
      expect(await gitService.currentBranch(localKeyboardsRepo).toPromise())
        .toEqual('jdoe-myKeyboard');

      // should have pushed to keyboards repo on GitHub
      const gitHubCommit = await gitService
        .log(gitHubKeyboardsRepo, { '-1': null, 'jdoe-myKeyboard': null })
        .toPromise();
      const expectedCommit = await gitService
        .log(localKeyboardsRepo, { '-1': null })
        .toPromise();
      expect(gitHubCommit.latest.hash).toEqual(expectedCommit.latest.hash);

      // should have created PR
      expect(mockImplementation).toHaveBeenCalledWith(
        'token 12345',
        'keymanapp',
        'keyboards',
        'jdoe:jdoe-myKeyboard',
        'master',
        '[myKeyboard] Add myKeyboard keyboard',
        'Merge the single keyboard repo myKeyboard into the keyboards repo. Courtesy of Keyman Developer Online.',
      );
    }


() => of({
          'number': 42,
          url:
            'https://api.github.com/repos/keymanapp/keyboards/pulls/42',
          state: PrState.Open,
          action: PrAction.Created,
        })


export default class ChthonianPlanetGen extends BasePlanetGen implements IPlanetGen {
    getKey(): number {
        return PlanetType.Chthonian;
    }

    run(workObj: PlanetTypeWorker): Orbit<IPlanet> {
        const stats = new PlanetStats();

        stats.size = Score.nG;
        stats.atmosphere = Score.n1;
        stats.hydrosphere = Score.n0;
        stats.biosphere = Score.n0;
        stats.planetGroup = 'Jovian';
        stats.planetClass = 'Chthonian';
        stats.planetType = '';
        stats.description =
            'These are Jovian worlds with masses ranging from 0.015 to 0.24 times that of Jupiter.  They are the exposed cores of Jovian worlds which have lost their gaseous envelopes through solar evaporation.  This typically occurs to older Jovians in tight solar orbits, or Jovians that have been greatly affected by the evolution of their primary sun.';

        workObj.planet.orbitStats.planetaryStats = stats;
        workObj.planet = this.response(workObj.planet, workObj.star, workObj.zone, workObj.age, workObj.techLevel, workObj.parent);
        return workObj.planet;
    }
}


getKey(): number {
        return PlanetType.Chthonian;
    }


run(workObj: PlanetTypeWorker): Orbit<IPlanet> {
        const stats = new PlanetStats();

        stats.size = Score.nG;
        stats.atmosphere = Score.n1;
        stats.hydrosphere = Score.n0;
        stats.biosphere = Score.n0;
        stats.planetGroup = 'Jovian';
        stats.planetClass = 'Chthonian';
        stats.planetType = '';
        stats.description =
            'These are Jovian worlds with masses ranging from 0.015 to 0.24 times that of Jupiter.  They are the exposed cores of Jovian worlds which have lost their gaseous envelopes through solar evaporation.  This typically occurs to older Jovians in tight solar orbits, or Jovians that have been greatly affected by the evolution of their primary sun.';

        workObj.planet.orbitStats.planetaryStats = stats;
        workObj.planet = this.response(workObj.planet, workObj.star, workObj.zone, workObj.age, workObj.techLevel, workObj.parent);
        return workObj.planet;
    }


({ size }: IconProps) => {
	return (
		<svg
			viewBox="0 0 30 30"
			xmlns="http://www.w3.org/2000/svg"
			width={size ? iconSize[size] : undefined}
		>
			<path
				fillRule="evenodd"
				clipRule="evenodd"
				d="M25.9999 8.09999C25.1249 8.47499 24.3499 8.69999 23.3749 8.82499C24.3999 8.24999 25.0749 7.4 25.3999 6.325C24.5249 6.75 23.4999 7.325 22.5249 7.4C21.6999 6.575 20.5999 6 19.1999 6C16.75 6 14.7 8.04999 14.7 10.5C14.7 10.775 14.725 11.25 14.825 11.525C11 11.325 7.87499 9.57499 5.49999 6.8C5.175 7.47499 4.9 8.27499 4.9 9.07499C4.9 10.575 5.69999 12.1 6.92499 12.825C6.52499 12.9 5.25 12.5 4.85 12.3C4.85 14.625 6.47499 16.3 8.49998 16.775C7.72499 16.975 7.12499 17.025 6.44999 16.85C7.07499 18.65 8.64998 19.95 10.65 19.95C9.14998 21.2249 7.17499 21.8999 5.075 21.9249C4.7 21.8499 4.3 21.9249 4 21.8499C5.92499 23.1249 8.42498 23.8249 10.925 23.8249C19.1999 23.8249 23.7749 16.975 23.7749 11.025C23.7749 10.85 23.7249 10.625 23.7249 10.45C24.6249 9.77499 25.3999 8.97499 25.9999 8.09999Z"
			/>
		</svg>


data => {
        this.myCareplan = data;
        // this.allCarePlan = data.other_programs;
      }


data => {
        // this.myCarePlan = data.my_programs;
        this.allCarePlan = data;
      }


message => {
      }


() => {
      this.temp = this.listData;
      this.rows = this.listData;
      this.allData = this.listAllData;
      this.loadingIndicator = false;
      this.carePlanData = this.myCareplan;

      this.isMycarePlan = true;
    }


d => {
          t = d.result.then(data => {
            if (data === 'saved' || data === true) {
              this.updateGridWithCurrentData();
            }

          });
        }


data => {
            if (data === 'saved' || data === true) {
              this.updateGridWithCurrentData();
            }

          }


(sub) => {
      if (sub) {
        sub.unsubscribe();
      }
    }


() => {
      window.dispatchEvent(new Event('resize'));
    }


ngAfterViewChecked() {
    // Check if the table size has changed,
    if (this.table && this.table.recalculate && (this.tableWrapper.nativeElement.clientWidth !== this.currentComponentWidth)) {
      this.currentComponentWidth = this.tableWrapper.nativeElement.clientWidth;
      this.table.recalculate();
      this.changeDetectorRef.detectChanges();
    }
  }


onPage(event) {
    this.gridOptions.offset = event.offset;
    this.updateGridWithCurrentData();
  }


// call this method for responsive method
updateTableNext(event) {
    this.offsetCount++;
    this.hidePrevBtn = false;
    this.gridOptions.offset = this.offsetCount;
    this.updateGridWithCurrentData();
  }


updateTablePrev(event) {
    this.offsetCount--;
    this.gridOptions.offset = this.offsetCount;
    if (this.offsetCount <= 0) {
      this.hidePrevBtn = true;
    }
    this.updateGridWithCurrentData();
  }


/**
   * This is a refactored utility function which helps to toggle the rows and helps in
   * collapsing the whole table and expanding it out as well.
   * @param row Currently clicked row. This helps in evaluating the current row and then toggling it out.
   */
toggleAndAssign(row) {
    this.table.rowDetail.toggleExpandRow(row);
    this.rowToggled = row;
  }


toggleExpandRow(row) {
    if (this.rowToggled === row || this.rowToggled === undefined) {
      this.toggleAndAssign(row);
    } else {
      this.table.rowDetail.collapseAllRows();
      this.toggleAndAssign(row);
    }
    this.dashboardHeader.emit(row);
  }


onDetailToggle(event) {
  }


updateFilter(event) {
    this.gridOptions.offset = 0;
    this.table.offset = 0;
    this.updateGridWithCurrentData();

    // let val = event.target.value;
    // val = val.toLowerCase();
    // // filter our data
    // const temp = this.temp.filter(function (d) {
    //   return d.participant_name.toLowerCase().indexOf(val) !== -1 || !val;
    // });

    // // update the rows
    // this.rows = temp;
    // this.table.offset = 0;
  }


// onChange(checked) {
//   if (checked) {
//     this.rows = this.listData;
//     this.temp = this.listData;
//     this.isMycarePlan = true;
//   }
//   else {
//     this.rows = this.allData;
//     this.temp = this.allData;
//     this.isMycarePlan = false;
//   }
// }
participantSelection(selectedCategory) {
    if (selectedCategory === '1') {
      this.rows = this.listData;
      this.temp = this.listData;
      this.isMycarePlan = true;
      this.isChecked = true;
      this.carePlanData = this.myCareplan;
      this.resetItems();

    } else if (selectedCategory === '2') {
      this.rows = this.allData;
      this.temp = this.allData;
      this.isMycarePlan = false;
      this.isChecked = false;
      this.carePlanData = this.allCarePlan;
      this.resetItems();
    }
  }


// add tags on dropdown selection
onSelection(data) {
    const temp = [];
    const program_name = [];
    const risk_name = [];
    const options = (this.isMycarePlan) ? this.myCareplan : this.allCarePlan;
    this.riskStatus = [];
    this.programNumber = [];
    this._CheckBoxService.setCheckBoxData(data);
    const newData = this._CheckBoxService.getCheckBoxData();
    // Check or Uncheck option from list
    if (data.selected) {
      for (const obj in options) {
        if (options[obj].selected !== undefined && options[obj].program_name === data) {
          options[obj].selected = true;
        }
      }
    }

    if (!data.selected) {
      for (const obj in options) {
        if (options[obj].selected !== undefined && options[obj].program_name === data) {
          options[obj].selected = false;
        }
      }
    }

    // updating table data and Checkbox data
    this.updateData(newData);
  }


// watching for changes
ngOnChanges(changes: { [propName: string]: SimpleChange }) {
    if (changes['listData'] !== undefined && this.isChecked) {
      this.rows = this.listData;
      this.temp = this.listData;
    } else if (changes['listAllData'] !== undefined) {
      if (!this.isChecked) {
        this.rows = this.listAllData;
        this.temp = this.listAllData;
      }
      this.allData = this.listAllData;
    }
  }


removeSelection(data) {
    this._CheckBoxService.removeCheckBoxData(data);
    const newData = this._CheckBoxService.getCheckBoxData();
    const options = (this.isMycarePlan) ? this.myCareplan : this.allCarePlan;
    const pgmName = [];
    this.riskStatus = [];
    this.programNumber = [];
    // uncheck data from list
    for (const obj in options) {
      if (options[obj].selected !== undefined && options[obj].program_name === data) {
        options[obj].selected = false;
      }
    }
    // uncheck data from stage list
    for (const obj in this.riskStatusDetails) {
      if (this.riskStatusDetails[obj].program_name === data) {
        this.riskStatusDetails[obj].selected = false;
      }
    }

    // updating table data and Checkbox data
    this.updateData(newData);
  }


getVitalComponentClass(status) {
    switch (status) {
      case -1: return 'vital-gray';
      case 0: return 'vital-green';
      case 1: return 'vital-orange';
      case 2: return 'vital-red';
    }
  }


ngOnInit() {

    this.userDetail = <IUserDetail>this._storage.get('userdetails');

    this.gridOptions = {
      my_patients: this.showParticipant,
      program_nums: null,
      risk_status: null,
      search_params: null,
      offset: 0
    };

    // Putting this condition as a Role based calling of services.
    // These services are not required for client admin.
    if (this.userDetail.roleType !== 'ADMIN') {

      this._userManagementService.getMyCarePlans().then(data => {
        this.myCareplan = data;
        // this.allCarePlan = data.other_programs;
      });

      this._userManagementService.getAllCarePlans().then(data => {
        // this.myCarePlan = data.my_programs;
        this.allCarePlan = data;
      });
    }

    this.subScriptions.push(
      this._pubSub.Stream.subscribe(message => {
      })
    );

    const intialData: IPatientListGridRequest = <IPatientListGridRequest>{
      offset: 0,
      my_patients: this.showParticipant,
      search_params: this.searchParticipant
    };

    this.updateGridData(intialData);

    setTimeout(() => {
      this.temp = this.listData;
      this.rows = this.listData;
      this.allData = this.listAllData;
      this.loadingIndicator = false;
      this.carePlanData = this.myCareplan;

      this.isMycarePlan = true;
    }, 2000);
  }


resetItems() {
    this._CheckBoxService.removeCompleteData();
    const newData = this._CheckBoxService.getCheckBoxData();
    // updating table data and Checkbox data
    this.updateData(newData);
  }


updateData(newData) {
    const temp = [];
    this.rows = [];
    const program_name = [];
    const risk_name = [];
    this.updatedData = [];
    this.updatedStage = [];
    this.programNumber = [];
    this.riskStatus = [];
    this.table.offset = 0;
    // seperation based on careplan or risk stage
    for (const obj in newData) {
      if ((newData[obj].program_ref_no === '0') ||
        (newData[obj].program_ref_no === '1') || (newData[obj].program_ref_no === '2') || (newData[obj].program_ref_no === '-1')) {
        risk_name.push(newData[obj].program_ref_no);
        program_name.push(newData[obj].program_name);
        this.riskStatus = risk_name;
      } else {
        temp.push(newData[obj].program_ref_no);
        program_name.push(newData[obj].program_name);
        this.programNumber = temp;
      }
    }

    // updating the count in dropdown and updating tags
    this.program_name = program_name;
    this.updatedData = this.programNumber;
    this.updatedStage = this.riskStatus;

    const selectedData = {
      data: (this.programNumber.length === 0) ? null : this.programNumber,
      risk_status: (this.riskStatus.length === 0) ? null : this.riskStatus,
      checked: this.isChecked
    };

    this.gridOptions.program_nums = selectedData.data;
    this.gridOptions.risk_status = selectedData.risk_status;
    this.gridOptions.my_patients = this.showParticipant;
    this.gridOptions.offset = 0;

    this.updateGridWithCurrentData();

    //this.selectionChange.emit(selectedData);
  }


getRowClass(row) {
    return 'danger';
  }


openInterventionModal(type, participat_id) {
    let t;
    if (type === 'vitals') {
      this._modal.open(InterventionComponent, overlayConfigFactory({ addMedicationPlan: false, participantId: participat_id },
        InterventionModalContext)).then(d => {
          t = d.result.then(data => {
            if (data === 'saved' || data === true) {
              this.updateGridWithCurrentData();
            }

          });
        });
    } else if (type === 'compliance') {
      this._modal.open(InterventionComplianceComponent, overlayConfigFactory({ addMedicationPlan: false, participantId: participat_id },
        InterventionComplianceModalContext)).then(d => {
          t = d.result.then(data => {
            if (data === 'saved' || data === true) {
              this.updateGridWithCurrentData();
            }

          });
        });
    }
  }


showMyParticipant(event) {
    this.searchParticipant = '';
    if (event) {
      this.rows = this.listData;
      this.temp = this.listData;
      this.isMycarePlan = true;
      this.isChecked = true;
      this.carePlanData = this.myCareplan;
      // this.resetItems();
    } else {
      if (this.allData) {
        this.rows = this.allData;
        this.temp = this.allData;
      }
      this.isMycarePlan = false;
      this.isChecked = false;
      this.carePlanData = this.allCarePlan;
      // this.resetItems();
    }

    const newData = this._CheckBoxService.getCheckBoxData();
    // updating table data and Checkbox data
    this.updateData(newData);
  }


isLinkDisabled(item) {
    if (item > 0) {
      return '';
    } else {
      return 'not-active';
    }
  }


unSubscribe() {
    _.forEach(this.subScriptions, (sub) => {
      if (sub) {
        sub.unsubscribe();
      }
    });
  }


showParticipantChange() {
    this.updateGridWithCurrentData();
    if (this.showParticipant) {
      this.participantSelection('1');
    } else {
      this.participantSelection('2');
    }
  }


updateGridWithCurrentData() {
    const intialData: IPatientListGridRequest = <IPatientListGridRequest>{
      offset: this.gridOptions.offset,
      my_patients: this.showParticipant,
      search_params: this.searchParticipant,
      program_nums: this.gridOptions.program_nums,
      risk_status: this.gridOptions.risk_status
    };

    this.updateGridData(intialData);
  }


// get my Participants List
async updateGridData(reqObj: IPatientListGridRequest): Promise<IPatientListGridData> {
    this.dataLoadingStarted();
    this.unSubscribe();
    try {
      const data: any = await this._userManagementService.getParticipantList(reqObj)
        .first().toPromise<IPatientListGridData>();
      this.gridData = <IPatientListGridData>data.json();
      this.dataLoadingCompleted();
    } catch (e) {
      this.dataLoadingCompleted();
    }

    return this.gridData;
  }


/**
 * Helps in order to close and open the list of participants.
 */
toggleList(i) {
    // let currentElem = document.querySelectorAll('[data-anchor]')[i];
    // currentElem.scrollIntoView();
    this.highlightedDiv = i;
    setTimeout(() => {
      window.dispatchEvent(new Event('resize'));
    }, 50);

  }


ngOnDestroy() {
    this.unSubscribe();
  }


dataLoadingStarted(): void {
    this.isDataLoading = true;
  }


dataLoadingCompleted(): void {
    this.isDataLoading = false;
  }


// call a function when key event is enter in search input
searchKeyPress(event) {
    if (event.keyCode === 13 || this.searchParticipant === '') {
      this.updateGridWithCurrentData();
    }
    return true;
  }


props => (
  <svg xmlns="http://www.w3.org/2000/svg"


(props: SvgIconProps) => (
  <SvgIcon component={SvgComponent}


export function findFile(files: Array<ResolvedUpdateFileInfo>, extension: string, not?: Array<string>): ResolvedUpdateFileInfo | null | undefined {
  if (files.length === 0) {
    throw newError("No files provided", "ERR_UPDATER_NO_FILES_PROVIDED")
  }

  const result = files.find(it => it.url.pathname.toLowerCase().endsWith(`.${extension}`))
  if (result != null) {
    return result
  } else if (not == null) {
    return files[0]
  } else {
    return files.find(fileInfo => !not.some(ext => fileInfo.url.pathname.toLowerCase().endsWith(`.${ext}`)))
  }
}


export function parseUpdateInfo(rawData: string | null, channelFile: string, channelFileUrl: URL): UpdateInfo {
  if (rawData == null) {
    throw newError(`Cannot parse update info from ${channelFile} in the latest release artifacts (${channelFileUrl}): rawData: null`, "ERR_UPDATER_INVALID_UPDATE_INFO")
  }

  let result: UpdateInfo
  try {
    result = load(rawData) as UpdateInfo
  } catch (e) {
    throw newError(
      `Cannot parse update info from ${channelFile} in the latest release artifacts (${channelFileUrl}): ${e.stack || e.message}, rawData: ${rawData}`,
      "ERR_UPDATER_INVALID_UPDATE_INFO"
    )
  }
  return result
}


export function getFileList(updateInfo: UpdateInfo): Array<UpdateFileInfo> {
  const files = updateInfo.files
  if (files != null && files.length > 0) {
    return files
  }

  // noinspection JSDeprecatedSymbols
  if (updateInfo.path != null) {
    // noinspection JSDeprecatedSymbols
    return [
      {
        url: updateInfo.path,
        sha2: (updateInfo as any).sha2,
        sha512: updateInfo.sha512,
      } as any,
    ]
  } else {
    throw newError(`No files provided: ${safeStringifyJson(updateInfo)}`, "ERR_UPDATER_NO_FILES_PROVIDED")
  }
}


export function resolveFiles(updateInfo: UpdateInfo, baseUrl: URL, pathTransformer: (p: string) => string = (p: string): string => p): Array<ResolvedUpdateFileInfo> {
  const files = getFileList(updateInfo)
  const result: Array<ResolvedUpdateFileInfo> = files.map(fileInfo => {
    if ((fileInfo as any).sha2 == null && fileInfo.sha512 == null) {
      throw newError(`Update info doesn't contain nor sha256 neither sha512 checksum: ${safeStringifyJson(fileInfo)}`, "ERR_UPDATER_NO_CHECKSUM")
    }
    return {
      url: newUrlFromBase(pathTransformer(fileInfo.url), baseUrl),
      info: fileInfo,
    }
  })

  const packages = (updateInfo as WindowsUpdateInfo).packages
  const packageInfo = packages == null ? null : packages[process.arch] || packages.ia32
  if (packageInfo != null) {
    ;(result[0] as any).packageInfo = {
      ...packageInfo,
      path: newUrlFromBase(pathTransformer(packageInfo.path), baseUrl).href,
    }
  }
  return result
}


it => it.url.pathname.toLowerCase().endsWith(`.${extension}`)


fileInfo => !not.some(ext => fileInfo.url.pathname.toLowerCase().endsWith(`.${ext}`))


ext => fileInfo.url.pathname.toLowerCase().endsWith(`.${ext}`)


(p: string): string => p


fileInfo => {
    if ((fileInfo as any).sha2 == null && fileInfo.sha512 == null) {
      throw newError(`Update info doesn't contain nor sha256 neither sha512 checksum: ${safeStringifyJson(fileInfo)}`, "ERR_UPDATER_NO_CHECKSUM")
    }
    return {
      url: newUrlFromBase(pathTransformer(fileInfo.url), baseUrl),
      info: fileInfo,
    }
  }


export abstract class Provider<T extends UpdateInfo> {
  private requestHeaders: OutgoingHttpHeaders | null = null
  protected readonly executor: HttpExecutor<any>

  protected constructor(private readonly runtimeOptions: ProviderRuntimeOptions) {
    this.executor = runtimeOptions.executor
  }

  get isUseMultipleRangeRequest(): boolean {
    return this.runtimeOptions.isUseMultipleRangeRequest !== false
  }

  private getChannelFilePrefix(): string {
    if (this.runtimeOptions.platform === "linux") {
      const arch = process.env.TEST_UPDATER_ARCH || process.arch
      const archSuffix = arch === "x64" ? "" : `-${arch}`
      return "-linux" + archSuffix
    } else if (this.runtimeOptions.platform === "darwin") {
      return "-mac"
    } else {
      const arch = process.env.TEST_UPDATER_ARCH || process.arch
      const is32 = arch === "ia32" || arch === "x32"
      return is32 ? "-win32" : ""
    }
  }

  // due to historical reasons for windows we use channel name without platform specifier
  protected getDefaultChannelName(): string {
    return this.getCustomChannelName("latest")
  }

  protected getCustomChannelName(channel: string): string {
    return `${channel}${this.getChannelFilePrefix()}`
  }

  get fileExtraDownloadHeaders(): OutgoingHttpHeaders | null {
    return null
  }

  setRequestHeaders(value: OutgoingHttpHeaders | null): void {
    this.requestHeaders = value
  }

  abstract getLatestVersion(): Promise<T>

  abstract resolveFiles(updateInfo: T): Array<ResolvedUpdateFileInfo>

  /**
   * Method to perform API request only to resolve update info, but not to download update.
   */
  protected httpRequest(url: URL, headers?: OutgoingHttpHeaders | null, cancellationToken?: CancellationToken): Promise<string | null> {
    return this.executor.request(this.createRequestOptions(url, headers), cancellationToken)
  }

  protected createRequestOptions(url: URL, headers?: OutgoingHttpHeaders | null): RequestOptions {
    const result: RequestOptions = {}
    if (this.requestHeaders == null) {
      if (headers != null) {
        result.headers = headers
      }
    } else {
      result.headers = headers == null ? this.requestHeaders : { ...this.requestHeaders, ...headers }
    }

    configureRequestUrl(url, result)
    return result
  }
}


export interface ProviderRuntimeOptions {
  isUseMultipleRangeRequest: boolean
  platform: ProviderPlatform

  executor: HttpExecutor<any>
}


export type ProviderPlatform = "darwin" | "linux" | "win32"


private getChannelFilePrefix(): string {
    if (this.runtimeOptions.platform === "linux") {
      const arch = process.env.TEST_UPDATER_ARCH || process.arch
      const archSuffix = arch === "x64" ? "" : `-${arch}`
      return "-linux" + archSuffix
    } else if (this.runtimeOptions.platform === "darwin") {
      return "-mac"
    } else {
      const arch = process.env.TEST_UPDATER_ARCH || process.arch
      const is32 = arch === "ia32" || arch === "x32"
      return is32 ? "-win32" : ""
    }
  }


// due to historical reasons for windows we use channel name without platform specifier
protected getDefaultChannelName(): string {
    return this.getCustomChannelName("latest")
  }


protected getCustomChannelName(channel: string): string {
    return `${channel}${this.getChannelFilePrefix()}`
  }


setRequestHeaders(value: OutgoingHttpHeaders | null): void {
    this.requestHeaders = value
  }


abstract getLatestVersion(): Promise<T>


abstract resolveFiles(updateInfo: T): Array<ResolvedUpdateFileInfo>


/**
   * Method to perform API request only to resolve update info, but not to download update.
   */
protected httpRequest(url: URL, headers?: OutgoingHttpHeaders | null, cancellationToken?: CancellationToken): Promise<string | null> {
    return this.executor.request(this.createRequestOptions(url, headers), cancellationToken)
  }


protected createRequestOptions(url: URL, headers?: OutgoingHttpHeaders | null): RequestOptions {
    const result: RequestOptions = {}
    if (this.requestHeaders == null) {
      if (headers != null) {
        result.headers = headers
      }
    } else {
      result.headers = headers == null ? this.requestHeaders : { ...this.requestHeaders, ...headers }
    }

    configureRequestUrl(url, result)
    return result
  }


export async function install(Vue: VueConstructor, options: any) {

  if(install.installed) {
    console.log('not installed')
    return;
  } else {

    install.installed = true;
    Vue.component('Copilot', CopilotModal);
  }

}


class Copilot {
  static install: PluginFunction<never>;
}


type ErrorHandler = (err: Error) => void;


/**
 * This class represents the lazy loaded HomeComponent.
 */
@Component({
  moduleId: module.id,
  selector: 'sd-home',
  templateUrl: 'home.component.html',
  // styleUrls: ['home.component.css'],
  directives: [REACTIVE_FORM_DIRECTIVES, DataTable]
})
export class HomeComponent implements OnInit {

  newName: string = '';
  errorMessage: string;
  names: any[] = [];

  /**
   * Creates an instance of the HomeComponent with the injected
   * NameListService.
   *
   * @param {NameListService} nameListService - The injected NameListService.
   */
  constructor() {}

  /**
   * Get the names OnInit
   */
  ngOnInit() {

  }

}


/**
   * Get the names OnInit
   */
ngOnInit() {

  }


(props) => {
  const [userInfo, setUserInfo] = useState<Record<string, HelixUser>>({});
  const { config, addQuickButton, setLiveItems } = useContext(ConfigContext);
  const channelNames = new Set(
    config.liveState.liveItems.map((item) => item.channelName)
  );
  useEffect(() => {
    if (!config.liveState.liveItems.length) {
      return;
    }
    getUserInfo([...channelNames]).then((info) => {
      const userInfo: Record<string, HelixUser> = {};
      for (const channel of info) {
        if (channel) {
          userInfo[channel.login] = channel;
        }
      }
      setUserInfo(userInfo);
    });
  }, [Array.from(channelNames).join(":")]);
  const isBroadcaster = Auth.isBroadcaster && !props.disableEdits;
  const {
    liveItems: items,
    listOptions,
    styles: { fontFamily },
  } = config.liveState;

  return (
    <div className={styles.followList} style={{ fontFamily }}


(item) => item.channelName


() => {
    if (!config.liveState.liveItems.length) {
      return;
    }
    getUserInfo([...channelNames]).then((info) => {
      const userInfo: Record<string, HelixUser> = {};
      for (const channel of info) {
        if (channel) {
          userInfo[channel.login] = channel;
        }
      }
      setUserInfo(userInfo);
    });
  }


(info) => {
      const userInfo: Record<string, HelixUser> = {};
      for (const channel of info) {
        if (channel) {
          userInfo[channel.login] = channel;
        }
      }
      setUserInfo(userInfo);
    }


(item) => {
          return (
            <li key={item.id}>
              <FollowButton
                channelLogin={item.channelName}
                forceTemplate="HEART"
                disableTheme
                onClick={props.onFollowClick}
              />{" "}
              {listOptions.showAvatars && (
                <img
                  src={userInfo[item.channelName]?.profile_image_url}
                  className={styles.avatar}
                />


() =>
                    setLiveItems(items.filter((i) => i.id !== item.id))


(i) => i.id !== item.id


interface Props {
  onFollowClick?: () => void;
  disableEdits?: boolean;
}


export function useSnackbar(defaultOptions: UseSnackbarOptions = defaults) {
  const toast = useToast(defaultOptions)

  const parseOptions = React.useCallback(
    (options: SnackbarOptions): UseToastOptions => {
      if (typeof options === 'string') {
        return {
          title: options,
        }
      }
      return options
    },
    []
  )

  return React.useMemo(() => {
    const snackbar = (options: SnackbarOptions): ToastId | undefined => {
      const opts = parseOptions(options)
      return toast({
        render: (props) => (
          <Snackbar {...defaultOptions} {...opts} {...props} />
        ),
        ...opts,
      }


(props) => {
  const styles = useStyles()
  return (
    <chakra.span
      display="inherit"
      {...props}
      alignItems="center"
      __css={styles.icon}
    >
      <Spinner size="sm" />
    </chakra.span>


(props) => {
  const {
    status,
    variant,
    id,
    title,
    icon,
    isClosable,
    onClose,
    description,
    action,
  } = props

  const theme = useTheme()

  // Use the snackbar variant if it exists, otherwise default to solid
  const defaultVariant = theme.components?.Alert?.variants?.snackbar
    ? 'snackbar'
    : 'solid'

  const alertTitleId =
    typeof id !== 'undefined' ? `toast-${id}-title` : undefined

  return (
    <Alert
      status={status}
      variant={variant || defaultVariant}


(options: SnackbarOptions): UseToastOptions => {
      if (typeof options === 'string') {
        return {
          title: options,
        }
      }
      return options
    }


() => {
    const snackbar = (options: SnackbarOptions): ToastId | undefined => {
      const opts = parseOptions(options)
      return toast({
        render: (props) => (
          <Snackbar {...defaultOptions} {...opts} {...props} />
        ),


(options: SnackbarOptions): ToastId | undefined => {
      const opts = parseOptions(options)
      return toast({
        render: (props) => (
          <Snackbar {...defaultOptions} {...opts} {...props} />
        ),


(props) => (
          <Snackbar {...defaultOptions}


(options: SnackbarOptions) =>
      snackbar({
        status: 'info',
        ...parseOptions(options),
      })


(options: SnackbarOptions) =>
      snackbar({
        status: 'success',
        ...parseOptions(options),
      })


(options: SnackbarOptions) =>
      snackbar({
        status: 'error',
        ...parseOptions(options),
      })


async (
      promise: Promise<any>,
      { loading, success, error }: SnackbarPromiseOptions
    ) => {
      let toastId: ToastId | undefined
      if (loading) {
        const options = parseOptions(loading)
        toastId = snackbar({
          status: 'info',
          duration: null,
          icon: <AlertSpinner color="white" />,
          ...options,
        })
      }
      promise
        .then(() => {
          const options = parseOptions(success)
          if (toastId) {
            snackbar.update(toastId, {
              status: 'success',
              ...options,
            })
          } else {
            snackbar(options)
          }
        })
        .catch((error) => {
          const options: UseToastOptions = {
            title: error.name,
            description: error.description,
            status: 'error',
          }
          if (toastId) {
            snackbar.update(toastId, options)
          } else {
            snackbar(options)
          }
        })
    }


() => {
          const options = parseOptions(success)
          if (toastId) {
            snackbar.update(toastId, {
              status: 'success',
              ...options,
            })
          } else {
            snackbar(options)
          }
        }


(error) => {
          const options: UseToastOptions = {
            title: error.name,
            description: error.description,
            status: 'error',
          }
          if (toastId) {
            snackbar.update(toastId, options)
          } else {
            snackbar(options)
          }
        }


(toastId: ToastId, options: UseToastOptions) => {
      return toast.update(toastId, {
        render: (props) => (
          <Snackbar {...defaultOptions} {...options} {...props} />
        ),
        ...options,
      }


interface UseSnackbarOptions extends UseToastOptions {
  icon?: React.ReactNode
  action?: React.ReactNode
  variant?:
    | 'snackbar'
    | 'subtle'
    | 'solid'
    | 'left-accent'
    | 'top-accent'
    | string
}


export interface SnackbarPromiseOptions {
  loading?: SnackbarOptions
  success: SnackbarOptions
  error: any
}


type SnackbarOptions = UseSnackbarOptions | string


() => {
  let component: IdiomasPage;
  let fixture: ComponentFixture<IdiomasPage>;

  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      declarations: [ IdiomasPage ],
      imports: [IonicModule.forRoot()]
    }).compileComponents();

    fixture = TestBed.createComponent(IdiomasPage);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }));

  it('should create', () => {
    expect(component).toBeTruthy();
  });
}


() => {
    TestBed.configureTestingModule({
      declarations: [ IdiomasPage ],
      imports: [IonicModule.forRoot()]
    }).compileComponents();

    fixture = TestBed.createComponent(IdiomasPage);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }


/* ------------------------------------------------------------------- */
/*                              Config
/* ------------------------------------------------------------------- */
// =====> Component config
@Component({
  selector: 'app-settings',
  styleUrls: ['./settings.component.sass'],
  templateUrl: './settings.component.html'
})

/* ------------------------------------------------------------------- */
/*                              Component
/* ------------------------------------------------------------------- */

export class SettingsComponent implements OnInit {

  /* ------------------------------------------------------------------- */
  /*                           Constructor
  /* ------------------------------------------------------------------- */

  public constructor() { }

  /* ------------------------------------------------------------------- */
  /*                            Lifecycle
  /* ------------------------------------------------------------------- */

  ngOnInit() {
  }

}


/* ------------------------------------------------------------------- */
/*                            Lifecycle
  /* ------------------------------------------------------------------- */
ngOnInit() {
  }


() => AuthorBioWhereUniqueInput


() => AuthorBioUpdateWithoutAuthorInput


() => AuthorBioCreateWithoutAuthorInput


@InputType()
export class AuthorBioUpsertWithWhereUniqueWithoutAuthorInput {

    @Field(() => AuthorBioWhereUniqueInput, {nullable:false})
    where!: AuthorBioWhereUniqueInput;

    @Field(() => AuthorBioUpdateWithoutAuthorInput, {nullable:false})
    update!: AuthorBioUpdateWithoutAuthorInput;

    @Field(() => AuthorBioCreateWithoutAuthorInput, {nullable:false})
    create!: AuthorBioCreateWithoutAuthorInput;
}


(authState) => {
      if (!authState.isLoggedIn) {
        this.router.navigate([this.routePath]);
      }
    }


/**
 * Component Class
 */
@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit, OnDestroy {

  /**
   * Authentication Service subscription
   */
  authServiceSubscription: any;

  /**
   * Path for routing
   */
  routePath = '/auth/login';

  /**
   * Constructor.
   * @param endpointsService  EndpointService Injection.
   * @param route  ActivatedRoute Injection.
   * @param router  Router Injection.
   * @param globalService  GlobalService Injection.
   * @param apiService  ApiService Injection.
   * @param authService  AuthService Injection.
   */
  constructor(private apiService: ApiService,
              public authService: AuthService,
              private globalService: GlobalService,
              private router: Router,
              private route: ActivatedRoute,
              private endpointsService: EndpointsService) { }

  /**
   * Component on initialized.
   */
  ngOnInit() {
    if (!this.authService.isLoggedIn()) {
      this.router.navigate([this.routePath]);
    }
    this.authServiceSubscription = this.authService.change.subscribe((authState) => {
      if (!authState.isLoggedIn) {
        this.router.navigate([this.routePath]);
      }
    });
  }

  ngOnDestroy(): void {
    if (this.authServiceSubscription) {
      this.authServiceSubscription.unsubscribe();
    }
  }

}


/**
   * Component on initialized.
   */
ngOnInit() {
    if (!this.authService.isLoggedIn()) {
      this.router.navigate([this.routePath]);
    }
    this.authServiceSubscription = this.authService.change.subscribe((authState) => {
      if (!authState.isLoggedIn) {
        this.router.navigate([this.routePath]);
      }
    });
  }


ngOnDestroy(): void {
    if (this.authServiceSubscription) {
      this.authServiceSubscription.unsubscribe();
    }
  }


export default function OfficerDashboard({
  bolos,
  calls,
  activeOfficer,
  activeIncidents,

  allOfficers,
  allDeputies,
}: Props) {
  const leoState = useLeoState();
  const dispatchState = useDispatchState();
  const t = useTranslations("Leo");
  const { signal100Enabled, Component, audio: signal100Audio } = useSignal100();
  const { unit, audio, PanicButton } = usePanicButton();
  const { isOpen } = useModal();
  const { user } = useAuth();

  const { currentResult, setCurrentResult } = useNameSearch();

  function handleRecordCreate(data: Record) {
    if (!currentResult) return;

    setCurrentResult({
      ...currentResult,
      Record: [data, ...currentResult.Record],
    });
  }

  React.useEffect(() => {
    leoState.setActiveOfficer(activeOfficer);

    dispatchState.setCalls(calls);
    dispatchState.setBolos(bolos);

    dispatchState.setActiveIncidents(activeIncidents);
    dispatchState.setAllOfficers(allOfficers);

    function activeFilter(v: EmsFdDeputy | Officer) {
      return Boolean(v.statusId && v.status?.shouldDo !== ShouldDoType.SET_OFF_DUTY);
    }

    const activeOfficers = [...allOfficers].filter(activeFilter);
    const activeDeputies = [...allDeputies].filter(activeFilter);

    dispatchState.setActiveDeputies(activeDeputies);
    dispatchState.setActiveOfficers(activeOfficers);

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [bolos, calls, allOfficers, allDeputies, activeOfficer]);

  React.useEffect(() => {
    if (!user) return;
    const userOfficers = allOfficers.filter((v) => v.userId === user.id);

    leoState.setOfficers(userOfficers);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [user, allOfficers]);

  return (
    <Layout
      permissions={{ fallback: (u) => u.isLeo, permissions: [Permissions.Leo] }}


function handleRecordCreate(data: Record) {
    if (!currentResult) return;

    setCurrentResult({
      ...currentResult,
      Record: [data, ...currentResult.Record],
    });
  }


function activeFilter(v: EmsFdDeputy | Officer) {
      return Boolean(v.statusId && v.status?.shouldDo !== ShouldDoType.SET_OFF_DUTY);
    }


async () => {
    return (await import("components/leo/modals/CreateWarrantModal")).CreateWarrantModal;
  }


async () => {
    return (await import("components/leo/modals/CustomFieldSearch/CustomFieldSearch"))
      .CustomFieldSearch;
  }


async () => {
    return (await import("components/leo/modals/NameSearchModal/NameSearchModal")).NameSearchModal;
  }


async () => {
    return (await import("components/leo/modals/VehicleSearchModal")).VehicleSearchModal;
  }


async () => {
    return (await import("components/leo/modals/WeaponSearchModal")).WeaponSearchModal;
  }


async () => {
    return (await import("components/shared/NotepadModal")).NotepadModal;
  }


async () => {
    return (await import("components/leo/modals/SelectOfficerModal")).SelectOfficerModal;
  }


async () => {
    return (await import("components/leo/modals/ManageRecordModal")).ManageRecordModal;
  }


() => {
    leoState.setActiveOfficer(activeOfficer);

    dispatchState.setCalls(calls);
    dispatchState.setBolos(bolos);

    dispatchState.setActiveIncidents(activeIncidents);
    dispatchState.setAllOfficers(allOfficers);

    function activeFilter(v: EmsFdDeputy | Officer) {
      return Boolean(v.statusId && v.status?.shouldDo !== ShouldDoType.SET_OFF_DUTY);
    }

    const activeOfficers = [...allOfficers].filter(activeFilter);
    const activeDeputies = [...allDeputies].filter(activeFilter);

    dispatchState.setActiveDeputies(activeDeputies);
    dispatchState.setActiveOfficers(activeOfficers);

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }


() => {
    if (!user) return;
    const userOfficers = allOfficers.filter((v) => v.userId === user.id);

    leoState.setOfficers(userOfficers);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }


(v) => v.userId === user.id


(u) => u.isLeo


async ({ req, locale }) => {
  const adminValuesURL =
    "/admin/values/codes_10?paths=penal_code,impound_lot,license,driverslicense_category,vehicle_flag,citizen_flag";

  const [
    activeOfficer,
    values,
    calls,
    bolos,
    { officers: allOfficers, deputies: allDeputies, activeIncidents },
  ] = await requestAll(req, [
    ["/leo/active-officer", null],
    [adminValuesURL, []],
    ["/911-calls", []],
    ["/bolos", []],
    ["/dispatch", { officers: [], deputies: [], activeIncidents: [] }],
  ]);

  return {
    props: {
      session: await getSessionUser(req),
      allOfficers,
      allDeputies,
      activeOfficer,
      calls,
      bolos,
      values,
      activeIncidents,
      messages: {
        ...(await getTranslations(
          ["citizen", "leo", "truck-logs", "ems-fd", "calls", "common"],
          locale,
        )),
      },
    },
  };
}


interface Props {
  activeOfficer: ActiveOfficer | null;
  calls: Full911Call[];
  bolos: Bolo[];
  activeIncidents: LeoIncident[];

  allDeputies: EmsFdDeputy[];
  allOfficers: Officer[];
}


t("officer")


() => {
  let component: NewInvoiceComponent;
  let fixture: ComponentFixture<NewInvoiceComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ NewInvoiceComponent ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(NewInvoiceComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
}


() => {
    TestBed.configureTestingModule({
      declarations: [ NewInvoiceComponent ]
    })
    .compileComponents();
  }


() => {
    fixture = TestBed.createComponent(NewInvoiceComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  }


() => {
  const queryClient = new QueryClient();

  it('Skal inneholde checkbokser med riktige labels', () => {
    const component = render(
      <QueryClientProvider client={queryClient}>
        <HendelseTypeFilter />
      </QueryClientProvider>
    );

    const onskerMoteCheckbox = component.getByRole('checkbox', {
      name: /Ønsker møte/,
      checked: false,
    });
    expect(onskerMoteCheckbox).to.exist;

    const svarMoteCheckbox = component.getByRole('checkbox', {
      name: /Svar møteplanlegger/,
      checked: false,
    });
    expect(svarMoteCheckbox).to.exist;

    const ufordelteCheckbox = component.getByRole('checkbox', {
      name: /Ufordelte brukere/,
      checked: false,
    });
    expect(ufordelteCheckbox).to.exist;

    const arbeidsgiverCheckbox = component.getByRole('checkbox', {
      name: /Arbeidsgiver ønsker bistand/,
      checked: false,
    });
    expect(arbeidsgiverCheckbox).to.exist;
  });
}


() => {
    const component = render(
      <QueryClientProvider client={queryClient}>
        <HendelseTypeFilter />
      </QueryClientProvider>
    );

    const onskerMoteCheckbox = component.getByRole('checkbox', {
      name: /Ønsker møte/,
      checked: false,
    });
    expect(onskerMoteCheckbox).to.exist;

    const svarMoteCheckbox = component.getByRole('checkbox', {
      name: /Svar møteplanlegger/,
      checked: false,
    });
    expect(svarMoteCheckbox).to.exist;

    const ufordelteCheckbox = component.getByRole('checkbox', {
      name: /Ufordelte brukere/,
      checked: false,
    });
    expect(ufordelteCheckbox).to.exist;

    const arbeidsgiverCheckbox = component.getByRole('checkbox', {
      name: /Arbeidsgiver ønsker bistand/,
      checked: false,
    });
    expect(arbeidsgiverCheckbox).to.exist;
  }


(url: string) => {
  const precacheController = getOrCreatePrecacheController();
  return precacheController.createHandlerForURL(url);
}


export default function Home() {
  return (

      <ExperienceBar/>

            <Profile/>
            <CompletedChallenges/>
            <Countdown/>

  )
}


function reshapeTo2D(src, num_col_dims) {
    const [n, c, h, w] = src;
    // 小于等于二维
    if (n === 1 && c === 1) {
        return [
            [1, 1, h],
            3,
            [w],
            1,
            [h, w]
        ];
    }

    const part1 = src.slice(0, num_col_dims);
    const part2 = src.slice(num_col_dims);

    return [
        part1,
        part1.length,
        part2,
        part2.length,
        [part1.reduce((all, num) => all * num), part2.reduce((all, num) => all * num)]
    ];
}


function getTensorPosFromArrayIndex(name, numbers_shape, length_shape) {
    if (length_shape === 1) {
        return `
            int getTensorPosFromArrayIndex_${name}(int n) {
                return calMod(n, ${numbers_shape[0]});
            }
        `;
    }

    const shape = reduceShape(numbers_shape);
    shape.push(1);
    const shapeVec = `ivec${length_shape}(${shape.join(', ')})`;
    return `
    ivec${length_shape} shapeVec_${name} = ${shapeVec};
    ivec${length_shape} getTensorPosFromArrayIndex_${name}(int n) {
        ivec${length_shape} pos;
        pos[0] = n / shapeVec_${name}[0];
        for (int i = 1; i < ${length_shape}; i++) {
            n = calMod(n, shapeVec_${name}[i - 1]);
            pos[i] = n / shapeVec_${name}[i];
        }
        return pos;
    }
    `;
}


function getVecType(len) {
    return len === 1 ? 'int' : 'ivec' + len;
}


function recoverShape({ total_shape, channel, height_shape, width_shape }) {
    return [total_shape / channel / height_shape / width_shape, channel, height_shape, width_shape];
}


function mainFunc(
    { origin, weight },
    { x_num_col_dims, y_num_col_dims }
) {
    // flatten
    const xShape = recoverShape(origin);
    const yShape = recoverShape(weight);

    const [x1, x1Len, x2, x2Len, x2d] = reshapeTo2D(xShape, x_num_col_dims);
    const [y1, y1Len, y2, y2Len] = reshapeTo2D(yShape, y_num_col_dims);

    const getTensorPosFromArrayIndex_x1 = getTensorPosFromArrayIndex('x1', x1, x1Len);
    const getTensorPosFromArrayIndex_x2 = getTensorPosFromArrayIndex('x2', x2, x2Len);
    const getTensorPosFromArrayIndex_y1 = getTensorPosFromArrayIndex('y1', y1, y1Len);
    const getTensorPosFromArrayIndex_y2 = getTensorPosFromArrayIndex('y2', y2, y2Len);

    return `
    ${getTensorPosFromArrayIndex_x1}
    ${getTensorPosFromArrayIndex_x2}
    ${getTensorPosFromArrayIndex_y1}
    ${getTensorPosFromArrayIndex_y2}

    // start函数
    void main(void) {
        float res = 0.0;
        // 获取output的坐标
        ivec4 opos = getOutputTensorPos();
        float bias = getValueFromTensorPos_bias(opos.r, opos.g, opos.b, opos.a);
        float temp = 0.0;

        // output is 2D
        int b = opos.b;
        int a = opos.a;

        ${getVecType(x1Len)} x1 = getTensorPosFromArrayIndex_x1(b);
        ${getVecType(y2Len)} y2 = getTensorPosFromArrayIndex_y2(a);

        for (int j = 0; j < ${x2d[1]}; j++) {
            ${getVecType(x2Len)} x2 = getTensorPosFromArrayIndex_x2(j);
            ${getVecType(y1Len)} y1 = getTensorPosFromArrayIndex_y1(j);

            ivec4 xPos = ivec4(${getVecType(x1Len)}(x1), ${getVecType(x2Len)}(x2));
            ivec4 yPos = ivec4(${getVecType(y1Len)}(y1), ${getVecType(y2Len)}(y2));

            float o = getValueFromTensorPos_origin(xPos.r, xPos.g, xPos.b, xPos.a);
            float c = getValueFromTensorPos_weight(yPos.r, yPos.g, yPos.b, yPos.a);
            res += c * o;
        }

        res = res + bias;
        setOutput(res);
    }
    `;
}


(all, num) => all * num


export function use(middleware: RequestHandler) {
  return function (target: any, key: string, desc: PropertyDescriptor) {
    const middlewares =
      Reflect.getMetadata(MetaDataKeys.MIDDLEWARE, target, key) || [];

    Reflect.defineMetadata(
      MetaDataKeys.MIDDLEWARE,
      [...middlewares, middleware],
      target,
      key
    );
  };
}


link => {
        assert.deepStrictEqual(sanitizeAttributes(link.attributes), link.attributes);
      }


() => {
    const contextManager = new TestStackContextManager().enable();
    context.setGlobalContextManager(contextManager);
  }


() => {
    context.disable();
    delete envSource.OTEL_TRACES_SAMPLER;
    delete envSource.OTEL_TRACES_SAMPLER_ARG;
  }


() => {
    const tracer = new Tracer(
      { name: 'default', version: '0.0.1' },
      {},
      tracerProvider
    );
    assert.ok(tracer instanceof Tracer);
  }


() => {
    const tracer = new Tracer(
      { name: 'default', version: '0.0.1' },
      {},
      tracerProvider
    );
    assert.strictEqual(
      tracer['_sampler'].toString(),
      'ParentBased{root=AlwaysOnSampler, remoteParentSampled=AlwaysOnSampler, remoteParentNotSampled=AlwaysOffSampler, localParentSampled=AlwaysOnSampler, localParentNotSampled=AlwaysOffSampler}'
    );
  }


() => {
    const tracer = new Tracer(
      { name: 'default', version: '0.0.1' },
      { sampler: new AlwaysOffSampler() },
      tracerProvider
    );
    const span = tracer.startSpan('span1');
    assert.ok(!span.isRecording());
    span.end();
  }


() => {
    const tracer = new Tracer(
      { name: 'default', version: '0.0.1' },
      { sampler: new AlwaysOnSampler() },
      tracerProvider
    );
    const span = tracer.startSpan('span2');
    assert.ok(span.isRecording());
    span.end();
  }


() => {
    const tracer = new Tracer(
      { name: 'default', version: '0.0.1' },
      { sampler: new TestSampler() },
      tracerProvider
    );
    const span = tracer.startSpan('span3');
    assert.strictEqual((span as Span).attributes.testAttribute, 'foobar');
    span.end();
  }


() => {
    const tracer = new Tracer(
      { name: 'default', version: '0.0.1' },
      {},
      tracerProvider
    );

    const lib: InstrumentationLibrary = tracer.instrumentationLibrary;

    assert.strictEqual(lib.name, 'default');
    assert.strictEqual(lib.version, '0.0.1');
  }


() => {
    const context = suppressTracing(ROOT_CONTEXT);

    it('should return cached no-op span ', done => {
      const tracer = new Tracer(
        { name: 'default', version: '0.0.1' },
        { sampler: new TestSampler() },
        tracerProvider
      );

      const span = tracer.startSpan('span3', undefined, context);

      assert.ok(!span.isRecording());
      span.end();

      done();
    });
  }


done => {
      const tracer = new Tracer(
        { name: 'default', version: '0.0.1' },
        { sampler: new TestSampler() },
        tracerProvider
      );

      const span = tracer.startSpan('span3', undefined, context);

      assert.ok(!span.isRecording());
      span.end();

      done();
    }


() => {
    const parent: SpanContext = {
      traceId: '00112233445566778899001122334455',
      spanId: '0011223344556677',
      traceFlags: TraceFlags.SAMPLED,
    };
    const tracer = new Tracer(
      { name: 'default', version: '0.0.1' },
      {},
      tracerProvider
    );
    const span = tracer.startSpan(
      'aSpan',
      undefined,
      trace.setSpanContext(ROOT_CONTEXT, parent)
    );
    assert.strictEqual((span as Span).parentSpanId, parent.spanId);
    assert.strictEqual(span.spanContext().traceId, parent.traceId);
  }


() => {
    const parent: SpanContext = {
      traceId: INVALID_TRACEID,
      spanId: '0011223344556677',
      traceFlags: TraceFlags.SAMPLED,
    };
    const tracer = new Tracer(
      { name: 'default', version: '0.0.1' },
      {},
      tracerProvider
    );
    const span = tracer.startSpan(
      'aSpan',
      undefined,
      trace.setSpanContext(ROOT_CONTEXT, parent)
    );
    assert.strictEqual((span as Span).parentSpanId, undefined);
  }