/**
 *
 * @export
 * @interface FalconxStream
 */
export interface FalconxStream {
    /**
     *
     * @type {boolean}
     * @memberof FalconxStream
     */
    executed?: boolean;
    /**
     *
     * @type {string}
     * @memberof FalconxStream
     */
    fileName?: string;
    /**
     *
     * @type {string}
     * @memberof FalconxStream
     */
    humanKeywords?: string;
    /**
     *
     * @type {string}
     * @memberof FalconxStream
     */
    instructionsArtifactId?: string;
    /**
     *
     * @type {Array<FalconxMatchedSignature>}
     * @memberof FalconxStream
     */
    matchedSignatures?: Array<FalconxMatchedSignature>;
    /**
     *
     * @type {string}
     * @memberof FalconxStream
     */
    uid?: string;
}


/** @soyCompatible */
@customElement('md-radio')
export class MdRadio extends Radio {
  static override styles = [styles];
}


interface HTMLElementTagNameMap {
    'md-radio': MdRadio;
  }


(arr: number[]) => {
  for (let i: number = 0; i < arr.length; ++i) {
    for (let j: number = i + 1; j < arr.length; ++j) {
      if (
        Math.pow(arr[i], 2) + Math.pow(arr[j], 2) ===
        Math.pow(arr[j + 1], 2)
      ) {
        return true;
      }
    }
  }
  return false;
}


(sectionNumber: number) =>
  `[data-testid="section-list-section"]:nth-child(${sectionNumber})`


(sectionNumber: number, itemNumber: number) =>
  `[data-testid="section-list-section"]:nth-child(${sectionNumber}) [data-testid="section-items-item"]:nth-child(${itemNumber})`


() => {
  before(() => {
    cy.visit('/menu/11ca8caa-e5dc-494d-bcfd-79fdeb34b1b1')
  })

  it('display menu details', () => {
    cy.get('h2[data-testid="menu-detail-card-title"]')
      .first()
      .should('contain', 'Cafe comfort and waffles')

    cy.get('p[data-testid="menu-detail-card-description"]')
      .first()
      .should(
        'contain',
        "The cafe is all about food to make you feel better when you can't face the world or feel like you are going crazy. Have an all day breakfast, your mothers Sunday roast or help yourself to the biggest bowl of ice-cream will lots of extras"
      )
  })

  it('display sections', () => {
    cy.get('[data-testid="section-list"]').should('be.visible')
    cy.get('[data-testid="section-list-section"]').should('have.length', 2)
  })

  describe('Main menu', () => {
    it('show the main section title and description first', () => {
      cy.get(sectionSel(1)).within(() => {
        cy.get('[data-testid="section-title"]').should('contain', 'Main')
        cy.get('[data-testid="section-description"]').should(
          'contain',
          'Stuff to fill you up'
        )
      })
    })

    it('has one item in the main section', () => {
      cy.get(`${sectionSel(1)} [data-testid="item-card"]`).should(
        'have.length',
        1
      )
    })

    it('first main section item is a bowl of sausages', () => {
      cy.get(sectionItemSel(1, 1)).within(() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Plate of sausages'
        )
        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'Big bowl of sausages'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      })
    })
  })

  describe('Desert', () => {
    it('show the desert section title and description second', () => {
      cy.get(sectionSel(2)).within(() => {
        cy.get('[data-testid="section-title"]').should('contain', 'Desert')

        cy.get('[data-testid="section-description"]').should(
          'contain',
          'The best stuff'
        )
      })
    })

    it('has 2 items in the desert section', () => {
      cy.get(`${sectionSel(2)} [data-testid="item-card"]`).should(
        'have.length',
        2
      )
    })

    it('1st desert item is Chocolate ice-cream surprise', () => {
      cy.get(sectionItemSel(2, 1)).within(() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Chocolate ice-cream surprise'
        )

        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'An amazing mixture of chocolate and cherries'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      })
    })

    it('2nd desert item is a bowl of cherries', () => {
      cy.get(sectionItemSel(2, 2)).within(() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Bowl of cherries'
        )

        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'Big bowl of cherries'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      })
    })
  })
}


() => {
    cy.visit('/menu/11ca8caa-e5dc-494d-bcfd-79fdeb34b1b1')
  }


() => {
    cy.get('h2[data-testid="menu-detail-card-title"]')
      .first()
      .should('contain', 'Cafe comfort and waffles')

    cy.get('p[data-testid="menu-detail-card-description"]')
      .first()
      .should(
        'contain',
        "The cafe is all about food to make you feel better when you can't face the world or feel like you are going crazy. Have an all day breakfast, your mothers Sunday roast or help yourself to the biggest bowl of ice-cream will lots of extras"
      )
  }


() => {
    cy.get('[data-testid="section-list"]').should('be.visible')
    cy.get('[data-testid="section-list-section"]').should('have.length', 2)
  }


() => {
    it('show the main section title and description first', () => {
      cy.get(sectionSel(1)).within(() => {
        cy.get('[data-testid="section-title"]').should('contain', 'Main')
        cy.get('[data-testid="section-description"]').should(
          'contain',
          'Stuff to fill you up'
        )
      })
    })

    it('has one item in the main section', () => {
      cy.get(`${sectionSel(1)} [data-testid="item-card"]`).should(
        'have.length',
        1
      )
    })

    it('first main section item is a bowl of sausages', () => {
      cy.get(sectionItemSel(1, 1)).within(() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Plate of sausages'
        )
        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'Big bowl of sausages'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      })
    })
  }


() => {
      cy.get(sectionSel(1)).within(() => {
        cy.get('[data-testid="section-title"]').should('contain', 'Main')
        cy.get('[data-testid="section-description"]').should(
          'contain',
          'Stuff to fill you up'
        )
      })
    }


() => {
        cy.get('[data-testid="section-title"]').should('contain', 'Main')
        cy.get('[data-testid="section-description"]').should(
          'contain',
          'Stuff to fill you up'
        )
      }


() => {
      cy.get(`${sectionSel(1)} [data-testid="item-card"]`).should(
        'have.length',
        1
      )
    }


() => {
      cy.get(sectionItemSel(1, 1)).within(() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Plate of sausages'
        )
        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'Big bowl of sausages'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      })
    }


() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Plate of sausages'
        )
        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'Big bowl of sausages'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      }


() => {
    it('show the desert section title and description second', () => {
      cy.get(sectionSel(2)).within(() => {
        cy.get('[data-testid="section-title"]').should('contain', 'Desert')

        cy.get('[data-testid="section-description"]').should(
          'contain',
          'The best stuff'
        )
      })
    })

    it('has 2 items in the desert section', () => {
      cy.get(`${sectionSel(2)} [data-testid="item-card"]`).should(
        'have.length',
        2
      )
    })

    it('1st desert item is Chocolate ice-cream surprise', () => {
      cy.get(sectionItemSel(2, 1)).within(() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Chocolate ice-cream surprise'
        )

        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'An amazing mixture of chocolate and cherries'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      })
    })

    it('2nd desert item is a bowl of cherries', () => {
      cy.get(sectionItemSel(2, 2)).within(() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Bowl of cherries'
        )

        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'Big bowl of cherries'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      })
    })
  }


() => {
      cy.get(sectionSel(2)).within(() => {
        cy.get('[data-testid="section-title"]').should('contain', 'Desert')

        cy.get('[data-testid="section-description"]').should(
          'contain',
          'The best stuff'
        )
      })
    }


() => {
        cy.get('[data-testid="section-title"]').should('contain', 'Desert')

        cy.get('[data-testid="section-description"]').should(
          'contain',
          'The best stuff'
        )
      }


() => {
      cy.get(`${sectionSel(2)} [data-testid="item-card"]`).should(
        'have.length',
        2
      )
    }


() => {
      cy.get(sectionItemSel(2, 1)).within(() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Chocolate ice-cream surprise'
        )

        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'An amazing mixture of chocolate and cherries'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      })
    }


() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Chocolate ice-cream surprise'
        )

        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'An amazing mixture of chocolate and cherries'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      }


() => {
      cy.get(sectionItemSel(2, 2)).within(() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Bowl of cherries'
        )

        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'Big bowl of cherries'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      })
    }


() => {
        cy.get('[data-testid="item-card-title"]').should(
          'contain',
          'Bowl of cherries'
        )

        cy.get('[data-testid="item-card-description"]').should(
          'contain',
          'Big bowl of cherries'
        )

        cy.get('[data-testid="item-card-image"]')
          .should('have.css', 'background-image')
          .and(
            'contain',
            'url("http://localhost:3000/images/default-thumbnail.png")'
          )
      }


@Injectable()
export class TasksService {
    constructor(
       @InjectRepository(Task)
       private tasksRepository: Repository<Task>,
       private usersService: UsersService,
    ) {}

    async createTask(createTaskDto: CreateTaskDto): Promise<Task> {
        const task = {...new Task(), ...createTaskDto, deadlineTime: new Date(Date.now() + 2*24*60*60*1000)}
        try {
            task.executor = await this.usersService.findOne('27');
            return await this.tasksRepository.save(task);

        } catch(e) {
            throw new HttpException({
                status: HttpStatus.FORBIDDEN,
                error: e.message,
            }, HttpStatus.FORBIDDEN)
        }
    }

    async getUsersAllTasks(userId: number) {
        return await this.tasksRepository.find({where: {executor: userId}})
    }

    async getOneTaskById(id: number): Promise<Task> {
        const task = await this.tasksRepository.findOne(id)
        if (task === undefined) {
            throw new HttpException({
                status: HttpStatus.NOT_FOUND,
                error: 'Task is not found'
            }, HttpStatus.NOT_FOUND)
        }
        return task
    }

    async addExecutor(updateTaskDto: UpdateTaskDto) {

    }

    async getTasks(): Promise<Task[]> {
        return this.tasksRepository.find({cache: 60000})
    }
}


async createTask(createTaskDto: CreateTaskDto): Promise<Task> {
        const task = {...new Task(), ...createTaskDto, deadlineTime: new Date(Date.now() + 2*24*60*60*1000)}
        try {
            task.executor = await this.usersService.findOne('27');
            return await this.tasksRepository.save(task);

        } catch(e) {
            throw new HttpException({
                status: HttpStatus.FORBIDDEN,
                error: e.message,
            }, HttpStatus.FORBIDDEN)
        }
    }


async getUsersAllTasks(userId: number) {
        return await this.tasksRepository.find({where: {executor: userId}})
    }


async getOneTaskById(id: number): Promise<Task> {
        const task = await this.tasksRepository.findOne(id)
        if (task === undefined) {
            throw new HttpException({
                status: HttpStatus.NOT_FOUND,
                error: 'Task is not found'
            }, HttpStatus.NOT_FOUND)
        }
        return task
    }


async addExecutor(updateTaskDto: UpdateTaskDto) {

    }


async getTasks(): Promise<Task[]> {
        return this.tasksRepository.find({cache: 60000})
    }


/**
 * Construct a tensor by repeating it the number of times given by reps.
 *
 * This operation creates a new tensor by replicating `input` `reps`
 * times. The output tensor's i'th dimension has `input.shape[i] *
 * reps[i]` elements, and the values of `input` are replicated
 * `reps[i]` times along the i'th dimension. For example, tiling
 * `[a, b, c, d]` by `[2]` produces `[a, b, c, d, a, b, c, d]`.
 *
 * ```js
 * const a = tf.tensor1d([1, 2]);
 *
 * a.tile([2]).print();    // or a.tile([2])
 * ```
 *
 * ```js
 * const a = tf.tensor2d([1, 2, 3, 4], [2, 2]);
 *
 * a.tile([1, 2]).print();  // or a.tile([1, 2])
 * ```
 * @param x The tensor to tile.
 * @param reps Determines the number of replications per dimension.
 *
 * @doc {heading: 'Tensors', subheading: 'Slicing and Joining'}
 */
function tile_<T extends Tensor>(x: T|TensorLike, reps: number[]): T {
  const $x = convertToTensor(x, 'x', 'tile', 'string_or_numeric');
  util.assert(
      $x.rank === reps.length,
      () => `Error in transpose: rank of input ${$x.rank} ` +
          `must match length of reps ${reps}.`);

  const inputs: TileInputs = {x: $x};
  const attrs: TileAttrs = {reps};

  return ENGINE.runKernel(
      Tile, inputs as unknown as NamedTensorMap,
      attrs as unknown as NamedAttrMap);
}


() => `Error in transpose: rank of input ${$x.rank} ` +
          `must match length of reps ${reps}.`


function initializeDI() {
        ioc = new UnitTestIocContainer();
        ioc.registerCommonTypes();
        ioc.registerProcessTypes();
        ioc.registerVariableTypes();

        ioc.registerTestParsers();
        ioc.registerTestVisitors();
        ioc.registerTestResultsHelper();
        ioc.registerTestStorage();
        ioc.registerTestsHelper();

    }


() => {
    let ioc: UnitTestIocContainer;
    suiteSetup(initialize);
    setup(async () => {
        await initializeTest();
        initializeDI();
    });
    teardown(() => ioc.dispose());

    function initializeDI() {
        ioc = new UnitTestIocContainer();
        ioc.registerCommonTypes();
        ioc.registerProcessTypes();
        ioc.registerVariableTypes();

        ioc.registerTestParsers();
        ioc.registerTestVisitors();
        ioc.registerTestResultsHelper();
        ioc.registerTestStorage();
        ioc.registerTestsHelper();

    }

    test('Running tests should not stop existing discovery', async () => {
        const mockTestManager = new MockTestManagerWithRunningTests(UNITTEST_PROVIDER, Product.unittest, Uri.file(testFilesPath), testFilesPath, ioc.serviceContainer);
        ioc.serviceManager.addSingletonInstance<ITestDiscoveryService>(ITestDiscoveryService, new MockDiscoveryService(mockTestManager.discoveryDeferred.promise), UNITTEST_PROVIDER);

        const discoveryPromise = mockTestManager.discoverTests(CommandSource.auto);
        mockTestManager.discoveryDeferred.resolve(EmptyTests);
        mockTestManager.runTest(CommandSource.ui);

        await expect(discoveryPromise).to.eventually.equal(EmptyTests);
    });

    test('Discovering tests should stop running tests', async () => {
        const mockTestManager = new MockTestManagerWithRunningTests(UNITTEST_PROVIDER, Product.unittest, Uri.file(testFilesPath), testFilesPath, ioc.serviceContainer);
        ioc.serviceManager.addSingletonInstance<ITestDiscoveryService>(ITestDiscoveryService, new MockDiscoveryService(mockTestManager.discoveryDeferred.promise), UNITTEST_PROVIDER);
        mockTestManager.discoveryDeferred.resolve(EmptyTests);
        await mockTestManager.discoverTests(CommandSource.auto);
        const runPromise = mockTestManager.runTest(CommandSource.ui);
        // tslint:disable-next-line:no-string-based-set-timeout
        await new Promise(resolve => setTimeout(resolve, 1000));

        // User manually discovering tests will kill the existing test runner.
        mockTestManager.discoverTests(CommandSource.ui, true, false, true);
        await expect(runPromise).to.eventually.be.rejectedWith(CANCELLATION_REASON);
    });
}


async () => {
        await initializeTest();
        initializeDI();
    }


() => ioc.dispose()


async () => {
        const mockTestManager = new MockTestManagerWithRunningTests(UNITTEST_PROVIDER, Product.unittest, Uri.file(testFilesPath), testFilesPath, ioc.serviceContainer);
        ioc.serviceManager.addSingletonInstance<ITestDiscoveryService>(ITestDiscoveryService, new MockDiscoveryService(mockTestManager.discoveryDeferred.promise), UNITTEST_PROVIDER);

        const discoveryPromise = mockTestManager.discoverTests(CommandSource.auto);
        mockTestManager.discoveryDeferred.resolve(EmptyTests);
        mockTestManager.runTest(CommandSource.ui);

        await expect(discoveryPromise).to.eventually.equal(EmptyTests);
    }


async () => {
        const mockTestManager = new MockTestManagerWithRunningTests(UNITTEST_PROVIDER, Product.unittest, Uri.file(testFilesPath), testFilesPath, ioc.serviceContainer);
        ioc.serviceManager.addSingletonInstance<ITestDiscoveryService>(ITestDiscoveryService, new MockDiscoveryService(mockTestManager.discoveryDeferred.promise), UNITTEST_PROVIDER);
        mockTestManager.discoveryDeferred.resolve(EmptyTests);
        await mockTestManager.discoverTests(CommandSource.auto);
        const runPromise = mockTestManager.runTest(CommandSource.ui);
        // tslint:disable-next-line:no-string-based-set-timeout
        await new Promise(resolve => setTimeout(resolve, 1000));

        // User manually discovering tests will kill the existing test runner.
        mockTestManager.discoverTests(CommandSource.ui, true, false, true);
        await expect(runPromise).to.eventually.be.rejectedWith(CANCELLATION_REASON);
    }


resolve => setTimeout(resolve, 1000)


() => (
  <AppWrapper>
    <Provider store={store}>
      <ThemeProvider>
        <Global />
        <Titlebar


function Header () {
  return (

      ReactFast

Home

Seo

About

Not Found Page

Dynamic

  );
}


export class CarSelector extends BaseApiSelector<CarJSONAModel> {
    constructor() {
        super("car");
    }
}


// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isTextObject(obj: any): obj is TextObject {
  return typeof obj === 'object' && 'text' in obj
}


export function toTextComplete(text: Text): TextComplete {
  if (typeof text === 'string') {
    return { text, cdata: false }
  }

  if (typeof text.cdata === 'undefined') {
    text.cdata = true
  }

  return text as TextComplete
}


function addNode<O extends ElementCompact, K extends keyof O>(
  obj: O,
  key: K,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  value: any,
  prop: keyof ElementCompact,
  attributes?: ElementCompact
): void {
  if (typeof value !== 'undefined') {
    if (isTextObject(value)) {
      value = value.text
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    obj[key] = { [prop]: `${value}` } as any
  }

  if (attributes) {
    if (!obj[key]) {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      obj[key] = {} as any
    }

    obj[key]._attributes = attributes
  }
}


/**
 * Add the property `key` to `obj` as `{ _text: value }` if `value` is defined.
 * So this adds an {@link xml-js#ElementCompact | ElementCompact} object to
 * the property.
 *
 * @internal
 *
 * @param obj - The object to add the property to
 * @param key - The property name to set
 * @param value - The value to set
 */
export function addSimple<O extends ElementCompact, K extends keyof O>(
  obj: O,
  key: K,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  value: any,
  attributes?: ElementCompact
): void {
  if (isTextObject(value)) {
    const t = toTextComplete(value)

    if (t.cdata) {
      return addNode(obj, key, t.text, '_cdata', attributes)
    }
  }

  addNode(obj, key, value, '_text', attributes)
}


/**
 * Add the property `key` to `obj` as `{ _cdata: value }` if `value` is defined.
 * So this adds an {@link xml-js#ElementCompact | ElementCompact} object to
 * the property.
 *
 * @internal
 *
 * @param obj - The object to add the property to
 * @param key - The property name to set
 * @param value - The value to set
 */
export function addCDATA<O extends ElementCompact, K extends keyof O>(
  obj: O,
  key: K,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  value: any
): void {
  addNode(obj, key, value, '_cdata')
}


/**
 * @internal
 * @param ns
 */
export function fqn(ns: Namespace): string {
  if (ns.ns) {
    return `${ns.ns}:${ns.name}`
  }

  return ns.name
}


export function extensionToElementCompact(
  ext: ExtensionValue
): ElementCompact | Array<ElementCompact> {
  const ret: ElementCompact = {}

  if (typeof ext === 'string' || typeof ext === 'number') {
    ret._text = ext
  } else if (Array.isArray(ext)) {
    return ext.map((e) => extensionToElementCompact(e))
  } else {
    if (ext.text) {
      ret._text = ext.text
    }

    if (ext.attributes) {
      ret._attributes = ext.attributes
    }
  }

  return ret
}


export function filterExtensions(
  ext: Extension[],
  type: ExtensionType
): Extension[] {
  if (!Array.isArray(type)) {
    type = [type]
  }

  return ext.filter((e) => {
    if (Array.isArray(e.type)) {
      return e.type.some((ee) => type.includes(ee))
    } else {
      return type.includes(e.type)
    }
  })
}


export function xmlEscape(input: string): string {
  if (input.trim() !== '') {
    input = input
      .replace(/</g, '<')
      .replace(/>/g, '>')
      .replace(/"/g, '"')
      .replace(/'/g, ''')
      .replace(/&(?!(amp;)|(lt;)|(gt;)|(quot;)|(#39;)|(apos;))/g, '&')
      // replaces odd backslash(\\) with even.
      .replace(/([^\\])((\\\\)*)\\(?![\\/{])/g, '$1\\\\$2')
  }

  return input
}


export function escapeAttributeCallback(
  attributeValue: string
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
): string {
  if (typeof attributeValue === 'string') {
    return xmlEscape(attributeValue)
  }

  return attributeValue
}


(e) => extensionToElementCompact(e)


(e) => {
    if (Array.isArray(e.type)) {
      return e.type.some((ee) => type.includes(ee))
    } else {
      return type.includes(e.type)
    }
  }


(ee) => type.includes(ee)


export class MissingRequiredOptionError extends Error {
  constructor(option: string) {
    super()
    this.name = this.constructor.name
    this.message = `Missing required option "${option}"`
  }
}


() => {
  test('throws without options', () => {
    const trigger = () => {
      // @ts-expect-error
      configure();
    };

    // We check that it throws at the widget level
    // but assert the error message only in the connector.
    expect(trigger).toThrow();
  });

  test('does not throw with empty search parameters', () => {
    const trigger = () => {
      configure({});
    };

    expect(trigger).not.toThrow();
  });

  test('does not throw with search parameters', () => {
    const trigger = () => {
      configure({
        analytics: true,
      });
    };

    expect(trigger).not.toThrow();
  });
}


() => {
    const trigger = () => {
      // @ts-expect-error
      configure();
    };

    // We check that it throws at the widget level
    // but assert the error message only in the connector.
    expect(trigger).toThrow();
  }


() => {
      // @ts-expect-error
      configure();
    }


() => {
    const trigger = () => {
      configure({});
    };

    expect(trigger).not.toThrow();
  }


() => {
      configure({});
    }


() => {
    const trigger = () => {
      configure({
        analytics: true,
      });
    };

    expect(trigger).not.toThrow();
  }


() => {
      configure({
        analytics: true,
      });
    }


(props: ISvgIconProps) => (
    '<?xml version="1.0" encoding="UTF-8"?>'
    + '<svg width="' + props.size + '" height="' + props.size + '" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">'
        + '<path d="M15 26.3137C15 26.3137 19.5962 25.9602 22.7782 22.7782C25.9601 19.5962 26.3137 15 26.3137 15L34.0657 27.1817C35.3205 29.1535 35.0374 31.7322 33.3848 33.3848C31.7322 35.0374 29.1535 35.3205 27.1817 34.0657L15 26.3137Z" fill="' + props.colors[1] + '" stroke="' + props.colors[0] + '" stroke-width="' + props.strokeWidth + '"/>'
        + '<circle cx="15" cy="15" r="11" stroke="' + props.colors[0] + '" stroke-width="' + props.strokeWidth + '"/>'
        + '<path d="M5.65674 25.4561L25.4557 5.65707" stroke="' + props.colors[0] + '" stroke-width="' + props.strokeWidth + '" stroke-linecap="' + props.strokeLinecap + '" stroke-linejoin="' + props.strokeLinejoin + '"/>'
        + '<path d="M34 33L42 41L33 41" stroke="' + props.colors[0] + '" stroke-width="' + props.strokeWidth + '" stroke-linecap="' + props.strokeLinecap + '" stroke-linejoin="' + props.strokeLinejoin + '"/>'
    + '</svg>'
)


@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class AssetsRoutingModule { }


'setUp'(cb: () => void) {
    stack = new cdk.Stack();
    td = new ecs.Ec2TaskDefinition(stack, 'TaskDefinition');

    cb();
  }


'create a gelf log driver with minimum options'(test: Test) {
    // WHEN
    td.addContainer('Container', {
      image,
      logging: new ecs.GelfLogDriver({
        address: 'my-gelf-address',
      }),
      memoryLimitMiB: 128,
    });

    // THEN
    expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', {
      ContainerDefinitions: [
        {
          LogConfiguration: {
            LogDriver: 'gelf',
            Options: {
              'gelf-address': 'my-gelf-address',
            },
          },
        },
      ],
    }));

    test.done();
  }


'create a gelf log driver using gelf with minimum options'(test: Test) {
    // WHEN
    td.addContainer('Container', {
      image,
      logging: ecs.LogDrivers.gelf({
        address: 'my-gelf-address',
      }),
      memoryLimitMiB: 128,
    });

    // THEN
    expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', {
      ContainerDefinitions: [
        {
          LogConfiguration: {
            LogDriver: 'gelf',
            Options: {
              'gelf-address': 'my-gelf-address',
            },
          },
        },
      ],
    }));

    test.done();
  }


() => action(ActionTypes.FETCH_DATA)


() => action(ActionTypes.CANCEL)


() => action(ActionTypes.RESET)


(beers: Beer[]) => {
  return action(ActionTypes.FETCH_FULFILLED, beers)
}


(message: string) => {
  return action(ActionTypes.FETCH_FAILED, message)
}


(status: Status) => {
  return action(ActionTypes.SET_STATUS, status)
}


(input: string) => {
  return action(ActionTypes.SEARCH, input)
}


() => action(ActionTypes.RANDOM)


/**
 * @docid EdmLiteral
 * @namespace DevExpress.data
 * @module data/odata/utils
 * @export EdmLiteral
 * @prevFileNamespace DevExpress.data
 * @public
 */
export class EdmLiteral {
    constructor(value: string);
    /**
     * @docid EdmLiteral.valueOf
     * @publicName valueOf()
     * @return string
     * @prevFileNamespace DevExpress.data
     * @public
     */
    valueOf(): string;
}


/**
     * @docid EdmLiteral.valueOf
     * @publicName valueOf()
     * @return string
     * @prevFileNamespace DevExpress.data
     * @public
     */
valueOf(): string;


export default function UserProfile() {
	const { resource, user, suggestions } = useLoaderData<LoaderData>();
	const { message } = useSessionData();
	const location = useLocation();
	const [showBookmark, action] = useMemo(() => {
		const searchParams = new URLSearchParams(location.search);
		const showBookmark = searchParams.get('open') === 'bookmark';

		searchParams.delete('open');

		return [showBookmark, `?${searchParams.toString()}&index`];
	}, [location.search]);

	if (!resource) {
		return <About />;
	}

	return (

				<ResourcesDetails resource={resource} user={user} message={message}>
					{suggestions.map(({ entries, searchOptions }) => (
						<SuggestedResources
							key={JSON.stringify(searchOptions)}
							entries={entries}
							searchOptions={searchOptions}
						/>
					))}
				</ResourcesDetails>

			{showBookmark ? (
				<Form
					className="w-full lg:w-80 3xl:w-96 lg:border-l"
					method="post"
					action={action}
				>
					<BookmarkDetails resource={resource} />
				</Form>
			) : null}

	);
}


({ params, location }) => {
	const { guide } = params;

	if (!guide) {
		return {};
	}

	const searchOptions = getSearchOptions(
		`${location.pathname}${location.search}`,
	);
	const title = getTitleBySearchOptions(searchOptions);

	return formatMeta({
		title,
		description: 'A platform for sharing everything about Remix',
		'og:url': `https://remix.guide/${guide}`,
	});
}


async ({ params, context, request }) => {
	const { session, userStore, resourceStore } = context as Context;
	const [profile, formData] = await Promise.all([
		session.getUserProfile(),
		request.formData(),
	]);
	const type = formData.get('type');
	const resourceId = formData.get('resourceId')?.toString();

	if (!type || !resourceId) {
		return new Response('Bad Request', { status: 400 });
	}

	if (type === 'view') {
		const url = formData.get('url')?.toString();

		if (!url) {
			return new Response('Bad Request', { status: 400 });
		}

		await userStore.view(profile?.id ?? null, resourceId, url);
	} else {
		if (!profile) {
			return new Response('Unauthorized', { status: 401 });
		}

		switch (type) {
			case 'bookmark': {
				const url = formData.get('url')?.toString();

				if (!url) {
					return new Response('Bad Request', { status: 400 });
				}

				await userStore.bookmark(profile.id, resourceId, url);
				break;
			}
			case 'unbookmark': {
				const url = formData.get('url')?.toString();

				if (!url) {
					return new Response('Bad Request', { status: 400 });
				}

				await userStore.unbookmark(profile.id, resourceId, url);
				break;
			}
			case 'update': {
				const description = formData.get('description')?.toString() ?? null;
				const lists = formData.getAll('lists').map((value) => value.toString());

				await resourceStore.updateBookmark(resourceId, description, lists);

				return redirect(request.url, {
					headers: {
						'Set-Cookie': await session.flash(
							'The bookmark is updated successfully',
							'success',
						),
					},
				});
			}
			case 'delete': {
				await resourceStore.deleteBookmark(resourceId);

				return redirect(`/${params.guide}`, {
					headers: {
						'Set-Cookie': await session.flash(
							'The bookmark is deleted successfully',
							'success',
						),
					},
				});
			}
			default:
				return new Response('Bad Request', { status: 400 });
		}
	}

	return null;
}


(value) => value.toString()


async ({ context, request }) => {
	const url = new URL(request.url);
	const resourceId = url.searchParams.get('resourceId');

	if (!resourceId) {
		return json({});
	}

	const { session, resourceStore, userStore } = context as Context;
	const [list, profile] = await Promise.all([
		resourceStore.list(),
		session.getUserProfile(),
	]);
	const resource = list[resourceId];

	if (!resource) {
		throw notFound();
	}

	const user = profile?.id ? await userStore.getUser(profile.id) : null;

	return json({
		user,
		resource: user ? patchResource(resource, user) : resource,
		suggestions: getSuggestions(list, resource),
	});
}


({
	prevUrl,
	url,
	submission,
}) => {
	if (
		prevUrl.searchParams.get('resourceId') !==
		url.searchParams.get('resourceId')
	) {
		return true;
	}

	return ['bookmark', 'unbookmark', 'update', 'delete'].includes(
		submission?.formData.get('type')?.toString() ?? '',
	);
}


() => {
		const searchParams = new URLSearchParams(location.search);
		const showBookmark = searchParams.get('open') === 'bookmark';

		searchParams.delete('open');

		return [showBookmark, `?${searchParams.toString()}&index`];
	}


({ entries, searchOptions }) => (
						<SuggestedResources
							key={JSON.stringify(searchOptions)}


interface LoaderData {
	resource: Resource;
	message: string | null;
	user: User | null;
	suggestions: Array<{
		entries: Resource[];
		searchOptions: SearchOptions;
	}>;
}


/**
 * Wrapper for async express endpoints to catch errors and forward them to the error handler.
 */
export function expressWrap(callback: express.RequestHandler): express.RequestHandler {
  return async (req, res, next) => {
    try {
      await callback(req, res, next);
    } catch (err) {
      next(err);
    }
  };
}


async (req, res, next) => {
    try {
      await callback(req, res, next);
    } catch (err) {
      next(err);
    }
  }


(options: JsonErrorHandlerOptions = {}): express.ErrorRequestHandler => {
  return (err, req, res, _next) => {
    const mreq = req as RequestWithLogin;
    log.warn(
      "Error during api call to %s: (%s) user %d%s%s",
      req.path, err.message, mreq.userId,
      options.shouldLogParams !== false ? ` params ${JSON.stringify(req.params)}` : '',
      options.shouldLogBody !== false ? ` body ${JSON.stringify(req.body)}` : '',
    );
    let details = err.details && {...err.details};
    const status = details?.status || err.status || 500;
    if (details) {
      // Remove some details exposed for websocket API only.
      delete details.accessMode;
      delete details.status;  // TODO: reconcile err.status and details.status, no need for both.
      if (Object.keys(details).length === 0) { details = undefined; }
    }
    res.status(status).json({error: err.message || 'internal error', details});
  };
}


(err, req, res, _next) => {
    const mreq = req as RequestWithLogin;
    log.warn(
      "Error during api call to %s: (%s) user %d%s%s",
      req.path, err.message, mreq.userId,
      options.shouldLogParams !== false ? ` params ${JSON.stringify(req.params)}` : '',
      options.shouldLogBody !== false ? ` body ${JSON.stringify(req.body)}` : '',
    );
    let details = err.details && {...err.details};
    const status = details?.status || err.status || 500;
    if (details) {
      // Remove some details exposed for websocket API only.
      delete details.accessMode;
      delete details.status;  // TODO: reconcile err.status and details.status, no need for both.
      if (Object.keys(details).length === 0) { details = undefined; }
    }
    res.status(status).json({error: err.message || 'internal error', details});
  }


(req, res, next) => {
  res.status(404).json({error: `not found: ${req.url}`});
}


interface JsonErrorHandlerOptions {
  shouldLogBody?: boolean;
  shouldLogParams?: boolean;
}


result => {
      //      this.animal = result;
    }


result => {
//      this.animal = result;
    }


@Component(
  {
    selector: 'ha-gcode-overview',
    templateUrl: './gcode-overview.component.html',
    styleUrls: ['./gcode-overview.component.css']
  })
export class GcodeOverviewComponent implements OnInit {
  entries: LoadOptions[] = [];
  errorMessage: string = '';
  isLoading: boolean = true;

  animal: string;
  name: string;

  constructor(
    private router: Router,
    private loadOptionService: CNCLibLoadOptionService,
    private dialog: MatDialog
  ) {
  }

  newLoadOption() {

    const dialogRef = this.dialog.open(MessageBoxComponent,
      {
        width: '250px',
        data: { title: "Error", message: "Not implemented yet" }
      });

    dialogRef.afterClosed().subscribe(result => {
      //      this.animal = result;
    });

  }

  detailLoadOption(id: number) {

    const dialogRef = this.dialog.open(MessageBoxComponent,
      {
        width: '250px',
        data: { title: "Info", message: "Hallo" }
      });

    dialogRef.afterClosed().subscribe(result => {
//      this.animal = result;
    });

/*
    const dialogRef = this.dialog.open(ModalComponent,
      {
        width: '250px',
        data: { name: this.name, animal: this.animal }
      });

    dialogRef.afterClosed().subscribe(result => {
      this.animal = result;
    });
*/
  }

  async ngOnInit() {
    this.entries = await this.loadOptionService.getAll();
  }
}


newLoadOption() {

    const dialogRef = this.dialog.open(MessageBoxComponent,
      {
        width: '250px',
        data: { title: "Error", message: "Not implemented yet" }
      });

    dialogRef.afterClosed().subscribe(result => {
      //      this.animal = result;
    });

  }


detailLoadOption(id: number) {

    const dialogRef = this.dialog.open(MessageBoxComponent,
      {
        width: '250px',
        data: { title: "Info", message: "Hallo" }
      });

    dialogRef.afterClosed().subscribe(result => {
//      this.animal = result;
    });

/*
    const dialogRef = this.dialog.open(ModalComponent,
      {
        width: '250px',
        data: { name: this.name, animal: this.animal }
      });

    dialogRef.afterClosed().subscribe(result => {
      this.animal = result;
    });
*/
  }


async ngOnInit() {
    this.entries = await this.loadOptionService.getAll();
  }


/**
 * Author: Jakub Man <xmanja00@stud.fit.vutbr.cz>
 */
export class Notification {
    id: number;
    title: string;
    time: string;
    deviceName: string;
    channel: string;
}


@Component({
  moduleId: module.id,
  selector: 'product-feature-list',
  templateUrl: 'product-feature.list.template.html'
})

export class ProductFeatureListComponent extends AppListComponent<ProductFeatureModel> {

  @ViewChild(ProductFeatureListGridComponent) list: ProductFeatureListGridComponent;

  constructor(dialog: ProductFeatureDialogService) {
    super(dialog);
  }
}


export declare class LegacyFakeTimers<TimerRef = unknown> {
  private _cancelledTicks;
  private _config;
  private _disposed?;
  private _fakeTimerAPIs;
  private _global;
  private _immediates;
  private _maxLoops;
  private _moduleMocker;
  private _now;
  private _ticks;
  private _timerAPIs;
  private _timers;
  private _uuidCounter;
  private _timerConfig;
  constructor({
    global,
    moduleMocker,
    timerConfig,
    config,
    maxLoops,
  }: {
    global: typeof globalThis;
    moduleMocker: ModuleMocker;
    timerConfig: TimerConfig<TimerRef>;
    config: StackTraceConfig;
    maxLoops?: number;
  });
  clearAllTimers(): void;
  dispose(): void;
  reset(): void;
  runAllTicks(): void;
  runAllImmediates(): void;
  private _runImmediate;
  runAllTimers(): void;
  runOnlyPendingTimers(): void;
  advanceTimersToNextTimer(steps?: number): void;
  advanceTimersByTime(msToRun: number): void;
  runWithRealTimers(cb: Callback): void;
  useRealTimers(): void;
  useFakeTimers(): void;
  getTimerCount(): number;
  private _checkFakeTimers;
  private _createMocks;
  private _fakeClearTimer;
  private _fakeClearImmediate;
  private _fakeNextTick;
  private _fakeRequestAnimationFrame;
  private _fakeSetImmediate;
  private _fakeSetInterval;
  private _fakeSetTimeout;
  private _getNextTimerHandle;
  private _runTimerHandle;
}


export declare class ModernFakeTimers {
  private _clock;
  private _config;
  private _fakingTime;
  private _global;
  private _fakeTimers;
  constructor({
    global,
    config,
  }: {
    global: typeof globalThis;
    config: Config.ProjectConfig;
  });
  clearAllTimers(): void;
  dispose(): void;
  runAllTimers(): void;
  runOnlyPendingTimers(): void;
  advanceTimersToNextTimer(steps?: number): void;
  advanceTimersByTime(msToRun: number): void;
  runAllTicks(): void;
  useRealTimers(): void;
  useFakeTimers(fakeTimersConfig?: Config.FakeTimersConfig): void;
  reset(): void;
  setSystemTime(now?: number | Date): void;
  getRealSystemTime(): number;
  getTimerCount(): number;
  private _checkFakeTimers;
  private _toSinonFakeTimersConfig;
}


declare type Callback = (...args: Array<unknown>) => void;


declare type TimerConfig<Ref> = {
  idToRef: (id: number) => Ref;
  refToId: (ref: Ref) => number | void;
};


clearAllTimers(): void;


runAllTicks(): void;


runAllImmediates(): void;


runAllTimers(): void;


runOnlyPendingTimers(): void;


advanceTimersToNextTimer(steps?: number): void;


advanceTimersByTime(msToRun: number): void;


runWithRealTimers(cb: Callback): void;


useRealTimers(): void;


useFakeTimers(): void;


getTimerCount(): number;


useFakeTimers(fakeTimersConfig?: Config.FakeTimersConfig): void;


setSystemTime(now?: number | Date): void;


getRealSystemTime(): number;


function createWindow() {

  const electronScreen = screen;
  const size = electronScreen.getPrimaryDisplay().workAreaSize;

  // Create the browser window.
  win = new BrowserWindow({
    x: 0,
    y: 0,
    width: size.width,
    height: size.height,
    webPreferences: {
        nodeIntegration: true
    }
  });

  if (serve) {
    win.loadURL('http://127.0.0.1:8080');
    // Open the DevTools.
    win.webContents.openDevTools();
  } else {
    // and load the index.html of the app.
    win.loadURL(url.format({
      protocol: 'file:',
      pathname: path.join(__dirname, '/index.html'),
      slashes:  true
    }));
    // Remove menu bar.
    win.setMenu(null);
  }

  // Emitted when the window is closed.
  win.on('closed', () => {
    // Dereference the window object, usually you would store window
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    win = null;
  });
}


val => val === '--serve'


() => {
    // Dereference the window object, usually you would store window
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    win = null;
  }


() => {
    // On OS X it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin') {
      app.quit();
    }
  }


() => {
    // On OS X it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (win === null) {
      createWindow();
    }
  }


(error, request, response, next) => {

    if(error instanceof ValidationError) {
        let errors: ValidationErrors = {};

        error.inner.forEach(err => {
            errors[err.path] = err.errors;
        });

        return response.status(400).json({message: 'validations fails', errors});
    }
    console.error(error);

    return response.status(500).json({message: 'Internal server error' })
}


err => {
            errors[err.path] = err.errors;
        }


interface ValidationErrors {
    [key: string]: string[];
}


@Component({
  selector: 'ngx-import-people',
  templateUrl: './import-people.component.html',
  styleUrls: ['./import-people.component.scss'],
})
export class ImportPeopleComponent {

}


export class XrmStageMock implements Xrm.Stage, INamedComponent {
    private _status: Xrm.StageStatus;
    private _name: string;
    private _id: string;
    private _steps: Xrm.StageStep[];

    constructor(id: string, name: string) {
        this._id = id;
        this._name = name;
    }

    /* NEW MEMBERS TO HELP MOCKING */
    setStatus(status: Xrm.StageStatus): void {
        this._status = status;
    }
    setName(name: string): void {
        this._name = name;
    }
    setId(id: string): void {
        this._id = id;
    }
    /* END OF NEW MEMBERS*/
    getId(): string {
        return this._id;
    }
    getName(): string {
        return this._name;
    }
    getSteps(): Xrm.StageStep[] {
        return this._steps;
    }
    getCategory(): Xrm.IStageCategory {
        throw new Error("Method not implemented.");
    }
    getEntityName(): string {
        throw new Error("Method not implemented.");
    }
    getStatus(): Xrm.StageStatus {
        return this._status;
    }
    getNavigationBehavior(): Xrm.NavigationBehaviorObject {
        throw new Error("Method not implemented.");
    }
}


/* NEW MEMBERS TO HELP MOCKING */
setStatus(status: Xrm.StageStatus): void {
        this._status = status;
    }


setName(name: string): void {
        this._name = name;
    }


setId(id: string): void {
        this._id = id;
    }


/* END OF NEW MEMBERS*/
getId(): string {
        return this._id;
    }


getName(): string {
        return this._name;
    }


getSteps(): Xrm.StageStep[] {
        return this._steps;
    }


getCategory(): Xrm.IStageCategory {
        throw new Error("Method not implemented.");
    }


getEntityName(): string {
        throw new Error("Method not implemented.");
    }


getStatus(): Xrm.StageStatus {
        return this._status;
    }


getNavigationBehavior(): Xrm.NavigationBehaviorObject {
        throw new Error("Method not implemented.");
    }


() => {
        this.publishers.forEach(publisher => {
          if (!!publisher.stream && !!publisher.stream.hasVideo && !!publisher.stream.streamManager.videos[0]) {

            let attempts = 0;

            const oldWidth = publisher.stream.videoDimensions.width;
            const oldHeight = publisher.stream.videoDimensions.height;
            // New resolution got from different places for Chrome and Firefox. Chrome needs a videoWidth and videoHeight of a videoElement.
            // Firefox needs getSettings from the videoTrack
            let firefoxSettings = publisher.stream.getMediaStream().getVideoTracks()[0].getSettings();
            let newWidth = (platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.width : publisher.videoReference.videoWidth;
            let newHeight = (platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.height : publisher.videoReference.videoHeight;

            const repeatUntilChange = setInterval(() => {
              firefoxSettings = publisher.stream.getMediaStream().getVideoTracks()[0].getSettings();
              newWidth = (platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.width : publisher.videoReference.videoWidth;
              newHeight = (platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.height : publisher.videoReference.videoHeight;
              sendStreamPropertyChangedEvent(oldWidth, oldHeight, newWidth, newHeight);
            }, 100);

            const sendStreamPropertyChangedEvent = (oldWidth, oldHeight, newWidth, newHeight) => {
              attempts++;
              if (attempts > 4) {
                clearTimeout(repeatUntilChange);
              }
              if (newWidth !== oldWidth || newHeight !== oldHeight) {
                publisher.stream.videoDimensions = {
                  width: newWidth || 0,
                  height: newHeight || 0
                };
                this.sendRequest(
                  'streamPropertyChanged',
                  {
                    streamId: publisher.stream.streamId,
                    property: 'videoDimensions',
                    newValue: JSON.stringify(publisher.stream.videoDimensions),
                    reason: 'deviceRotated'
                  },
                  (error, response) => {
                    if (error) {
                      console.error("Error sending 'streamPropertyChanged' event", error);
                    } else {
                      this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]);
                      publisher.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(publisher, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]);
                    }
                  });
                clearTimeout(repeatUntilChange);
              }
            };
          }
        });
      }


publisher => {
          if (!!publisher.stream && !!publisher.stream.hasVideo && !!publisher.stream.streamManager.videos[0]) {

            let attempts = 0;

            const oldWidth = publisher.stream.videoDimensions.width;
            const oldHeight = publisher.stream.videoDimensions.height;
            // New resolution got from different places for Chrome and Firefox. Chrome needs a videoWidth and videoHeight of a videoElement.
            // Firefox needs getSettings from the videoTrack
            let firefoxSettings = publisher.stream.getMediaStream().getVideoTracks()[0].getSettings();
            let newWidth = (platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.width : publisher.videoReference.videoWidth;
            let newHeight = (platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.height : publisher.videoReference.videoHeight;

            const repeatUntilChange = setInterval(() => {
              firefoxSettings = publisher.stream.getMediaStream().getVideoTracks()[0].getSettings();
              newWidth = (platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.width : publisher.videoReference.videoWidth;
              newHeight = (platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.height : publisher.videoReference.videoHeight;
              sendStreamPropertyChangedEvent(oldWidth, oldHeight, newWidth, newHeight);
            }, 100);

            const sendStreamPropertyChangedEvent = (oldWidth, oldHeight, newWidth, newHeight) => {
              attempts++;
              if (attempts > 4) {
                clearTimeout(repeatUntilChange);
              }
              if (newWidth !== oldWidth || newHeight !== oldHeight) {
                publisher.stream.videoDimensions = {
                  width: newWidth || 0,
                  height: newHeight || 0
                };
                this.sendRequest(
                  'streamPropertyChanged',
                  {
                    streamId: publisher.stream.streamId,
                    property: 'videoDimensions',
                    newValue: JSON.stringify(publisher.stream.videoDimensions),
                    reason: 'deviceRotated'
                  },
                  (error, response) => {
                    if (error) {
                      console.error("Error sending 'streamPropertyChanged' event", error);
                    } else {
                      this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]);
                      publisher.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(publisher, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]);
                    }
                  });
                clearTimeout(repeatUntilChange);
              }
            };
          }
        }


() => {
              firefoxSettings = publisher.stream.getMediaStream().getVideoTracks()[0].getSettings();
              newWidth = (platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.width : publisher.videoReference.videoWidth;
              newHeight = (platform.name!!.toLowerCase().indexOf('firefox') !== -1) ? firefoxSettings.height : publisher.videoReference.videoHeight;
              sendStreamPropertyChangedEvent(oldWidth, oldHeight, newWidth, newHeight);
            }


(oldWidth, oldHeight, newWidth, newHeight) => {
              attempts++;
              if (attempts > 4) {
                clearTimeout(repeatUntilChange);
              }
              if (newWidth !== oldWidth || newHeight !== oldHeight) {
                publisher.stream.videoDimensions = {
                  width: newWidth || 0,
                  height: newHeight || 0
                };
                this.sendRequest(
                  'streamPropertyChanged',
                  {
                    streamId: publisher.stream.streamId,
                    property: 'videoDimensions',
                    newValue: JSON.stringify(publisher.stream.videoDimensions),
                    reason: 'deviceRotated'
                  },
                  (error, response) => {
                    if (error) {
                      console.error("Error sending 'streamPropertyChanged' event", error);
                    } else {
                      this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]);
                      publisher.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(publisher, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]);
                    }
                  });
                clearTimeout(repeatUntilChange);
              }
            }


(error, response) => {
                    if (error) {
                      console.error("Error sending 'streamPropertyChanged' event", error);
                    } else {
                      this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]);
                      publisher.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(publisher, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]);
                    }
                  }


() => {
        if (completionHandler !== undefined) {
          completionHandler(undefined);
        }
        publisher.emitEvent('accessAllowed', []);
      }


(error) => {
        if (completionHandler !== undefined) {
          completionHandler(error);
        }
        publisher.emitEvent('accessDenied', []);
      }


(resolve, reject) => {

      let publisher: Publisher;

      const callback = (error: Error) => {
        if (!!error) {
          reject(error);
        } else {
          resolve(publisher);
        }
      };

      if (!!properties) {
        publisher = this.initPublisher(targetElement, properties, callback);
      } else {
        publisher = this.initPublisher(targetElement, callback);
      }
    }


(error: Error) => {
        if (!!error) {
          reject(error);
        } else {
          resolve(publisher);
        }
      }


(resolve, reject) => {
      navigator.mediaDevices.enumerateDevices().then((deviceInfos) => {
        const devices: Device[] = [];
        deviceInfos.forEach(deviceInfo => {
          if (deviceInfo.kind === 'audioinput' || deviceInfo.kind === 'videoinput') {
            devices.push({
              kind: deviceInfo.kind,
              deviceId: deviceInfo.deviceId,
              label: deviceInfo.label
            });
          }
        });
        resolve(devices);
      }).catch((error) => {
        console.error('Error getting devices', error);
        reject(error);
      });
    }


(deviceInfos) => {
        const devices: Device[] = [];
        deviceInfos.forEach(deviceInfo => {
          if (deviceInfo.kind === 'audioinput' || deviceInfo.kind === 'videoinput') {
            devices.push({
              kind: deviceInfo.kind,
              deviceId: deviceInfo.deviceId,
              label: deviceInfo.label
            });
          }
        });
        resolve(devices);
      }


deviceInfo => {
          if (deviceInfo.kind === 'audioinput' || deviceInfo.kind === 'videoinput') {
            devices.push({
              kind: deviceInfo.kind,
              deviceId: deviceInfo.deviceId,
              label: deviceInfo.label
            });
          }
        }


(error) => {
        console.error('Error getting devices', error);
        reject(error);
      }


(resolve, reject) => {
      this.generateMediaConstraints(options)
        .then(constraints => {
          navigator.mediaDevices.getUserMedia(constraints)
            .then(mediaStream => {
              resolve(mediaStream);
            })
            .catch(error => {
              let errorName: OpenViduErrorName;
              const errorMessage = error.toString();
              if (!(options.videoSource === 'screen')) {
                errorName = OpenViduErrorName.DEVICE_ACCESS_DENIED;
              } else {
                errorName = OpenViduErrorName.SCREEN_CAPTURE_DENIED;
              }
              reject(new OpenViduError(errorName, errorMessage));
            });
        })
        .catch((error: OpenViduError) => {
          reject(error);
        });
    }


constraints => {
          navigator.mediaDevices.getUserMedia(constraints)
            .then(mediaStream => {
              resolve(mediaStream);
            })
            .catch(error => {
              let errorName: OpenViduErrorName;
              const errorMessage = error.toString();
              if (!(options.videoSource === 'screen')) {
                errorName = OpenViduErrorName.DEVICE_ACCESS_DENIED;
              } else {
                errorName = OpenViduErrorName.SCREEN_CAPTURE_DENIED;
              }
              reject(new OpenViduError(errorName, errorMessage));
            });
        }


mediaStream => {
              resolve(mediaStream);
            }


error => {
              let errorName: OpenViduErrorName;
              const errorMessage = error.toString();
              if (!(options.videoSource === 'screen')) {
                errorName = OpenViduErrorName.DEVICE_ACCESS_DENIED;
              } else {
                errorName = OpenViduErrorName.SCREEN_CAPTURE_DENIED;
              }
              reject(new OpenViduError(errorName, errorMessage));
            }


(error: OpenViduError) => {
          reject(error);
        }


(resolve, reject) => {
      let audio, video;

      if (publisherProperties.audioSource === null || publisherProperties.audioSource === false) {
        audio = false;
      } else if (publisherProperties.audioSource === undefined) {
        audio = true;
      } else {
        audio = publisherProperties.audioSource;
      }

      if (publisherProperties.videoSource === null || publisherProperties.videoSource === false) {
        video = false;
      } else {
        video = {
          height: {
            ideal: 480
          },
          width: {
            ideal: 640
          }
        };
      }

      const mediaConstraints: MediaStreamConstraints = {
        audio,
        video
      };

      if (typeof mediaConstraints.audio === 'string') {
        mediaConstraints.audio = { deviceId: { exact: mediaConstraints.audio } };
      }

      if (mediaConstraints.video) {

        if (!!publisherProperties.resolution) {
          const widthAndHeight = publisherProperties.resolution.toLowerCase().split('x');
          const width = Number(widthAndHeight[0]);
          const height = Number(widthAndHeight[1]);
          (mediaConstraints.video as any).width.ideal = width;
          (mediaConstraints.video as any).height.ideal = height;
        }

        if (!!publisherProperties.frameRate) {
          (mediaConstraints.video as any).frameRate = { ideal: publisherProperties.frameRate };
        }

        if (!!publisherProperties.videoSource && typeof publisherProperties.videoSource === 'string') {

          if (publisherProperties.videoSource === 'screen') {

            if (platform.name !== 'Chrome' && platform.name!.indexOf('Firefox') === -1) {
              const error = new OpenViduError(OpenViduErrorName.SCREEN_SHARING_NOT_SUPPORTED, 'You can only screen share in desktop Chrome and Firefox. Detected browser: ' + platform.name);
              console.error(error);
              reject(error);
            } else {

              if (!!this.advancedConfiguration.screenShareChromeExtension && !(platform.name!.indexOf('Firefox') !== -1)) {

                // Custom screen sharing extension for Chrome

                screenSharing.getScreenConstraints((error, screenConstraints) => {
                  if (!!error || !!screenConstraints.mandatory && screenConstraints.mandatory.chromeMediaSource === 'screen') {
                    if (error === 'permission-denied' || error === 'PermissionDeniedError') {
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_CAPTURE_DENIED, 'You must allow access to one window of your desktop');
                      console.error(error);
                      reject(error);
                    } else {
                      const extensionId = this.advancedConfiguration.screenShareChromeExtension!.split('/').pop()!!.trim();
                      screenSharing.getChromeExtensionStatus(extensionId, (status) => {
                        if (status === 'installed-disabled') {
                          const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_DISABLED, 'You must enable the screen extension');
                          console.error(error);
                          reject(error);
                        }
                        if (status === 'not-installed') {
                          const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_NOT_INSTALLED, (<string>this.advancedConfiguration.screenShareChromeExtension));
                          console.error(error);
                          reject(error);
                        }
                      });
                    }
                  } else {
                    mediaConstraints.video = screenConstraints;
                    resolve(mediaConstraints);
                  }
                });
              } else {

                // Default screen sharing extension for Chrome

                screenSharingAuto.getScreenId((error, sourceId, screenConstraints) => {
                  if (!!error) {
                    if (error === 'not-installed') {
                      const extensionUrl = !!this.advancedConfiguration.screenShareChromeExtension ? this.advancedConfiguration.screenShareChromeExtension :
                        'https://chrome.google.com/webstore/detail/openvidu-screensharing/lfcgfepafnobdloecchnfaclibenjold';
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_NOT_INSTALLED, extensionUrl);
                      console.error(error);
                      reject(error);
                    } else if (error === 'installed-disabled') {
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_DISABLED, 'You must enable the screen extension');
                      console.error(error);
                      reject(error);
                    } else if (error === 'permission-denied') {
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_CAPTURE_DENIED, 'You must allow access to one window of your desktop');
                      console.error(error);
                      reject(error);
                    }
                  } else {
                    mediaConstraints.video = screenConstraints.video;
                    resolve(mediaConstraints);
                  }
                });
              }

              publisherProperties.videoSource = 'screen';

            }
          } else {
            // tslint:disable-next-line:no-string-literal
            mediaConstraints.video['deviceId'] = { exact: publisherProperties.videoSource };
            resolve(mediaConstraints);
          }
        } else {
          resolve(mediaConstraints);
        }
      } else {
        resolve(mediaConstraints);
      }
    }


(error, screenConstraints) => {
                  if (!!error || !!screenConstraints.mandatory && screenConstraints.mandatory.chromeMediaSource === 'screen') {
                    if (error === 'permission-denied' || error === 'PermissionDeniedError') {
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_CAPTURE_DENIED, 'You must allow access to one window of your desktop');
                      console.error(error);
                      reject(error);
                    } else {
                      const extensionId = this.advancedConfiguration.screenShareChromeExtension!.split('/').pop()!!.trim();
                      screenSharing.getChromeExtensionStatus(extensionId, (status) => {
                        if (status === 'installed-disabled') {
                          const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_DISABLED, 'You must enable the screen extension');
                          console.error(error);
                          reject(error);
                        }
                        if (status === 'not-installed') {
                          const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_NOT_INSTALLED, (<string>this.advancedConfiguration.screenShareChromeExtension));
                          console.error(error);
                          reject(error);
                        }
                      });
                    }
                  } else {
                    mediaConstraints.video = screenConstraints;
                    resolve(mediaConstraints);
                  }
                }


(status) => {
                        if (status === 'installed-disabled') {
                          const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_DISABLED, 'You must enable the screen extension');
                          console.error(error);
                          reject(error);
                        }
                        if (status === 'not-installed') {
                          const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_NOT_INSTALLED, (<string>this.advancedConfiguration.screenShareChromeExtension));
                          console.error(error);
                          reject(error);
                        }
                      }


(error, sourceId, screenConstraints) => {
                  if (!!error) {
                    if (error === 'not-installed') {
                      const extensionUrl = !!this.advancedConfiguration.screenShareChromeExtension ? this.advancedConfiguration.screenShareChromeExtension :
                        'https://chrome.google.com/webstore/detail/openvidu-screensharing/lfcgfepafnobdloecchnfaclibenjold';
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_NOT_INSTALLED, extensionUrl);
                      console.error(error);
                      reject(error);
                    } else if (error === 'installed-disabled') {
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_DISABLED, 'You must enable the screen extension');
                      console.error(error);
                      reject(error);
                    } else if (error === 'permission-denied') {
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_CAPTURE_DENIED, 'You must allow access to one window of your desktop');
                      console.error(error);
                      reject(error);
                    }
                  } else {
                    mediaConstraints.video = screenConstraints.video;
                    resolve(mediaConstraints);
                  }
                }


/**
   * Returns new session
   */
initSession(): Session {
    this.session = new Session(this);
    return this.session;
  }


initPublisher(targetElement: string | HTMLElement): Publisher;


initPublisher(targetElement: string | HTMLElement, properties: PublisherProperties): Publisher;


initPublisher(targetElement: string | HTMLElement, completionHandler: (error: Error | undefined) => void): Publisher;


initPublisher(targetElement: string | HTMLElement, properties: PublisherProperties, completionHandler: (error: Error | undefined) => void): Publisher;


/**
   * Returns a new publisher
   *
   * #### Events dispatched
   *
   * The [[Publisher]] object will dispatch an `accessDialogOpened` event, only if the pop-up shown by the browser to request permissions for the camera is opened. You can use this event to alert the user about granting permissions
   * for your website. An `accessDialogClosed` event will also be dispatched after user clicks on "Allow" or "Block" in the pop-up.
   *
   * The [[Publisher]] object will dispatch an `accessAllowed` or `accessDenied` event once it has been granted access to the requested input devices or not.
   *
   * The [[Publisher]] object will dispatch a `videoElementCreated` event once a HTML video element has been added to DOM (only if you
   * [let OpenVidu take care of the video players](/docs/how-do-i/manage-videos/#let-openvidu-take-care-of-the-video-players)). See [[VideoElementEvent]] to learn more.
   *
   * The [[Publisher]] object will dispatch a `streamPlaying` event once the local streams starts playing. See [[StreamManagerEvent]] to learn more.
   *
   * @param targetElement  HTML DOM element (or its `id` attribute) in which the video element of the Publisher will be inserted (see [[PublisherProperties.insertMode]]). If *null* or *undefined* no default video will be created for this Publisher.
   * You can always call method [[Publisher.addVideoElement]] or [[Publisher.createVideoElement]] to manage the video elements on your own (see [Manage video players](/docs/how-do-i/manage-videos) section)
   * @param completionHandler `error` parameter is null if `initPublisher` succeeds, and is defined if it fails.
   *                          `completionHandler` function is called before the Publisher dispatches an `accessAllowed` or an `accessDenied` event
   */
initPublisher(targetElement: string | HTMLElement, param2?, param3?): Publisher {

    let properties: PublisherProperties;

    if (!!param2 && (typeof param2 !== 'function')) {

      // Matches 'initPublisher(targetElement, properties)' or 'initPublisher(targetElement, properties, completionHandler)'

      properties = (<PublisherProperties>param2);

      properties = {
        audioSource: (typeof properties.audioSource !== 'undefined') ? properties.audioSource : undefined,
        frameRate: this.isMediaStreamTrack(properties.videoSource) ? undefined : ((typeof properties.frameRate !== 'undefined') ? properties.frameRate : undefined),
        insertMode: (typeof properties.insertMode !== 'undefined') ? ((typeof properties.insertMode === 'string') ? VideoInsertMode[properties.insertMode] : properties.insertMode) : VideoInsertMode.APPEND,
        mirror: (typeof properties.mirror !== 'undefined') ? properties.mirror : true,
        publishAudio: (typeof properties.publishAudio !== 'undefined') ? properties.publishAudio : true,
        publishVideo: (typeof properties.publishVideo !== 'undefined') ? properties.publishVideo : true,
        resolution: this.isMediaStreamTrack(properties.videoSource) ? undefined : ((typeof properties.resolution !== 'undefined') ? properties.resolution : '640x480'),
        videoSource: (typeof properties.videoSource !== 'undefined') ? properties.videoSource : undefined
      };
    } else {

      // Matches 'initPublisher(targetElement)' or 'initPublisher(targetElement, completionHandler)'

      properties = {
        insertMode: VideoInsertMode.APPEND,
        mirror: true,
        publishAudio: true,
        publishVideo: true,
        resolution: '640x480'
      };
    }

    const publisher: Publisher = new Publisher(targetElement, properties, this);

    let completionHandler: (error: Error | undefined) => void;
    if (!!param2 && (typeof param2 === 'function')) {
      completionHandler = param2;
    } else if (!!param3) {
      completionHandler = param3;
    }

    publisher.initialize()
      .then(() => {
        if (completionHandler !== undefined) {
          completionHandler(undefined);
        }
        publisher.emitEvent('accessAllowed', []);
      }).catch((error) => {
        if (completionHandler !== undefined) {
          completionHandler(error);
        }
        publisher.emitEvent('accessDenied', []);
      });

    this.publishers.push(publisher);
    return publisher;
  }


/**
   * Promisified version of [[OpenVidu.initPublisher]]
   *
   * > WARNING: events `accessDialogOpened` and `accessDialogClosed` will not be dispatched if using this method instead of [[OpenVidu.initPublisher]]
   */
initPublisherAsync(targetElement: string | HTMLElement): Promise<Publisher>;


initPublisherAsync(targetElement: string | HTMLElement, properties: PublisherProperties): Promise<Publisher>;


initPublisherAsync(targetElement: string | HTMLElement, properties?: PublisherProperties): Promise<Publisher> {
    return new Promise<Publisher>((resolve, reject) => {

      let publisher: Publisher;

      const callback = (error: Error) => {
        if (!!error) {
          reject(error);
        } else {
          resolve(publisher);
        }
      };

      if (!!properties) {
        publisher = this.initPublisher(targetElement, properties, callback);
      } else {
        publisher = this.initPublisher(targetElement, callback);
      }
    });
  }


/**
   * Returns a new local recorder for recording streams straight away from the browser
   * @param stream  Stream to record
   */
initLocalRecorder(stream: Stream): LocalRecorder {
    return new LocalRecorder(stream);
  }


/**
   * Checks if the browser supports OpenVidu
   * @returns 1 if the browser supports OpenVidu, 0 otherwise
   */
checkSystemRequirements(): number {
    const browser = platform.name;
    const version = platform.version;

    if ((browser !== 'Chrome') && (browser !== 'Chrome Mobile') &&
      (browser !== 'Firefox') && (browser !== 'Firefox Mobile') && (browser !== 'Firefox for iOS') &&
      (browser !== 'Opera') && (browser !== 'Opera Mobile') &&
      (browser !== 'Safari')) {
      return 0;
    } else {
      return 1;
    }
  }


/**
   * Collects information about the media input devices available on the system. You can pass property `deviceId` of a [[Device]] object as value of `audioSource` or `videoSource` properties in [[initPublisher]] method
   */
getDevices(): Promise<Device[]> {
    return new Promise<Device[]>((resolve, reject) => {
      navigator.mediaDevices.enumerateDevices().then((deviceInfos) => {
        const devices: Device[] = [];
        deviceInfos.forEach(deviceInfo => {
          if (deviceInfo.kind === 'audioinput' || deviceInfo.kind === 'videoinput') {
            devices.push({
              kind: deviceInfo.kind,
              deviceId: deviceInfo.deviceId,
              label: deviceInfo.label
            });
          }
        });
        resolve(devices);
      }).catch((error) => {
        console.error('Error getting devices', error);
        reject(error);
      });
    });
  }


/**
   * Get a MediaStream object that you can customize before calling [[initPublisher]] (pass _MediaStreamTrack_ property of the _MediaStream_ value resolved by the Promise as `audioSource` or `videoSource` properties in [[initPublisher]])
   *
   * Parameter `options` is the same as in [[initPublisher]] second parameter (of type [[PublisherProperties]]), but only the following properties will be applied: `audioSource`, `videoSource`, `frameRate`, `resolution`
   *
   * To customize the Publisher's video, the API for HTMLCanvasElement is very useful. For example, to get a black-and-white video at 10 fps and HD resolution with no sound:
   * ```
   * var OV = new OpenVidu();
   * var FRAME_RATE = 10;
   *
   * OV.getUserMedia({
   *    audioSource: false;
   *    videoSource: undefined,
   *    resolution: '1280x720',
   *    frameRate: FRAME_RATE
   * })
   * .then(mediaStream => {
   *
   *    var videoTrack = mediaStream.getVideoTracks()[0];
   *    var video = document.createElement('video');
   *    video.srcObject = new MediaStream([videoTrack]);
   *
   *    var canvas = document.createElement('canvas');
   *    var ctx = canvas.getContext('2d');
   *    ctx.filter = 'grayscale(100%)';
   *
   *    video.addEventListener('play', () => {
   *      var loop = () => {
   *        if (!video.paused && !video.ended) {
   *          ctx.drawImage(video, 0, 0, 300, 170);
   *          setTimeout(loop, 1000/ FRAME_RATE); // Drawing at 10 fps
   *        }
   *      };
   *      loop();
   *    });
   *    video.play();
   *
   *    var grayVideoTrack = canvas.captureStream(FRAME_RATE).getVideoTracks()[0];
   *    var publisher = this.OV.initPublisher(
   *      myHtmlTarget,
   *      {
   *        audioSource: false,
   *        videoSource: grayVideoTrack
   *      });
   * });
   * ```
   */
getUserMedia(options: PublisherProperties): Promise<MediaStream> {
    return new Promise<MediaStream>((resolve, reject) => {
      this.generateMediaConstraints(options)
        .then(constraints => {
          navigator.mediaDevices.getUserMedia(constraints)
            .then(mediaStream => {
              resolve(mediaStream);
            })
            .catch(error => {
              let errorName: OpenViduErrorName;
              const errorMessage = error.toString();
              if (!(options.videoSource === 'screen')) {
                errorName = OpenViduErrorName.DEVICE_ACCESS_DENIED;
              } else {
                errorName = OpenViduErrorName.SCREEN_CAPTURE_DENIED;
              }
              reject(new OpenViduError(errorName, errorMessage));
            });
        })
        .catch((error: OpenViduError) => {
          reject(error);
        });
    });
  }


/* tslint:disable:no-empty */
/**
   * Disable all logging except error level
   */
enableProdMode(): void {
    console.log = () => { };
    console.debug = () => { };
    console.info = () => { };
    console.warn = () => { };
  }


/* tslint:enable:no-empty */
/**
   * Set OpenVidu advanced configuration options. Currently `configuration` is an object with the following optional properties (see [[OpenViduAdvancedConfiguration]] for more details):
   * - `iceServers`: set custom STUN/TURN servers to be used by OpenVidu Browser
   * - `screenShareChromeExtension`: url to a custom screen share extension for Chrome to be used instead of the default one, based on ours [https://github.com/OpenVidu/openvidu-screen-sharing-chrome-extension](https://github.com/OpenVidu/openvidu-screen-sharing-chrome-extension)
   * - `publisherSpeakingEventsOptions`: custom configuration for the [[PublisherSpeakingEvent]] feature
   */
setAdvancedConfiguration(configuration: OpenViduAdvancedConfiguration): void {
    this.advancedConfiguration = configuration;
  }


/* Hidden methods */
/**
   * @hidden
   */
generateMediaConstraints(publisherProperties: PublisherProperties): Promise<MediaStreamConstraints> {
    return new Promise<MediaStreamConstraints>((resolve, reject) => {
      let audio, video;

      if (publisherProperties.audioSource === null || publisherProperties.audioSource === false) {
        audio = false;
      } else if (publisherProperties.audioSource === undefined) {
        audio = true;
      } else {
        audio = publisherProperties.audioSource;
      }

      if (publisherProperties.videoSource === null || publisherProperties.videoSource === false) {
        video = false;
      } else {
        video = {
          height: {
            ideal: 480
          },
          width: {
            ideal: 640
          }
        };
      }

      const mediaConstraints: MediaStreamConstraints = {
        audio,
        video
      };

      if (typeof mediaConstraints.audio === 'string') {
        mediaConstraints.audio = { deviceId: { exact: mediaConstraints.audio } };
      }

      if (mediaConstraints.video) {

        if (!!publisherProperties.resolution) {
          const widthAndHeight = publisherProperties.resolution.toLowerCase().split('x');
          const width = Number(widthAndHeight[0]);
          const height = Number(widthAndHeight[1]);
          (mediaConstraints.video as any).width.ideal = width;
          (mediaConstraints.video as any).height.ideal = height;
        }

        if (!!publisherProperties.frameRate) {
          (mediaConstraints.video as any).frameRate = { ideal: publisherProperties.frameRate };
        }

        if (!!publisherProperties.videoSource && typeof publisherProperties.videoSource === 'string') {

          if (publisherProperties.videoSource === 'screen') {

            if (platform.name !== 'Chrome' && platform.name!.indexOf('Firefox') === -1) {
              const error = new OpenViduError(OpenViduErrorName.SCREEN_SHARING_NOT_SUPPORTED, 'You can only screen share in desktop Chrome and Firefox. Detected browser: ' + platform.name);
              console.error(error);
              reject(error);
            } else {

              if (!!this.advancedConfiguration.screenShareChromeExtension && !(platform.name!.indexOf('Firefox') !== -1)) {

                // Custom screen sharing extension for Chrome

                screenSharing.getScreenConstraints((error, screenConstraints) => {
                  if (!!error || !!screenConstraints.mandatory && screenConstraints.mandatory.chromeMediaSource === 'screen') {
                    if (error === 'permission-denied' || error === 'PermissionDeniedError') {
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_CAPTURE_DENIED, 'You must allow access to one window of your desktop');
                      console.error(error);
                      reject(error);
                    } else {
                      const extensionId = this.advancedConfiguration.screenShareChromeExtension!.split('/').pop()!!.trim();
                      screenSharing.getChromeExtensionStatus(extensionId, (status) => {
                        if (status === 'installed-disabled') {
                          const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_DISABLED, 'You must enable the screen extension');
                          console.error(error);
                          reject(error);
                        }
                        if (status === 'not-installed') {
                          const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_NOT_INSTALLED, (<string>this.advancedConfiguration.screenShareChromeExtension));
                          console.error(error);
                          reject(error);
                        }
                      });
                    }
                  } else {
                    mediaConstraints.video = screenConstraints;
                    resolve(mediaConstraints);
                  }
                });
              } else {

                // Default screen sharing extension for Chrome

                screenSharingAuto.getScreenId((error, sourceId, screenConstraints) => {
                  if (!!error) {
                    if (error === 'not-installed') {
                      const extensionUrl = !!this.advancedConfiguration.screenShareChromeExtension ? this.advancedConfiguration.screenShareChromeExtension :
                        'https://chrome.google.com/webstore/detail/openvidu-screensharing/lfcgfepafnobdloecchnfaclibenjold';
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_NOT_INSTALLED, extensionUrl);
                      console.error(error);
                      reject(error);
                    } else if (error === 'installed-disabled') {
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_EXTENSION_DISABLED, 'You must enable the screen extension');
                      console.error(error);
                      reject(error);
                    } else if (error === 'permission-denied') {
                      const error = new OpenViduError(OpenViduErrorName.SCREEN_CAPTURE_DENIED, 'You must allow access to one window of your desktop');
                      console.error(error);
                      reject(error);
                    }
                  } else {
                    mediaConstraints.video = screenConstraints.video;
                    resolve(mediaConstraints);
                  }
                });
              }

              publisherProperties.videoSource = 'screen';

            }
          } else {
            // tslint:disable-next-line:no-string-literal
            mediaConstraints.video['deviceId'] = { exact: publisherProperties.videoSource };
            resolve(mediaConstraints);
          }
        } else {
          resolve(mediaConstraints);
        }
      } else {
        resolve(mediaConstraints);
      }
    });
  }


/**
   * @hidden
   */
startWs(onConnectSucces: (error: Error) => void): void {
    const config = {
      heartbeat: 5000,
      sendCloseMessage: false,
      ws: {
        uri: this.wsUri,
        useSockJS: false,
        onconnected: onConnectSucces,
        ondisconnect: this.disconnectCallback.bind(this),
        onreconnecting: this.reconnectingCallback.bind(this),
        onreconnected: this.reconnectedCallback.bind(this)
      },
      rpc: {
        requestTimeout: 10000,
        participantJoined: this.session.onParticipantJoined.bind(this.session),
        participantPublished: this.session.onParticipantPublished.bind(this.session),
        participantUnpublished: this.session.onParticipantUnpublished.bind(this.session),
        participantLeft: this.session.onParticipantLeft.bind(this.session),
        participantEvicted: this.session.onParticipantEvicted.bind(this.session),
        recordingStarted: this.session.onRecordingStarted.bind(this.session),
        recordingStopped: this.session.onRecordingStopped.bind(this.session),
        sendMessage: this.session.onNewMessage.bind(this.session),
        streamPropertyChanged: this.session.onStreamPropertyChanged.bind(this.session),
        iceCandidate: this.session.recvIceCandidate.bind(this.session),
        mediaError: this.session.onMediaError.bind(this.session)
      }
    };
    this.jsonRpcClient = new RpcBuilder.clients.JsonRpcClient(config);
  }


/**
   * @hidden
   */
closeWs(): void {
    this.jsonRpcClient.close();
  }


/**
   * @hidden
   */
sendRequest(method: string, params: any, callback?): void {
    if (params && params instanceof Function) {
      callback = params;
      params = {};
    }
    console.debug('Sending request: {method:"' + method + '", params: ' + JSON.stringify(params) + '}');
    this.jsonRpcClient.send(method, params, callback);
  }


/**
   * @hidden
   */
isMediaStreamTrack(mediaSource: any): boolean {
    const is = (!!mediaSource &&
      mediaSource.enabled !== undefined && typeof mediaSource.enabled === 'boolean' &&
      mediaSource.id !== undefined && typeof mediaSource.id === 'string' &&
      mediaSource.kind !== undefined && typeof mediaSource.kind === 'string' &&
      mediaSource.label !== undefined && typeof mediaSource.label === 'string' &&
      mediaSource.muted !== undefined && typeof mediaSource.muted === 'boolean' &&
      mediaSource.readyState !== undefined && typeof mediaSource.readyState === 'string');
    return is;
  }


/**
   * @hidden
   */
getWsUri(): string {
    return this.wsUri;
  }


/**
   * @hidden
   */
getSecret(): string {
    return this.secret;
  }


/**
   * @hidden
   */
getRecorder(): boolean {
    return this.recorder;
  }


/* Private methods */
private disconnectCallback(): void {
    console.warn('Websocket connection lost');
    if (this.isRoomAvailable()) {
      this.session.onLostConnection();
    } else {
      alert('Connection error. Please reload page.');
    }
  }


private reconnectingCallback(): void {
    console.warn('Websocket connection lost (reconnecting)');
    if (this.isRoomAvailable()) {
      this.session.onLostConnection();
    } else {
      alert('Connection error. Please reload page.');
    }
  }


private reconnectedCallback(): void {
    console.warn('Websocket reconnected');
    if (this.isRoomAvailable()) {
      this.session.onRecoveredConnection();
    } else {
      alert('Connection error. Please reload page.');
    }
  }


private isRoomAvailable(): boolean {
    if (this.session !== undefined && this.session instanceof Session) {
      return true;
    } else {
      console.warn('Session instance not found');
      return false;
    }
  }


props => {
  const classnames = useMemoClassNames();
  const { image = "default" } = props;
  const imageUrl = useMemo(() => {
    if (PRESETS.indexOf(image) !== -1) {
      return `https://img.yzcdn.cn/vant/empty-image-${image}.png`;
    } else {
      return image;
    }
  }, [image]);
  return (
    <View
      className={classnames(
        isExternalClass && "custom-class",
        isNormalClass && props.className,
        "van-empty"


() => {
    if (PRESETS.indexOf(image) !== -1) {
      return `https://img.yzcdn.cn/vant/empty-image-${image}.png`;
    } else {
      return image;
    }
  }


export type VanEmptyProps = {
  image?: string;
  description?: string;

  renderDescription?: React.ReactNode;
  renderImage?: React.ReactNode;

  className?: string;
  "custom-class"?: string;
};


classnames(
        isExternalClass


({
  title: paramTitle,
  description,
  loading,
  cancelText,
  confirmText,
  cancelButtonColor,
  confirmButtonColor,
  onCancel,
  onConfirm,
}: ConfirmModalProps) => {
  const modal = useModal();

  // States
  const [title, setTitle] = useState(paramTitle);

  useEffect(() => {
    if (title === undefined) {
      setTitle('Você confirma?');
    }
  }, [title]);

  const handleOnCancel = (event: GestureResponderEvent) => {
    modal.hide();
    onCancel && onCancel(event);
  };

  const handleOnConfirm = (event: GestureResponderEvent) => {
    modal.hide();
    onConfirm && onConfirm(event);
  };

  return (
    <Container>
      <DefaultContainer>
        <Title>{title}</Title>
        {typeof description === 'string' ? <Description>{description}</Description> : description}
        <ActionButtons>
          <CancelButton outline theme={cancelButtonColor || 'cancel'} onPress={handleOnCancel}>
            {(cancelText || 'Cancelar').toLowerCase()}


() => {
    if (title === undefined) {
      setTitle('Você confirma?');
    }
  }


(event: GestureResponderEvent) => {
    modal.hide();
    onCancel && onCancel(event);
  }


(event: GestureResponderEvent) => {
    modal.hide();
    onConfirm && onConfirm(event);
  }


export type ConfirmModalProps = {
  title?: string;
  description?: string | React.ReactNode;
  danger?: boolean;
  loading?: boolean;
  cancelText?: string;
  confirmText?: string;
  cancelButtonColor?: string;
  confirmButtonColor?: string;
  onCancel?: (event: GestureResponderEvent) => void;
  onConfirm?: (event: GestureResponderEvent) => void;
};


function App() {
  const router = useRouter()
  useEffect(() => {
    const handleRouteChange = (url) => {
      gtag.pageview(url)
    }
    router.events.on('routeChangeComplete', handleRouteChange)
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange)
    }
  }, [router.events])
  return (
    <>
      {/* Global Site Tag (gtag.js) - Google Analytics */}
      <Script
        strategy="afterInteractive"
        src={`https://www.googletagmanager.com/gtag/js?id=${gtag.GA_TRACKING_ID}`}


() => {
    const handleRouteChange = (url) => {
      gtag.pageview(url)
    }
    router.events.on('routeChangeComplete', handleRouteChange)
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange)
    }
  }


(url) => {
      gtag.pageview(url)
    }


() => {
      router.events.off('routeChangeComplete', handleRouteChange)
    }


(förvalt: systemets språk)


(förvalt: 7951 eller testnet: 17951)


(förvalt: 7950 eller testnet: 17950)


(förvalt: 127.0.0.1)


(förvalt: 100)


returns => [Person]


returns => Person


p => p.name === name


returns => [Planet]


returns => [Film]


returns => [Vehicle]


returns => [Starship]


returns => [Species]


@Resolver()
export class PersonResolver {
  @Query(returns => [Person])
  public people() {
    return people;
  }

  @Query(returns => Person, {nullable: true})
  public person(
    @Arg("name")
    name: string
  ) {
    return people.find(p => p.name === name);
  }
}


@Resolver()
export class PlanetResolver {
  @Query(returns => [Planet])
  public planets() {
    return planets;
  }
}


@Resolver()
export class FilmResolver {
  @Query(returns => [Film])
  public films() {
    return films;
  }
}


@Resolver()
export class VehiclesResolver {
  @Query(returns => [Vehicle])
  public vehicles() {
    return vehicles;
  }
}


@Resolver()
export class StarshipsResolver {
  @Query(returns => [Starship])
  public starships() {
    return starships;
  }
}


@Resolver()
export class SpeciesResolver {
  @Query(returns => [Species])
  public species() {
    return species;
  }
}


@Query(returns => [Person])
  public people() {
    return people;
  }


@Query(returns => Person, {nullable: true})
  public person(
    @Arg("name")
    name: string
  ) {
    return people.find(p => p.name === name);
  }


@Query(returns => [Planet])
  public planets() {
    return planets;
  }


@Query(returns => [Film])
  public films() {
    return films;
  }


@Query(returns => [Vehicle])
  public vehicles() {
    return vehicles;
  }


@Query(returns => [Starship])
  public starships() {
    return starships;
  }


@Query(returns => [Species])
  public species() {
    return species;
  }


export function useTickerAssets(testnet: boolean) {
  const fetchAssets = () => fetchAllAssets(testnet)
  return tickerAssetsCache.get(testnet) || tickerAssetsCache.suspend(testnet, fetchAssets)
}


export function useWellKnownAccounts() {
  const wellknownAccounts = React.useMemo(() => {
    return {
      lookup(publicKey: string): Promise<AccountRecord | undefined> {
        return fetchWellKnownAccount(publicKey)
      }
    }
  }, [])

  return wellknownAccounts
}


export function usePriceConversion(currency: CurrencyCode, testnet: boolean) {
  const [xlmPrice, setXlmPrice] = React.useState<number>(0)

  React.useEffect(() => {
    fetchCryptoPrice(currency, testnet).then(setXlmPrice)

    const interval = setInterval(() => {
      fetchCryptoPrice(currency, testnet).then(setXlmPrice)
    }, 60 * 1000)

    return () => clearInterval(interval)
  }, [currency, testnet])

  const conversion = React.useMemo(() => {
    return {
      xlmPrice,
      convertXLM(amount: number | BigNumber): BigNumber {
        return BigNumber(xlmPrice).mul(BigNumber(amount))
      }
    }
  }, [xlmPrice])

  return conversion
}


export function useFiatEstimate(asset: Asset, currency: CurrencyCode, testnet: boolean) {
  const conversion = usePriceConversion(currency, testnet)
  const nativeAsset = React.useMemo(() => Asset.native(), [])
  const tradePair = useLiveOrderbook(asset, nativeAsset, testnet)

  const fiatEstimate = React.useMemo(() => {
    if (asset.getAssetType() === "native") {
      return {
        estimatedPrice: conversion.xlmPrice,
        convertAmount(amount: number | BigNumber) {
          return BigNumber(conversion.convertXLM(amount))
        }
      }
    } else {
      const bestOffers = tradePair.bids
      const bestOffer = bestOffers.length ? bestOffers[0] : undefined
      const bestPrice = bestOffer ? Number(bestOffer.price) : 0

      return {
        estimatedPrice: bestPrice,
        convertAmount(amount: number | BigNumber) {
          return BigNumber(conversion.convertXLM(bestPrice * +amount))
        }
      }
    }
  }, [asset, conversion, tradePair.bids])

  return fiatEstimate
}