export class WindowsTerminal extends Terminal {
  private _isReady: boolean;
  private _deferreds: any[];
  private _agent: WindowsPtyAgent;

  constructor(file?: string, args?: ArgvOrCommandLine, opt?: IWindowsPtyForkOptions) {
    super(opt);

    this._checkType('args', args, 'string', true);

    // Initialize arguments
    args = args || [];
    file = file || DEFAULT_FILE;
    opt = opt || {};
    opt.env = opt.env || process.env;

    if (opt.encoding) {
      console.warn('Setting encoding on Windows is not supported');
    }

    const env = assign({}, opt.env);
    this._cols = opt.cols || DEFAULT_COLS;
    this._rows = opt.rows || DEFAULT_ROWS;
    const cwd = opt.cwd || process.cwd();
    const name = opt.name || env.TERM || DEFAULT_NAME;
    const parsedEnv = this._parseEnv(env);

    // If the terminal is ready
    this._isReady = false;

    // Functions that need to run after `ready` event is emitted.
    this._deferreds = [];

    // Create new termal.
    this._agent = new WindowsPtyAgent(file, args, parsedEnv, cwd, this._cols, this._rows, false, opt.useConpty, opt.conptyInheritCursor);
    this._socket = this._agent.outSocket;

    // Not available until `ready` event emitted.
    this._pid = this._agent.innerPid;
    this._fd = this._agent.fd;
    this._pty = this._agent.pty;

    // The forked windows terminal is not available until `ready` event is
    // emitted.
    this._socket.on('ready_datapipe', () => {

      // These events needs to be forwarded.
      ['connect', 'data', 'end', 'timeout', 'drain'].forEach(event => {
        this._socket.on(event, () => {

          // Wait until the first data event is fired then we can run deferreds.
          if (!this._isReady && event === 'data') {

            // Terminal is now ready and we can avoid having to defer method
            // calls.
            this._isReady = true;

            // Execute all deferred methods
            this._deferreds.forEach(fn => {
              // NB! In order to ensure that `this` has all its references
              // updated any variable that need to be available in `this` before
              // the deferred is run has to be declared above this forEach
              // statement.
              fn.run();
            });

            // Reset
            this._deferreds = [];

          }
        });
      });

      // Shutdown if `error` event is emitted.
      this._socket.on('error', err => {
        // Close terminal session.
        this._close();

        // EIO, happens when someone closes our child process: the only process
        // in the terminal.
        // node < 0.6.14: errno 5
        // node >= 0.6.14: read EIO
        if ((<any>err).code) {
          if (~(<any>err).code.indexOf('errno 5') || ~(<any>err).code.indexOf('EIO')) return;
        }

        // Throw anything else.
        if (this.listeners('error').length < 2) {
          throw err;
        }
      });

      // Cleanup after the socket is closed.
      this._socket.on('close', () => {
        this.emit('exit', this._agent.exitCode);
        this._close();
      });

    });

    this._file = file;
    this._name = name;

    this._readable = true;
    this._writable = true;

    this._forwardEvents();
  }

  protected _write(data: string): void {
    this._defer(this._doWrite, data);
  }

  private _doWrite(data: string): void {
    this._agent.inSocket.write(data);
  }

  /**
   * openpty
   */

  public static open(options?: IPtyOpenOptions): void {
    throw new Error('open() not supported on windows, use Fork() instead.');
  }

  /**
   * TTY
   */

  public resize(cols: number, rows: number): void {
    if (cols <= 0 || rows <= 0 || isNaN(cols) || isNaN(rows) || cols === Infinity || rows === Infinity) {
      throw new Error('resizing must be done using positive cols and rows');
    }
    this._defer(() => {
      this._agent.resize(cols, rows);
      this._cols = cols;
      this._rows = rows;
    });
  }

  public destroy(): void {
    this._defer(() => {
      this.kill();
    });
  }

  public kill(signal?: string): void {
    this._defer(() => {
      if (signal) {
        throw new Error('Signals not supported on windows.');
      }
      this._close();
      this._agent.kill();
    });
  }

  private _defer<A extends any>(deferredFn: (arg?: A) => void, arg?: A): void {
    // If the terminal is ready, execute.
    if (this._isReady) {
      deferredFn.call(this, arg);
      return;
    }

    // Queue until terminal is ready.
    this._deferreds.push({
      run: () => deferredFn.call(this, arg)
    });
  }

  public get process(): string { return this._name; }
  public get master(): Socket { throw new Error('master is not supported on Windows'); }
  public get slave(): Socket { throw new Error('slave is not supported on Windows'); }
}


protected _write(data: string): void {
    this._defer(this._doWrite, data);
  }


private _doWrite(data: string): void {
    this._agent.inSocket.write(data);
  }


/**
   * openpty
   */
public static open(options?: IPtyOpenOptions): void {
    throw new Error('open() not supported on windows, use Fork() instead.');
  }


/**
   * TTY
   */
public resize(cols: number, rows: number): void {
    if (cols <= 0 || rows <= 0 || isNaN(cols) || isNaN(rows) || cols === Infinity || rows === Infinity) {
      throw new Error('resizing must be done using positive cols and rows');
    }
    this._defer(() => {
      this._agent.resize(cols, rows);
      this._cols = cols;
      this._rows = rows;
    });
  }


public destroy(): void {
    this._defer(() => {
      this.kill();
    });
  }


public kill(signal?: string): void {
    this._defer(() => {
      if (signal) {
        throw new Error('Signals not supported on windows.');
      }
      this._close();
      this._agent.kill();
    });
  }


private _defer<A extends any>(deferredFn: (arg?: A) => void, arg?: A): void {
    // If the terminal is ready, execute.
    if (this._isReady) {
      deferredFn.call(this, arg);
      return;
    }

    // Queue until terminal is ready.
    this._deferreds.push({
      run: () => deferredFn.call(this, arg)
    });
  }


() => {
  it('should exist', () => {
    expect(typeof NumericRange).toBe('function');
  });

  it('should start cleared', () => {
    const range = new NumericRange();
    expect(range).toBeDefined();
    expect(range.isDefined).toBe(false);
    expect(range.lowBound).toBeNaN();
    expect(range.highBound).toBeNaN();
  });

  describe('clear', () => {
    it('should reset all values', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = 100;
      range.highBound = 100;

      range.clear();
      expect(range.isDefined).toBe(false);
      expect(range.lowBound).toBeNaN();
      expect(range.highBound).toBeNaN();
    });
  });

  describe('expandToInclude', () => {
    it('should include values when expanded', () => {
      const range = new NumericRange();

      range.expandToInclude(5);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(5);
      expect(range.highBound).toBe(5);

      range.expandToInclude(-5);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);
    });

    it('should not change if expand values are already included', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -5;
      range.highBound = 5;

      range.expandToInclude(2);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);

      range.expandToInclude(-4);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);

      range.expandToInclude(5);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);
    });
  });

  describe('truncateToWithin', () => {
    it('should clear range if entirely outside', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = 0;
      range.highBound = 100;

      range.truncateToWithin(200, Infinity);
      expect(range.isDefined).toBe(false);
      expect(range.lowBound).toBeNaN();
      expect(range.highBound).toBeNaN();
    });

    it('should leave range unchanged if not defined', () => {
      const range = new NumericRange();

      range.truncateToWithin(-200, 200);
      expect(range.isDefined).toBe(false);
      expect(isNaN(range.lowBound)).toBe(true);
      expect(isNaN(range.highBound)).toBe(true);
    });

    it('should reduce range to single value if lowValue = highValue', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -Infinity;
      range.highBound = Infinity;

      range.truncateToWithin(200, 200);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(200);
      expect(range.highBound).toBe(200);
    });

    it('should leave range unchanged if values lie outside', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -50;
      range.highBound = 50;

      range.truncateToWithin(-200, 200);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-50);
      expect(range.highBound).toBe(50);
    });

    it('should clip lowBound if needed', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -50;
      range.highBound = 50;

      range.truncateToWithin(-20, 200);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-20);
      expect(range.highBound).toBe(50);
    });

    it('should clip highBound if needed', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -50;
      range.highBound = 50;

      range.truncateToWithin(-200, 20);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-50);
      expect(range.highBound).toBe(20);
    });
  });

  describe('overlaps', () => {
    it('should return false if either range is not defined.', () => {
      const a = new NumericRange();
      const b = new NumericRange();

      expect(a.overlaps(b)).toBe(false);
      expect(b.overlaps(a)).toBe(false);

      a.expandToInclude(1);

      expect(a.overlaps(b)).toBe(false);
      expect(b.overlaps(a)).toBe(false);
    });

    it('should return false for defined non-overlapping ranges.', () => {
      const a = new NumericRange();
      const b = new NumericRange();

      a.expandToInclude(1);
      a.expandToInclude(5);

      b.expandToInclude(6);
      b.expandToInclude(10);

      expect(a.overlaps(b)).toBe(false);
      expect(b.overlaps(a)).toBe(false);
    });

    it('should return true for covered/covering ranges.', () => {
      const a = new NumericRange();
      const b = new NumericRange();

      a.expandToInclude(1);
      a.expandToInclude(10);

      b.expandToInclude(3);
      b.expandToInclude(7);

      expect(a.overlaps(b)).toBe(true);
      expect(b.overlaps(a)).toBe(true);
    });

    it('should return true for partially overlapping ranges.', () => {
      const a = new NumericRange();
      const b = new NumericRange();

      a.expandToInclude(1);
      a.expandToInclude(8);

      b.expandToInclude(3);
      b.expandToInclude(10);

      expect(a.overlaps(b)).toBe(true);
      expect(b.overlaps(a)).toBe(true);
    });
  });
}


() => {
    expect(typeof NumericRange).toBe('function');
  }


() => {
    const range = new NumericRange();
    expect(range).toBeDefined();
    expect(range.isDefined).toBe(false);
    expect(range.lowBound).toBeNaN();
    expect(range.highBound).toBeNaN();
  }


() => {
    it('should reset all values', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = 100;
      range.highBound = 100;

      range.clear();
      expect(range.isDefined).toBe(false);
      expect(range.lowBound).toBeNaN();
      expect(range.highBound).toBeNaN();
    });
  }


() => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = 100;
      range.highBound = 100;

      range.clear();
      expect(range.isDefined).toBe(false);
      expect(range.lowBound).toBeNaN();
      expect(range.highBound).toBeNaN();
    }


() => {
    it('should include values when expanded', () => {
      const range = new NumericRange();

      range.expandToInclude(5);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(5);
      expect(range.highBound).toBe(5);

      range.expandToInclude(-5);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);
    });

    it('should not change if expand values are already included', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -5;
      range.highBound = 5;

      range.expandToInclude(2);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);

      range.expandToInclude(-4);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);

      range.expandToInclude(5);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);
    });
  }


() => {
      const range = new NumericRange();

      range.expandToInclude(5);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(5);
      expect(range.highBound).toBe(5);

      range.expandToInclude(-5);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);
    }


() => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -5;
      range.highBound = 5;

      range.expandToInclude(2);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);

      range.expandToInclude(-4);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);

      range.expandToInclude(5);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-5);
      expect(range.highBound).toBe(5);
    }


() => {
    it('should clear range if entirely outside', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = 0;
      range.highBound = 100;

      range.truncateToWithin(200, Infinity);
      expect(range.isDefined).toBe(false);
      expect(range.lowBound).toBeNaN();
      expect(range.highBound).toBeNaN();
    });

    it('should leave range unchanged if not defined', () => {
      const range = new NumericRange();

      range.truncateToWithin(-200, 200);
      expect(range.isDefined).toBe(false);
      expect(isNaN(range.lowBound)).toBe(true);
      expect(isNaN(range.highBound)).toBe(true);
    });

    it('should reduce range to single value if lowValue = highValue', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -Infinity;
      range.highBound = Infinity;

      range.truncateToWithin(200, 200);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(200);
      expect(range.highBound).toBe(200);
    });

    it('should leave range unchanged if values lie outside', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -50;
      range.highBound = 50;

      range.truncateToWithin(-200, 200);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-50);
      expect(range.highBound).toBe(50);
    });

    it('should clip lowBound if needed', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -50;
      range.highBound = 50;

      range.truncateToWithin(-20, 200);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-20);
      expect(range.highBound).toBe(50);
    });

    it('should clip highBound if needed', () => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -50;
      range.highBound = 50;

      range.truncateToWithin(-200, 20);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-50);
      expect(range.highBound).toBe(20);
    });
  }


() => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = 0;
      range.highBound = 100;

      range.truncateToWithin(200, Infinity);
      expect(range.isDefined).toBe(false);
      expect(range.lowBound).toBeNaN();
      expect(range.highBound).toBeNaN();
    }


() => {
      const range = new NumericRange();

      range.truncateToWithin(-200, 200);
      expect(range.isDefined).toBe(false);
      expect(isNaN(range.lowBound)).toBe(true);
      expect(isNaN(range.highBound)).toBe(true);
    }


() => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -Infinity;
      range.highBound = Infinity;

      range.truncateToWithin(200, 200);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(200);
      expect(range.highBound).toBe(200);
    }


() => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -50;
      range.highBound = 50;

      range.truncateToWithin(-200, 200);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-50);
      expect(range.highBound).toBe(50);
    }


() => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -50;
      range.highBound = 50;

      range.truncateToWithin(-20, 200);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-20);
      expect(range.highBound).toBe(50);
    }


() => {
      const range = new NumericRange();

      range.isDefined = true;
      range.lowBound = -50;
      range.highBound = 50;

      range.truncateToWithin(-200, 20);
      expect(range.isDefined).toBe(true);
      expect(range.lowBound).toBe(-50);
      expect(range.highBound).toBe(20);
    }


() => {
    it('should return false if either range is not defined.', () => {
      const a = new NumericRange();
      const b = new NumericRange();

      expect(a.overlaps(b)).toBe(false);
      expect(b.overlaps(a)).toBe(false);

      a.expandToInclude(1);

      expect(a.overlaps(b)).toBe(false);
      expect(b.overlaps(a)).toBe(false);
    });

    it('should return false for defined non-overlapping ranges.', () => {
      const a = new NumericRange();
      const b = new NumericRange();

      a.expandToInclude(1);
      a.expandToInclude(5);

      b.expandToInclude(6);
      b.expandToInclude(10);

      expect(a.overlaps(b)).toBe(false);
      expect(b.overlaps(a)).toBe(false);
    });

    it('should return true for covered/covering ranges.', () => {
      const a = new NumericRange();
      const b = new NumericRange();

      a.expandToInclude(1);
      a.expandToInclude(10);

      b.expandToInclude(3);
      b.expandToInclude(7);

      expect(a.overlaps(b)).toBe(true);
      expect(b.overlaps(a)).toBe(true);
    });

    it('should return true for partially overlapping ranges.', () => {
      const a = new NumericRange();
      const b = new NumericRange();

      a.expandToInclude(1);
      a.expandToInclude(8);

      b.expandToInclude(3);
      b.expandToInclude(10);

      expect(a.overlaps(b)).toBe(true);
      expect(b.overlaps(a)).toBe(true);
    });
  }


() => {
      const a = new NumericRange();
      const b = new NumericRange();

      expect(a.overlaps(b)).toBe(false);
      expect(b.overlaps(a)).toBe(false);

      a.expandToInclude(1);

      expect(a.overlaps(b)).toBe(false);
      expect(b.overlaps(a)).toBe(false);
    }


() => {
      const a = new NumericRange();
      const b = new NumericRange();

      a.expandToInclude(1);
      a.expandToInclude(5);

      b.expandToInclude(6);
      b.expandToInclude(10);

      expect(a.overlaps(b)).toBe(false);
      expect(b.overlaps(a)).toBe(false);
    }


() => {
      const a = new NumericRange();
      const b = new NumericRange();

      a.expandToInclude(1);
      a.expandToInclude(10);

      b.expandToInclude(3);
      b.expandToInclude(7);

      expect(a.overlaps(b)).toBe(true);
      expect(b.overlaps(a)).toBe(true);
    }


() => {
      const a = new NumericRange();
      const b = new NumericRange();

      a.expandToInclude(1);
      a.expandToInclude(8);

      b.expandToInclude(3);
      b.expandToInclude(10);

      expect(a.overlaps(b)).toBe(true);
      expect(b.overlaps(a)).toBe(true);
    }


(capture, parse, state) => {
    const [content] = capture
    const { nested } = state

    if (nested) {
      return {
        content,
      }
    }

    return parse(convertEmojiToNames(content), {
      ...state,
      nested: true,
    })
  }


@Component({
    selector: 'app-compare-fieldName-validator',
    templateUrl: './compare-field-name.component.html'
})
export class CompareFieldNameValidatorComponent implements OnInit {
    userFormGroup: FormGroup

	constructor(
        private formBuilder: FormBuilder)
	{ }

    ngOnInit() {
        this.userFormGroup = this.formBuilder.group({
            password:['',],
            confirmPassword:['', RxwebValidators.compare({fieldName:'password'  ,message:'Both Input is not matched' })],
        });
    }
}


ngOnInit() {
        this.userFormGroup = this.formBuilder.group({
            password:['',],
            confirmPassword:['', RxwebValidators.compare({fieldName:'password'  ,message:'Both Input is not matched' })],
        });
    }


/**
 * Deserializes a tile in [b3dm](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/Batched3DModel) format.
 * @internal
 */
export class B3dmReader extends GltfReader {
  public static create(stream: ByteStream, iModel: IModelConnection, modelId: Id64String, is3d: boolean, range: ElementAlignedBox3d,
    system: RenderSystem, yAxisUp: boolean, isLeaf: boolean, tileCenter: Point3d, transformToRoot?: Transform,
    isCanceled?: ShouldAbortReadGltf, idMap?: BatchedTileIdMap): B3dmReader | undefined {
    const header = new B3dmHeader(stream);
    if (!header.isValid)
      return undefined;

    let returnToCenterTransform, pseudoRtcBias;
    if (header.featureTableJson && Array.isArray(header.featureTableJson.RTC_CENTER)) {
      returnToCenterTransform = Transform.createTranslationXYZ(header.featureTableJson.RTC_CENTER[0], header.featureTableJson.RTC_CENTER[1], header.featureTableJson.RTC_CENTER[2]);
    } else {
      /**
       * This is a workaround for tiles generated by
       * context capture which have a large offset from the tileset origin that exceeds the
       * capacity of 32 bit integers. It is essentially an ad hoc RTC applied at read time only if the tile is far from the
       * origin and there is no RTC supplied either with the B3DM of the GLTF.
       * as the vertices are supplied in a quantized format, applying the RTC bias to
       * quantization origin will make these tiles work correctly.
       */
      pseudoRtcBias = Vector3d.create(tileCenter.x, tileCenter.y, tileCenter.z);
    }

    if (undefined !== returnToCenterTransform)
      transformToRoot = transformToRoot ? transformToRoot.multiplyTransformTransform(returnToCenterTransform) : returnToCenterTransform;

    const props = GltfReaderProps.create(stream, yAxisUp);
    const batchTableLength = header.featureTableJson ? JsonUtils.asInt(header.featureTableJson.BATCH_LENGTH, 0) : 0;

    return undefined !== props ? new B3dmReader(props, iModel, modelId, is3d, system, range, isLeaf, batchTableLength,
      transformToRoot, header.batchTableJson, isCanceled, idMap, pseudoRtcBias) : undefined;
  }

  private constructor(props: GltfReaderProps, iModel: IModelConnection, modelId: Id64String, is3d: boolean, system: RenderSystem,
    private _range: ElementAlignedBox3d, private _isLeaf: boolean, private _batchTableLength: number, private _transformToRoot?: Transform, private _batchTableJson?: any
    , isCanceled?: ShouldAbortReadGltf, private _idMap?: BatchedTileIdMap, private _pseudoRtcBias?: Vector3d) {
    super(props, iModel, modelId, is3d, system, BatchType.Primary, isCanceled);
  }

  public async read(): Promise<GltfReaderResult> {
    // NB: For reality models with no batch table, we want the model ID in the feature table
    const featureTable: FeatureTable = new FeatureTable(this._batchTableLength ? this._batchTableLength : 1, this._modelId, this._type);
    if (this._batchTableLength > 0 && this._idMap !== undefined && this._batchTableJson !== undefined) {
      for (let i = 0; i < this._batchTableLength; i++) {
        const feature: any = {};
        for (const key in this._batchTableJson)
          feature[key] = this._batchTableJson[key][i];

        featureTable.insert(new Feature(this._idMap.getBatchId(feature)));
      }
    } else {
      const feature = new Feature(this._modelId);
      featureTable.insert(feature);
    }

    await this.loadTextures();
    if (this._isCanceled)
      return Promise.resolve({ readStatus: TileReadStatus.Canceled, isLeaf: this._isLeaf });

    return Promise.resolve(this.readGltfAndCreateGraphics(this._isLeaf, featureTable, this._range, this._transformToRoot, this._pseudoRtcBias));
  }

  protected readFeatures(features: Mesh.Features, json: any): boolean {
    let batchIds: any;
    if (this._batchTableLength > 0 && undefined !== this._batchTableJson && undefined !== json.attributes && undefined !== (batchIds = super.readBufferData32(json.attributes, "_BATCHID"))) {
      const indices = [];
      for (let i = 0; i < batchIds.count; i++)
        indices.push(batchIds.buffer[i]);

      features.setIndices(indices);
      return true;
    }

    const feature = new Feature(this._modelId);
    features.add(feature, 1);
    return true;
  }
}


public static create(stream: ByteStream, iModel: IModelConnection, modelId: Id64String, is3d: boolean, range: ElementAlignedBox3d,
    system: RenderSystem, yAxisUp: boolean, isLeaf: boolean, tileCenter: Point3d, transformToRoot?: Transform,
    isCanceled?: ShouldAbortReadGltf, idMap?: BatchedTileIdMap): B3dmReader | undefined {
    const header = new B3dmHeader(stream);
    if (!header.isValid)
      return undefined;

    let returnToCenterTransform, pseudoRtcBias;
    if (header.featureTableJson && Array.isArray(header.featureTableJson.RTC_CENTER)) {
      returnToCenterTransform = Transform.createTranslationXYZ(header.featureTableJson.RTC_CENTER[0], header.featureTableJson.RTC_CENTER[1], header.featureTableJson.RTC_CENTER[2]);
    } else {
      /**
       * This is a workaround for tiles generated by
       * context capture which have a large offset from the tileset origin that exceeds the
       * capacity of 32 bit integers. It is essentially an ad hoc RTC applied at read time only if the tile is far from the
       * origin and there is no RTC supplied either with the B3DM of the GLTF.
       * as the vertices are supplied in a quantized format, applying the RTC bias to
       * quantization origin will make these tiles work correctly.
       */
      pseudoRtcBias = Vector3d.create(tileCenter.x, tileCenter.y, tileCenter.z);
    }

    if (undefined !== returnToCenterTransform)
      transformToRoot = transformToRoot ? transformToRoot.multiplyTransformTransform(returnToCenterTransform) : returnToCenterTransform;

    const props = GltfReaderProps.create(stream, yAxisUp);
    const batchTableLength = header.featureTableJson ? JsonUtils.asInt(header.featureTableJson.BATCH_LENGTH, 0) : 0;

    return undefined !== props ? new B3dmReader(props, iModel, modelId, is3d, system, range, isLeaf, batchTableLength,
      transformToRoot, header.batchTableJson, isCanceled, idMap, pseudoRtcBias) : undefined;
  }


public async read(): Promise<GltfReaderResult> {
    // NB: For reality models with no batch table, we want the model ID in the feature table
    const featureTable: FeatureTable = new FeatureTable(this._batchTableLength ? this._batchTableLength : 1, this._modelId, this._type);
    if (this._batchTableLength > 0 && this._idMap !== undefined && this._batchTableJson !== undefined) {
      for (let i = 0; i < this._batchTableLength; i++) {
        const feature: any = {};
        for (const key in this._batchTableJson)
          feature[key] = this._batchTableJson[key][i];

        featureTable.insert(new Feature(this._idMap.getBatchId(feature)));
      }
    } else {
      const feature = new Feature(this._modelId);
      featureTable.insert(feature);
    }

    await this.loadTextures();
    if (this._isCanceled)
      return Promise.resolve({ readStatus: TileReadStatus.Canceled, isLeaf: this._isLeaf });

    return Promise.resolve(this.readGltfAndCreateGraphics(this._isLeaf, featureTable, this._range, this._transformToRoot, this._pseudoRtcBias));
  }


protected readFeatures(features: Mesh.Features, json: any): boolean {
    let batchIds: any;
    if (this._batchTableLength > 0 && undefined !== this._batchTableJson && undefined !== json.attributes && undefined !== (batchIds = super.readBufferData32(json.attributes, "_BATCHID"))) {
      const indices = [];
      for (let i = 0; i < batchIds.count; i++)
        indices.push(batchIds.buffer[i]);

      features.setIndices(indices);
      return true;
    }

    const feature = new Feature(this._modelId);
    features.add(feature, 1);
    return true;
  }


export class BaseCreateServiceInstanceStepper {
  public tiles = new TileSelector();
  public selectServiceType(type: SERVICE_INSTANCE_TYPES) {
    switch (type) {
      case SERVICE_INSTANCE_TYPES.SERVICE:
        this.tiles.select('Marketplace Service');
        return new CreateMarketplaceServiceInstance();
    }
  }
}


public selectServiceType(type: SERVICE_INSTANCE_TYPES) {
    switch (type) {
      case SERVICE_INSTANCE_TYPES.SERVICE:
        this.tiles.select('Marketplace Service');
        return new CreateMarketplaceServiceInstance();
    }
  }


// this high abstract handler implements ProxyHandler, and TSLints tries to force more detailed typing
/* eslint-disable @typescript-eslint/ban-types */
export function createDynamicObjectHandler<T extends object>(instanceResolver: () => T): ProxyHandler<T> {
    return {
        apply(target: T, thisArg: any, argArray: Array<any>): any {
            throw new NotImplementedException();
        },
        construct(target: T, argArray: Array<any>, newTarget: Function): object {
            throw new NotImplementedException();
        },
        defineProperty(target: T, p: string | symbol, attributes: PropertyDescriptor): boolean {
            throw new NotImplementedException();
        },
        deleteProperty(target: T, p: string | symbol): boolean {
            throw new NotImplementedException();
        },
        get(target: T, p: string | symbol, receiver: any): any {
            return instanceResolver()[p];
        },
        getOwnPropertyDescriptor(target: T, p: string | symbol): PropertyDescriptor | undefined {
            throw new NotImplementedException();
        },
        getPrototypeOf(target: T): object | null {
            return Object.getPrototypeOf(instanceResolver());
        },
        has(target: T, p: string | symbol): boolean {
            return !!instanceResolver()[p];
        },
        isExtensible(target: T): boolean {
            throw new NotImplementedException();
        },
        ownKeys(target: T): ArrayLike<string | symbol> {
            throw new NotImplementedException();
        },
        preventExtensions(target: T): boolean {
            throw new NotImplementedException();
        },
        set(target: T, p: string | symbol, value: any, receiver: any): boolean {
            return (instanceResolver()[p] = value);
        },
        setPrototypeOf(target: T, v: object | null): boolean {
            throw new NotImplementedException();
        },
    };
}


class NotImplementedException extends Error {
    constructor(message?: string) {
        message ??= 'Not implemented. Feel free to implement.';
        super(message);
    }
}


apply(target: T, thisArg: any, argArray: Array<any>): any {
            throw new NotImplementedException();
        }


construct(target: T, argArray: Array<any>, newTarget: Function): object {
            throw new NotImplementedException();
        }


defineProperty(target: T, p: string | symbol, attributes: PropertyDescriptor): boolean {
            throw new NotImplementedException();
        }


deleteProperty(target: T, p: string | symbol): boolean {
            throw new NotImplementedException();
        }


get(target: T, p: string | symbol, receiver: any): any {
            return instanceResolver()[p];
        }


getOwnPropertyDescriptor(target: T, p: string | symbol): PropertyDescriptor | undefined {
            throw new NotImplementedException();
        }


getPrototypeOf(target: T): object | null {
            return Object.getPrototypeOf(instanceResolver());
        }


has(target: T, p: string | symbol): boolean {
            return !!instanceResolver()[p];
        }


isExtensible(target: T): boolean {
            throw new NotImplementedException();
        }


ownKeys(target: T): ArrayLike<string | symbol> {
            throw new NotImplementedException();
        }


preventExtensions(target: T): boolean {
            throw new NotImplementedException();
        }


set(target: T, p: string | symbol, value: any, receiver: any): boolean {
            return (instanceResolver()[p] = value);
        }


setPrototypeOf(target: T, v: object | null): boolean {
            throw new NotImplementedException();
        }


/**
 * Returns `true` if FormControl's value represents a valid SSN,
 * otherwise returns `false`.
 */
function ssnValidator(control: FormControl): {[key: string]: any} {
  const value: string = control.value || '';
  const valid = value.match(/^\d{9}$/);
  return valid ? null : {ssn: true};
}


@Component({
  selector: 'app',
  template: `
    <form [formGroup]="form">
      SSN: <input type="text" formControlName="my-ssn">
           <span [hidden]="!form.hasError('ssn', 'my-ssn')">SSN in invalid</span>
    </form>
  `
})
class AppComponent {
  form: FormGroup;

  constructor() {
    this.form = new FormGroup({
      'my-ssn': new FormControl('', ssnValidator)
    });
  }
}


@NgModule({
  imports     : [ BrowserModule, ReactiveFormsModule ],
  declarations: [ AppComponent ],
  bootstrap   : [ AppComponent ]
})
class AppModule {}


({ index, height, children }) => {
  const { sizes } = useVScrollerState();

  if (height) {
    sizes.set(index, height);
    return children as ReactElement;
  }

  return <Resizer onResize={(e) => sizes.set(index, e.height)}>{children}</Resizer>;
}


(e) => sizes.set(index, e.height)


type VScrollerItemProps = {
  /** Index of the item being rendered */
  index: number;
  /** The height of the item, if known and fixed */
  height?: number;
};


/**
 * Buffers the source Observable values until the size hits the maximum
 * `bufferSize` given.
 *
 * Collects values from the past as an array, and emits
 * that array only when its size reaches `bufferSize`.
 *
 *
 *
 * Buffers a number of values from the source Observable by `bufferSize` then
 * emits the buffer and clears it, and starts a new buffer each
 * `startBufferEvery` values. If `startBufferEvery` is not provided or is
 * `null`, then new buffers are started immediately at the start of the source
 * and when each buffer closes and is emitted.
 *
 * @example
Emit the last two click events as an array

 * var clicks = Rx.Observable.fromEvent(document, 'click');
 * var buffered = clicks.bufferCount(2);
 * buffered.subscribe(x => console.log(x));
 *
 * @example
On every click, emit the last two click events as an array

 * var clicks = Rx.Observable.fromEvent(document, 'click');
 * var buffered = clicks.bufferCount(2, 1);
 * buffered.subscribe(x => console.log(x));
 *
 * @see {@link buffer}
 * @see {@link bufferTime}
 * @see {@link bufferToggle}
 * @see {@link bufferWhen}
 * @see {@link windowCount}
 *
 * @param {number} bufferSize The maximum size of the buffer emitted.
 * @param {number} [startBufferEvery] Interval at which to start a new buffer.
 * For example if `startBufferEvery` is `2`, then a new buffer will be started
 * on every other value from the source. A new buffer is started at the
 * beginning of the source by default.
 * @return {Observable<T[]>} An Observable of arrays of buffered values.
 * @method bufferCount
 * @owner Observable
 */
export function bufferCount<T>(bufferSize: number, startBufferEvery: number = null): Observable<T[]> {
  return this.lift(new BufferCountOperator<T>(bufferSize, startBufferEvery));
}


class BufferCountOperator<T> implements Operator<T, T[]> {
  constructor(private bufferSize: number, private startBufferEvery: number) {
  }

  call(subscriber: Subscriber<T[]>, source: any): any {
    return source._subscribe(new BufferCountSubscriber(subscriber, this.bufferSize, this.startBufferEvery));
  }
}


/**
 * We need this JSDoc comment for affecting ESDoc.
 * @ignore
 * @extends {Ignored}
 */
class BufferCountSubscriber<T> extends Subscriber<T> {
  private buffers: Array<T[]> = [[]];
  private count: number = 0;

  constructor(destination: Subscriber<T[]>, private bufferSize: number, private startBufferEvery: number) {
    super(destination);
  }

  protected _next(value: T) {
    const count = (this.count += 1);
    const destination = this.destination;
    const bufferSize = this.bufferSize;
    const startBufferEvery = (this.startBufferEvery == null) ? bufferSize : this.startBufferEvery;
    const buffers = this.buffers;
    const len = buffers.length;
    let remove = -1;

    if (count % startBufferEvery === 0) {
      buffers.push([]);
    }

    for (let i = 0; i < len; i++) {
      const buffer = buffers[i];
      buffer.push(value);
      if (buffer.length === bufferSize) {
        remove = i;
        destination.next(buffer);
      }
    }

    if (remove !== -1) {
      buffers.splice(remove, 1);
    }
  }

  protected _complete() {
    const destination = this.destination;
    const buffers = this.buffers;
    while (buffers.length > 0) {
      let buffer = buffers.shift();
      if (buffer.length > 0) {
        destination.next(buffer);
      }
    }
    super._complete();
  }
}


export interface BufferCountSignature<T> {
  (bufferSize: number, startBufferEvery?: number): Observable<T[]>;
}


call(subscriber: Subscriber<T[]>, source: any): any {
    return source._subscribe(new BufferCountSubscriber(subscriber, this.bufferSize, this.startBufferEvery));
  }


protected _next(value: T) {
    const count = (this.count += 1);
    const destination = this.destination;
    const bufferSize = this.bufferSize;
    const startBufferEvery = (this.startBufferEvery == null) ? bufferSize : this.startBufferEvery;
    const buffers = this.buffers;
    const len = buffers.length;
    let remove = -1;

    if (count % startBufferEvery === 0) {
      buffers.push([]);
    }

    for (let i = 0; i < len; i++) {
      const buffer = buffers[i];
      buffer.push(value);
      if (buffer.length === bufferSize) {
        remove = i;
        destination.next(buffer);
      }
    }

    if (remove !== -1) {
      buffers.splice(remove, 1);
    }
  }


protected _complete() {
    const destination = this.destination;
    const buffers = this.buffers;
    while (buffers.length > 0) {
      let buffer = buffers.shift();
      if (buffer.length > 0) {
        destination.next(buffer);
      }
    }
    super._complete();
  }


/**
 * Resourceguard
 *
 * @export
 * @class ResourceGuard
 * @implements {CanActivate}
 */
@Injectable()
export class ResourceGuard implements CanActivate {
  /**
   *Creates an instance of ResourceGuard.
   * @param {Reflector} reflector
   * @memberof ResourceGuard
   */
  constructor(private readonly reflector: Reflector) { }

  /**
   * Method canActivate
   *
   * @param {ExecutionContext} context
   * @returns {boolean}
   * @memberof ResourceGuard
   */
  canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    // console.log(roles);
    if (!roles) {
      return false;
    }

    const request = context.switchToHttp().getRequest();
    const user = request.user;
    // console.log(request);

    // check user permission list
    const isInPermisson = true;

    if (isInPermisson) {
      request.accessLevel = "all";

      return true;
    }
    return false;
  }
}


/**
   * Method canActivate
   *
   * @param {ExecutionContext} context
   * @returns {boolean}
   * @memberof ResourceGuard
   */
canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    // console.log(roles);
    if (!roles) {
      return false;
    }

    const request = context.switchToHttp().getRequest();
    const user = request.user;
    // console.log(request);

    // check user permission list
    const isInPermisson = true;

    if (isInPermisson) {
      request.accessLevel = "all";

      return true;
    }
    return false;
  }


export function stringEnumValues<E extends EnumUnderlayingType>(
  enumObject: StandardEnum<E>
) {
  return Object.values(enumObject).filter(
    (value): value is Extract<E, string> =>
      typeof value === "string" &&
      // Number enum value has double mapping: both name to value and value to name.
      // So when the value can be mapped to a number, it should be the name of a number enum value.
      typeof Reflect.get(enumObject, value) !== "number"
  );
}


export function numberEnumValues<E extends EnumUnderlayingType>(
  enumObject: StandardEnum<E>
) {
  return Object.values(enumObject).filter(
    (value): value is Extract<E, number> => typeof value === "number"
  );
}


export function enumValues<E extends EnumUnderlayingType>(
  enumObject: StandardEnum<E>
) {
  return Object.values(enumObject).filter(
    (value): value is E => typeof Reflect.get(enumObject, value) !== "number"
  );
}


export function enumKeys<T extends StandardEnum<EnumUnderlayingType>>(
  standardEnum: T
) {
  return Object.keys(standardEnum).filter((key): key is StringKey<T> =>
    isNaN(+key)
  );
}


(value): value is Extract<E, string> =>
      typeof value === "string" &&
      // Number enum value has double mapping: both name to value and value to name.
      // So when the value can be mapped to a number, it should be the name of a number enum value.
      typeof Reflect.get(enumObject, value) !== "number"


(value): value is Extract<E, number> => typeof value === "number"


(value): value is E => typeof Reflect.get(enumObject, value) !== "number"


(key): key is StringKey<T> =>
    isNaN(+key)


/**
 * Gets the first focusable element.
 *
 * @public
 */
export function getFirstFocusable(
  rootElement: HTMLElement,
  currentElement: HTMLElement,
  includeElementsInFocusZones?: boolean,
): HTMLElement | null {
  return getNextElement(
    rootElement,
    currentElement,
    true /*checkNode*/,
    false /*suppressParentTraversal*/,
    false /*suppressChildTraversal*/,
    includeElementsInFocusZones,
  );
}


/**
 * Gets the last focusable element.
 *
 * @public
 */
export function getLastFocusable(
  rootElement: HTMLElement,
  currentElement: HTMLElement,
  includeElementsInFocusZones?: boolean,
): HTMLElement | null {
  return getPreviousElement(
    rootElement,
    currentElement,
    true /*checkNode*/,
    false /*suppressParentTraversal*/,
    true /*traverseChildren*/,
    includeElementsInFocusZones,
  );
}


/**
 * Gets the first tabbable element. (The difference between focusable and tabbable is that tabbable elements are
 * focusable elements that also have tabIndex != -1.)
 * @param rootElement - The parent element to search beneath.
 * @param currentElement - The descendant of rootElement to start the search at.  This element is the first one checked,
 * and iteration continues forward.  Typical use passes rootElement.firstChild.
 * @param includeElementsInFocusZones - true if traversal should go into FocusZone descendants.
 * @param checkNode - Include currentElement in search when true. Defaults to true.
 * @public
 */
export function getFirstTabbable(
  rootElement: HTMLElement,
  currentElement: HTMLElement,
  includeElementsInFocusZones?: boolean,
  checkNode: boolean = true,
): HTMLElement | null {
  return getNextElement(
    rootElement,
    currentElement,
    checkNode,
    false /*suppressParentTraversal*/,
    false /*suppressChildTraversal*/,
    includeElementsInFocusZones,
    false /*allowFocusRoot*/,
    true /*tabbable*/,
  );
}


/**
 * Gets the last tabbable element. (The difference between focusable and tabbable is that tabbable elements are
 * focusable elements that also have tabIndex != -1.)
 * @param rootElement - The parent element to search beneath.
 * @param currentElement - The descendant of rootElement to start the search at.  This element is the first one checked,
 * and iteration continues in reverse.  Typical use passes rootElement.lastChild.
 * @param includeElementsInFocusZones - true if traversal should go into FocusZone descendants.
 * @param checkNode - Include currentElement in search when true. Defaults to true.
 * @public
 */
export function getLastTabbable(
  rootElement: HTMLElement,
  currentElement: HTMLElement,
  includeElementsInFocusZones?: boolean,
  checkNode: boolean = true,
): HTMLElement | null {
  return getPreviousElement(
    rootElement,
    currentElement,
    checkNode,
    false /*suppressParentTraversal*/,
    true /*traverseChildren*/,
    includeElementsInFocusZones,
    false /*allowFocusRoot*/,
    true /*tabbable*/,
  );
}


/**
 * Attempts to focus the first focusable element that is a child or child's child of the rootElement.
 *
 * @public
 * @param rootElement - Element to start the search for a focusable child.
 * @returns True if focus was set, false if it was not.
 */
export function focusFirstChild(rootElement: HTMLElement): boolean {
  let element: HTMLElement | null = getNextElement(rootElement, rootElement, true, false, false, true);

  if (element) {
    focusAsync(element);
    return true;
  }
  return false;
}


/**
 * Traverse to find the previous element.
 * If tabbable is true, the element must have tabIndex != -1.
 *
 * @public
 */
export function getPreviousElement(
  rootElement: HTMLElement,
  currentElement: HTMLElement | null,
  checkNode?: boolean,
  suppressParentTraversal?: boolean,
  traverseChildren?: boolean,
  includeElementsInFocusZones?: boolean,
  allowFocusRoot?: boolean,
  tabbable?: boolean,
): HTMLElement | null {
  if (!currentElement || (!allowFocusRoot && currentElement === rootElement)) {
    return null;
  }

  let isCurrentElementVisible = isElementVisible(currentElement);

  // Check its children.
  if (
    traverseChildren &&
    isCurrentElementVisible &&
    (includeElementsInFocusZones || !(isElementFocusZone(currentElement) || isElementFocusSubZone(currentElement)))
  ) {
    const childMatch = getPreviousElement(
      rootElement,
      currentElement.lastElementChild as HTMLElement,
      true,
      true,
      true,
      includeElementsInFocusZones,
      allowFocusRoot,
      tabbable,
    );

    if (childMatch) {
      if ((tabbable && isElementTabbable(childMatch, true)) || !tabbable) {
        return childMatch;
      }

      const childMatchSiblingMatch = getPreviousElement(
        rootElement,
        childMatch.previousElementSibling as HTMLElement,
        true,
        true,
        true,
        includeElementsInFocusZones,
        allowFocusRoot,
        tabbable,
      );
      if (childMatchSiblingMatch) {
        return childMatchSiblingMatch;
      }

      let childMatchParent = childMatch.parentElement;

      // At this point if we have not found any potential matches
      // start looking at the rest of the subtree under the currentParent.
      // NOTE: We do not want to recurse here because doing so could
      // cause elements to get skipped.
      while (childMatchParent && childMatchParent !== currentElement) {
        const childMatchParentMatch = getPreviousElement(
          rootElement,
          childMatchParent.previousElementSibling as HTMLElement,
          true,
          true,
          true,
          includeElementsInFocusZones,
          allowFocusRoot,
          tabbable,
        );

        if (childMatchParentMatch) {
          return childMatchParentMatch;
        }

        childMatchParent = childMatchParent.parentElement;
      }
    }
  }

  // Check the current node, if it's not the first traversal.
  if (checkNode && isCurrentElementVisible && isElementTabbable(currentElement, tabbable)) {
    return currentElement;
  }

  // Check its previous sibling.
  const siblingMatch = getPreviousElement(
    rootElement,
    currentElement.previousElementSibling as HTMLElement,
    true,
    true,
    true,
    includeElementsInFocusZones,
    allowFocusRoot,
    tabbable,
  );

  if (siblingMatch) {
    return siblingMatch;
  }

  // Check its parent.
  if (!suppressParentTraversal) {
    return getPreviousElement(
      rootElement,
      currentElement.parentElement,
      true,
      false,
      false,
      includeElementsInFocusZones,
      allowFocusRoot,
      tabbable,
    );
  }

  return null;
}


/**
 * Traverse to find the next focusable element.
 * If tabbable is true, the element must have tabIndex != -1.
 *
 * @public
 * @param checkNode - Include currentElement in search when true.
 */
export function getNextElement(
  rootElement: HTMLElement,
  currentElement: HTMLElement | null,
  checkNode?: boolean,
  suppressParentTraversal?: boolean,
  suppressChildTraversal?: boolean,
  includeElementsInFocusZones?: boolean,
  allowFocusRoot?: boolean,
  tabbable?: boolean,
): HTMLElement | null {
  if (!currentElement || (currentElement === rootElement && suppressChildTraversal && !allowFocusRoot)) {
    return null;
  }

  let isCurrentElementVisible = isElementVisible(currentElement);

  // Check the current node, if it's not the first traversal.
  if (checkNode && isCurrentElementVisible && isElementTabbable(currentElement, tabbable)) {
    return currentElement;
  }

  // Check its children.
  if (
    !suppressChildTraversal &&
    isCurrentElementVisible &&
    (includeElementsInFocusZones || !(isElementFocusZone(currentElement) || isElementFocusSubZone(currentElement)))
  ) {
    const childMatch = getNextElement(
      rootElement,
      currentElement.firstElementChild as HTMLElement,
      true,
      true,
      false,
      includeElementsInFocusZones,
      allowFocusRoot,
      tabbable,
    );

    if (childMatch) {
      return childMatch;
    }
  }

  if (currentElement === rootElement) {
    return null;
  }

  // Check its sibling.
  const siblingMatch = getNextElement(
    rootElement,
    currentElement.nextElementSibling as HTMLElement,
    true,
    true,
    false,
    includeElementsInFocusZones,
    allowFocusRoot,
    tabbable,
  );

  if (siblingMatch) {
    return siblingMatch;
  }

  if (!suppressParentTraversal) {
    return getNextElement(
      rootElement,
      currentElement.parentElement,
      false,
      false,
      true,
      includeElementsInFocusZones,
      allowFocusRoot,
      tabbable,
    );
  }

  return null;
}


/**
 * Determines if an element is visible.
 *
 * @public
 */
export function isElementVisible(element: HTMLElement | undefined | null): boolean {
  // If the element is not valid, return false.
  if (!element || !element.getAttribute) {
    return false;
  }

  const visibilityAttribute = element.getAttribute(IS_VISIBLE_ATTRIBUTE);

  // If the element is explicitly marked with the visibility attribute, return that value as boolean.
  if (visibilityAttribute !== null && visibilityAttribute !== undefined) {
    return visibilityAttribute === 'true';
  }

  // Fallback to other methods of determining actual visibility.
  return (
    element.offsetHeight !== 0 ||
    element.offsetParent !== null ||
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (element as any).isVisible === true
  ); // used as a workaround for testing.
}


/**
 * Determines if an element can receive focus programmatically or via a mouse click.
 * If checkTabIndex is true, additionally checks to ensure the element can be focused with the tab key,
 * meaning tabIndex != -1.
 *
 * @public
 */
export function isElementTabbable(element: HTMLElement, checkTabIndex?: boolean): boolean {
  // If this element is null or is disabled, it is not considered tabbable.
  if (!element || (element as HTMLButtonElement).disabled) {
    return false;
  }

  let tabIndex = 0;
  let tabIndexAttributeValue = null;

  if (element && element.getAttribute) {
    tabIndexAttributeValue = element.getAttribute('tabIndex');

    if (tabIndexAttributeValue) {
      tabIndex = parseInt(tabIndexAttributeValue, 10);
    }
  }

  let isFocusableAttribute = element.getAttribute ? element.getAttribute(IS_FOCUSABLE_ATTRIBUTE) : null;
  let isTabIndexSet = tabIndexAttributeValue !== null && tabIndex >= 0;

  const result =
    !!element &&
    isFocusableAttribute !== 'false' &&
    (element.tagName === 'A' ||
      element.tagName === 'BUTTON' ||
      element.tagName === 'INPUT' ||
      element.tagName === 'TEXTAREA' ||
      element.tagName === 'SELECT' ||
      isFocusableAttribute === 'true' ||
      isTabIndexSet);

  return checkTabIndex ? tabIndex !== -1 && result : result;
}


/**
 * Determines if a given element is a focus zone.
 *
 * @public
 */
export function isElementFocusZone(element?: HTMLElement): boolean {
  return !!(element && element.getAttribute && !!element.getAttribute(FOCUSZONE_ID_ATTRIBUTE));
}


/**
 * Determines if a given element is a focus sub zone.
 *
 * @public
 */
export function isElementFocusSubZone(element?: HTMLElement): boolean {
  return !!(element && element.getAttribute && element.getAttribute(FOCUSZONE_SUB_ATTRIBUTE) === 'true');
}


/**
 * Determines if an element, or any of its children, contain focus.
 *
 * @public
 */
export function doesElementContainFocus(element: HTMLElement): boolean {
  let document = getDocument(element);
  let currentActiveElement: HTMLElement | undefined = document && (document.activeElement as HTMLElement);
  if (currentActiveElement && elementContains(element, currentActiveElement)) {
    return true;
  }
  return false;
}


/**
 * Determines if an, or any of its ancestors, sepcificies that it doesn't want focus to wrap
 * @param element - element to start searching from
 * @param noWrapDataAttribute - the no wrap data attribute to match (either)
 * @returns true if focus should wrap, false otherwise
 */
export function shouldWrapFocus(
  element: HTMLElement,
  noWrapDataAttribute: 'data-no-vertical-wrap' | 'data-no-horizontal-wrap',
): boolean {
  return elementContainsAttribute(element, noWrapDataAttribute) === 'true' ? false : true;
}


/**
 * Sets focus to an element asynchronously. The focus will be set at the next browser repaint,
 * meaning it won't cause any extra recalculations. If more than one focusAsync is called during one frame,
 * only the latest called focusAsync element will actually be focused
 * @param element - The element to focus
 */
export function focusAsync(element: HTMLElement | { focus: () => void } | undefined | null): void {
  if (element) {
    // An element was already queued to be focused, so replace that one with the new element
    if (targetToFocusOnNextRepaint) {
      targetToFocusOnNextRepaint = element;
      return;
    }

    targetToFocusOnNextRepaint = element;

    const win = getWindow(element as Element);

    if (win) {
      // element.focus() is a no-op if the element is no longer in the DOM, meaning this is always safe
      win.requestAnimationFrame(() => {
        targetToFocusOnNextRepaint && targetToFocusOnNextRepaint.focus();

        // We are done focusing for this frame, so reset the queued focus element
        targetToFocusOnNextRepaint = undefined;
      });
    }
  }
}


/**
 * Finds the closest focusable element via an index path from a parent. See
 * `getElementIndexPath` for getting an index path from an element to a child.
 */
export function getFocusableByIndexPath(parent: HTMLElement, path: number[]): HTMLElement | undefined {
  let element = parent;

  for (const index of path) {
    const nextChild = element.children[Math.min(index, element.children.length - 1)] as HTMLElement;

    if (!nextChild) {
      break;
    }
    element = nextChild;
  }

  element =
    isElementTabbable(element) && isElementVisible(element)
      ? element
      : getNextElement(parent, element, true) || getPreviousElement(parent, element)!;

  return element as HTMLElement;
}


/**
 * Finds the element index path from a parent element to a child element.
 *
 * If you had this node structure: "A has children [B, C] and C has child D",
 * the index path from A to D would be [1, 0], or `parent.chidren[1].children[0]`.
 */
export function getElementIndexPath(fromElement: HTMLElement, toElement: HTMLElement): number[] {
  const path: number[] = [];

  while (toElement && fromElement && toElement !== fromElement) {
    const parent = getParent(toElement, true);

    if (parent === null) {
      return [];
    }

    path.unshift(Array.prototype.indexOf.call(parent.children, toElement));
    toElement = parent;
  }

  return path;
}


() => {
        targetToFocusOnNextRepaint && targetToFocusOnNextRepaint.focus();

        // We are done focusing for this frame, so reset the queued focus element
        targetToFocusOnNextRepaint = undefined;
      }


export declare class AgmInfoWindow implements OnDestroy, OnChanges, OnInit {
    private _infoWindowManager;
    private _el;
    /**
     * The latitude position of the info window (only usefull if you use it ouside of a {@link
     * AgmMarker}).
     */
    latitude: number;
    /**
     * The longitude position of the info window (only usefull if you use it ouside of a {@link
     * AgmMarker}).
     */
    longitude: number;
    /**
     * Disable auto-pan on open. By default, the info window will pan the map so that it is fully
     * visible when it opens.
     */
    disableAutoPan: boolean;
    /**
     * All InfoWindows are displayed on the map in order of their zIndex, with higher values
     * displaying in front of InfoWindows with lower values. By default, InfoWindows are displayed
     * according to their latitude, with InfoWindows of lower latitudes appearing in front of
     * InfoWindows at higher latitudes. InfoWindows are always displayed in front of markers.
     */
    zIndex: number;
    /**
     * Maximum width of the infowindow, regardless of content's width. This value is only considered
     * if it is set before a call to open. To change the maximum width when changing content, call
     * close, update maxWidth, and then open.
     */
    maxWidth: number;
    /**
     * Holds the marker that is the host of the info window (if available)
     */
    hostMarker: AgmMarker;
    /**
     * Holds the native element that is used for the info window content.
     */
    content: Node;
    /**
     * Sets the open state for the InfoWindow. You can also call the open() and close() methods.
     */
    isOpen: boolean;
    /**
     * Emits an event when the info window is closed.
     */
    infoWindowClose: EventEmitter<void>;
    private static _infoWindowOptionsInputs;
    private _infoWindowAddedToManager;
    private _id;
    constructor(_infoWindowManager: InfoWindowManager, _el: ElementRef);
    ngOnInit(): void;
    /** @internal */
    ngOnChanges(changes: {
        [key: string]: SimpleChange;
    }): void;
    private _registerEventListeners;
    private _updateOpenState;
    private _setInfoWindowOptions;
    /**
     * Opens the info window.
     */
    open(): Promise<void>;
    /**
     * Closes the info window.
     */
    close(): Promise<void>;
    /** @internal */
    id(): string;
    /** @internal */
    toString(): string;
    /** @internal */
    ngOnDestroy(): void;
    static ɵfac: ɵngcc0.ɵɵFactoryDef<AgmInfoWindow, never>;
    static ɵcmp: ɵngcc0.ɵɵComponentDefWithMeta<AgmInfoWindow, "agm-info-window", never, { "isOpen": "isOpen"; "latitude": "latitude"; "longitude": "longitude"; "disableAutoPan": "disableAutoPan"; "zIndex": "zIndex"; "maxWidth": "maxWidth"; }, { "infoWindowClose": "infoWindowClose"; }, never, ["*"]>;
}


/** @internal */
ngOnChanges(changes: {
        [key: string]: SimpleChange;
    }): void;


/**
     * Opens the info window.
     */
open(): Promise<void>;


/**
     * Closes the info window.
     */
close(): Promise<void>;


/** @internal */
id(): string;


/** @internal */
toString(): string;


/** @internal */
ngOnDestroy(): void;


({ id, params }) => {
  const navigate = useNavigator();
  const notify = useNotifier();
  const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions(
    params.ids
  );
  const intl = useIntl();
  const {
    loadMore: loadMoreCategories,
    search: searchCategories,
    result: searchCategoriesOpts
  } = useCategorySearch({
    variables: DEFAULT_INITIAL_SEARCH_DATA
  });
  const {
    loadMore: loadMoreCollections,
    search: searchCollections,
    result: searchCollectionsOpts
  } = useCollectionSearch({
    variables: DEFAULT_INITIAL_SEARCH_DATA
  });
  const warehouses = useWarehouseList({
    displayLoader: true,
    variables: {
      first: 50
    }
  });

  const [openModal, closeModal] = createDialogActionHandlers<
    ProductUrlDialog,
    ProductUrlQueryParams
  >(navigate, params => productUrl(id, params), params);

  const handleBack = () => navigate(productListUrl());

  return (
    <TypedProductDetailsQuery displayLoader variables={{ id }}


params => productUrl(id, params)


() => navigate(productListUrl())


() => {
          notify({
            text: intl.formatMessage({
              defaultMessage: "Product removed"
            })
          });
          navigate(productListUrl());
        }


(data: ProductUpdateMutationResult) => {
          if (data.productUpdate.errors.length === 0) {
            notify({
              text: intl.formatMessage(commonMessages.savedChanges)
            });
          }
        }


(data: ProductImageCreate) => {
          const imageError = data.productImageCreate.errors.find(
            error =>
              error.field === ("image" as keyof ProductImageCreateVariables)
          );
          if (imageError) {
            notify({
              text: intl.formatMessage(commonMessages.somethingWentWrong)
            });
          }
        }


error =>
              error.field === ("image" as keyof ProductImageCreateVariables)


() =>
          notify({
            text: intl.formatMessage(commonMessages.savedChanges)
          })


() => navigate(productVariantAddUrl(id))


(
          data: ProductVariantBulkDelete
        ) => {
          if (data.productVariantBulkDelete.errors.length === 0) {
            closeModal();
            reset();
            refetch();
          }
        }


(id: string) => () =>
                deleteProductImage.mutate({ id })


() =>
                deleteProductImage.mutate({ id })


(imageId: string) => () =>
                navigate(productImageUrl(id, imageId))


() =>
                navigate(productImageUrl(id, imageId))


() => updateProduct.opts.data.productUpdate.errors


() => updateSimpleProduct.opts.data.productUpdate.errors


() =>
                    updateSimpleProduct.opts.data.productVariantUpdate.errors


() => searchCategoriesOpts.data.search.edges


edge => edge.node


() => searchCollectionsOpts.data.search.edges


() =>
                          searchCategoriesOpts.data.search.pageInfo.hasNextPage


() =>
                          searchCollectionsOpts.data.search.pageInfo.hasNextPage


() => params.ids.length


interface ProductUpdateProps {
  id: string;
  params: ProductUrlQueryParams;
}


maybe(


/**
 *
Provides project-level details for your Amplify UI project.

 */
export class GetBackendCommand extends $Command<
  GetBackendCommandInput,
  GetBackendCommandOutput,
  AmplifyBackendClientResolvedConfig
> {
  // Start section: command_properties
  // End section: command_properties

  constructor(readonly input: GetBackendCommandInput) {
    // Start section: command_constructor
    super();
    // End section: command_constructor
  }

  /**
   * @internal
   */
  resolveMiddleware(
    clientStack: MiddlewareStack<ServiceInputTypes, ServiceOutputTypes>,
    configuration: AmplifyBackendClientResolvedConfig,
    options?: __HttpHandlerOptions
  ): Handler<GetBackendCommandInput, GetBackendCommandOutput> {
    this.middlewareStack.use(getSerdePlugin(configuration, this.serialize, this.deserialize));

    const stack = clientStack.concat(this.middlewareStack);

    const { logger } = configuration;
    const clientName = "AmplifyBackendClient";
    const commandName = "GetBackendCommand";
    const handlerExecutionContext: HandlerExecutionContext = {
      logger,
      clientName,
      commandName,
      inputFilterSensitiveLog: GetBackendRequest.filterSensitiveLog,
      outputFilterSensitiveLog: GetBackendResponse.filterSensitiveLog,
    };
    const { requestHandler } = configuration;
    return stack.resolve(
      (request: FinalizeHandlerArguments<any>) =>
        requestHandler.handle(request.request as __HttpRequest, options || {}),
      handlerExecutionContext
    );
  }

  private serialize(input: GetBackendCommandInput, context: __SerdeContext): Promise<__HttpRequest> {
    return serializeAws_restJson1GetBackendCommand(input, context);
  }

  private deserialize(output: __HttpResponse, context: __SerdeContext): Promise<GetBackendCommandOutput> {
    return deserializeAws_restJson1GetBackendCommand(output, context);
  }

  // Start section: command_body_extra
  // End section: command_body_extra
}


export type GetBackendCommandInput = GetBackendRequest;


export type GetBackendCommandOutput = GetBackendResponse & __MetadataBearer;


/**
   * @internal
   */
resolveMiddleware(
    clientStack: MiddlewareStack<ServiceInputTypes, ServiceOutputTypes>,
    configuration: AmplifyBackendClientResolvedConfig,
    options?: __HttpHandlerOptions
  ): Handler<GetBackendCommandInput, GetBackendCommandOutput> {
    this.middlewareStack.use(getSerdePlugin(configuration, this.serialize, this.deserialize));

    const stack = clientStack.concat(this.middlewareStack);

    const { logger } = configuration;
    const clientName = "AmplifyBackendClient";
    const commandName = "GetBackendCommand";
    const handlerExecutionContext: HandlerExecutionContext = {
      logger,
      clientName,
      commandName,
      inputFilterSensitiveLog: GetBackendRequest.filterSensitiveLog,
      outputFilterSensitiveLog: GetBackendResponse.filterSensitiveLog,
    };
    const { requestHandler } = configuration;
    return stack.resolve(
      (request: FinalizeHandlerArguments<any>) =>
        requestHandler.handle(request.request as __HttpRequest, options || {}),
      handlerExecutionContext
    );
  }


private serialize(input: GetBackendCommandInput, context: __SerdeContext): Promise<__HttpRequest> {
    return serializeAws_restJson1GetBackendCommand(input, context);
  }


private deserialize(output: __HttpResponse, context: __SerdeContext): Promise<GetBackendCommandOutput> {
    return deserializeAws_restJson1GetBackendCommand(output, context);
  }


@NgModule({
  imports: [
    RouterModule.forChild(ROUTES),
    CommonModule,
    MatButtonModule,
    MatCardModule,
    MatIconModule,
    MatProgressSpinnerModule,
    MatSelectModule,
    MatInputModule,
    HttpClientModule,
    FormsModule,
    SharedModule
  ],
  declarations: [StoreComponent],
  exports: [StoreComponent]
})
export class StoreModule {}


(p) => p.width


export default function Offset(src: any, offsetX: any, offsetY: any, out?: any): any;


export function App() {
    return <RepositoryList />
}


(_, index) => index + hourStart


hour => {
      const hasAppointmentInHour = appointments.find(
        appointment => getHours(appointment.date) === hour,
      );

      const compareDate = new Date(year, month - 1, day, hour);

      return {
        hour,
        available: !hasAppointmentInHour && isAfter(compareDate, currentDate),
      };
    }


appointment => getHours(appointment.date) === hour


@injectable()
class ListProviderDayAvailabilityService {
  constructor(
    @inject('AppointmentsRepository')
    private appointmentsRepository: IAppointmentsRepository,
  ) {}

  public async execute({
    provider_id,
    year,
    month,
    day,
  }: IRequest): Promise<IResponse> {
    const appointments = await this.appointmentsRepository.findAllInDayFromProvider(
      {
        provider_id,
        year,
        month,
        day,
      },
    );

    const hourStart = 8;

    const eachHourArray = Array.from(
      { length: 10 },
      (_, index) => index + hourStart,
    );

    const currentDate = new Date(Date.now());
    const availability = eachHourArray.map(hour => {
      const hasAppointmentInHour = appointments.find(
        appointment => getHours(appointment.date) === hour,
      );

      const compareDate = new Date(year, month - 1, day, hour);

      return {
        hour,
        available: !hasAppointmentInHour && isAfter(compareDate, currentDate),
      };
    });

    return availability;
  }
}


interface IRequest {
  provider_id: string;
  day: number;
  month: number;
  year: number;
}


type IResponse = Array<{
  hour: number;
  available: boolean;
}>;


public async execute({
    provider_id,
    year,
    month,
    day,
  }: IRequest): Promise<IResponse> {
    const appointments = await this.appointmentsRepository.findAllInDayFromProvider(
      {
        provider_id,
        year,
        month,
        day,
      },
    );

    const hourStart = 8;

    const eachHourArray = Array.from(
      { length: 10 },
      (_, index) => index + hourStart,
    );

    const currentDate = new Date(Date.now());
    const availability = eachHourArray.map(hour => {
      const hasAppointmentInHour = appointments.find(
        appointment => getHours(appointment.date) === hour,
      );

      const compareDate = new Date(year, month - 1, day, hour);

      return {
        hour,
        available: !hasAppointmentInHour && isAfter(compareDate, currentDate),
      };
    });

    return availability;
  }


export interface ISpecialFunctionKey {
    Type: ESpecialFunctionType;
    Index: number;
}


export interface IControllerConfig {
    ControllerType: string;
    AtemMixEffectBlock: number;
    ImageConnections: Array<ImageConnectionConfig>;
    SpecialFunctions: { [key in SpecialFunctionKey]: ISpecialFunctionKey };
    AltSpecialFunctions?: { [key in SpecialFunctionKey]: ISpecialFunctionKey };
    AltLowerSpecialFunctions?: { [key in SpecialFunctionKey]: ISpecialFunctionKey };
}


export enum ESpecialFunctionType {
    key = 'key',
    macro = 'macro',
}


(props: React.ComponentProps<typeof TimezoneField>) => (
  <Panel>
    <Panel.Body>
      <Form onSubmit={()


() => {
    const children = text("children", "Timezone");
    const props = {
      autoFocus: boolean("autoFocus", false),
      onChange: action("onChange"),
      onOffsetChange: action("onOffsetChange"),
      name: text("name", "text"),
      required: boolean("required", false),
      value: text("value", "")
    };

    return <Container {...props}>{children}</Container>;
  }


() => (
    <Container name="timezone"


() => {
    const validator = (value: null | string) => {
      if (value !== "Pacific/Tahiti") {
        return null;
      }
      return "Can't go to Tahiti.";
    };

    return (
      <Container name="timezone" required validator={validator}>
        Timezone
      </Container>


(value: null | string) => {
      if (value !== "Pacific/Tahiti") {
        return null;
      }
      return "Can't go to Tahiti.";
    }


export function recordVersion() {
  try {
    const match = /^(\d+)\.(\d+)\.(\d+)/.exec(pkg.version)
    if (match !== null) {
      const [_, major, minor, patch] = match
      const value =
        parseFloat(major) + parseFloat(minor) / 100 + parseFloat(patch) / 10000
      globalStats.record([{ measure: versionMeasure, value }])
    }
  } catch (error) {
    log.error(error)
  }
}


export function recordLogData(data: LogData) {
  const { level } = data
  const tags = new TagMap()
  tags.set(logLevelTagKey, { value: LogLevel[level] })
  globalStats.record([{ measure: logEventMeasure, value: 1 }], tags)
}


function createSessionTags(session: SoftwareSession, type: string) {
  const {
    status = 'undefined',
    environment: { name } = { name: 'undefined' }
  } = session

  const tags = new TagMap()
  tags.set(sessionTypeTagKey, { value: type })
  tags.set(sessionStatusTagKey, { value: status })
  tags.set(sessionEnvironTagKey, { value: name })

  return tags
}


export function recordSession(session: SoftwareSession, type: string): void {
  globalStats.record(
    [{ measure: sessionCountMeasure, value: 1 }],
    createSessionTags(session, type)
  )
}


export function recordSessionBeginDuration(
  value: number,
  session: SoftwareSession,
  type: string
): void {
  globalStats.record(
    [{ measure: sessionBeginDurationMeasure, value }],
    createSessionTags(session, type)
  )
}


export function recordSessionRestart(
  session: SoftwareSession,
  type: string
): void {
  globalStats.record(
    [{ measure: sessionRestartMeasure, value: 1 }],
    createSessionTags(session, type)
  )
}


export function recordSessionEndDuration(
  value: number,
  session: SoftwareSession,
  type: string
): void {
  globalStats.record(
    [{ measure: sessionEndDurationMeasure, value }],
    createSessionTags(session, type)
  )
}


export function recordExecuteDuration(value: number, type: string): void {
  const tags = new TagMap()
  tags.set(sessionTypeTagKey, { value: type })
  globalStats.record([{ measure: executeDurationMeasure, value }], tags)
}


/**
 * Record system level stats
 */
async function recordSystemStats() {
  try {
    const memInfo = await osu.mem.info()
    const cpuUsage = await osu.cpu.usage()
    const driveInfo = await osu.drive.info('/')
    globalStats.record([
      { measure: memoryFreeMeasure, value: memInfo.freeMemMb * 1024 },
      {
        measure: memoryUsedPercentMeasure,
        value: 100 - memInfo.freeMemPercentage
      },
      { measure: cpuUsagePercentMeasure, value: cpuUsage },
      // The `* 1` is necessary to make the value a `number`
      { measure: driveUsedPercentMeasure, value: driveInfo.usedPercentage * 1 }
    ])
  } catch (error) {
    log.error(error)
  }
}


/**
 * Start collecting system statistics and
 * exporting.
 *
 * @param interval The interval in seconds for collecting system stats.
 * @param prometheus The port number to serve Prometheus metrics on.
 */
export function start(interval: number, prometheus: number) {
  const record = () => {
    recordVersion()
    recordSystemStats().catch(error => log.error(error))
  }
  record()
  setInterval(record, interval * 1000)

  if (prometheus > 0) {
    const exporter = new PrometheusStatsExporter({
      port: prometheus,
      startServer: true
    })
    globalStats.registerExporter(exporter)
  }
}


() => {
    recordVersion()
    recordSystemStats().catch(error => log.error(error))
  }


error => log.error(error)


() => {
  test("creates input", () => {
    expect(
      print(createWhereUniqueInput(EXAMPLE_ENTITY, EXAMPLE_ENTITY_ID_TO_NAME))
        .code
    ).toEqual(
      print(
        createInput(
          createWhereUniqueInputID(EXAMPLE_ENTITY_NAME),
          [EXAMPLE_ENTITY_FIELD],
          false,
          true,
          EXAMPLE_ENTITY_ID_TO_NAME
        )
      ).code
    );
  });
}


() => {
    expect(
      print(createWhereUniqueInput(EXAMPLE_ENTITY, EXAMPLE_ENTITY_ID_TO_NAME))
        .code
    ).toEqual(
      print(
        createInput(
          createWhereUniqueInputID(EXAMPLE_ENTITY_NAME),
          [EXAMPLE_ENTITY_FIELD],
          false,
          true,
          EXAMPLE_ENTITY_ID_TO_NAME
        )
      ).code
    );
  }


() => {
  test("creates identifier", () => {
    expect(createWhereUniqueInputID(EXAMPLE_ENTITY_NAME)).toEqual(
      builders.identifier(`${EXAMPLE_ENTITY_NAME}WhereUniqueInput`)
    );
  });
}


() => {
    expect(createWhereUniqueInputID(EXAMPLE_ENTITY_NAME)).toEqual(
      builders.identifier(`${EXAMPLE_ENTITY_NAME}WhereUniqueInput`)
    );
  }


(fn:any) => typeof fn === 'function'


(prop:any) => typeof prop === 'undefined'


(o:any) => typeof o === 'object'


(o:any) => Array.isArray(o)


(fn:any) => {
  if (fn instanceof Promise) { return true; }
  return isObject(fn) && isFunction(fn.then);
}


(o:any, handler:any) => {
  if (!isObject(o) || o === null) { return o; }
  if (isArray(o)) {
    o.forEach((item:any, index:number) => {
      if (isObject(item)) {
        o[index] = addProxy(item, handler);
      }
    });
  } else if (isObject(o)) {
    Object.keys(o).forEach((key) => {
      if (isObject(o[key])) {
        o[key] = addProxy(o[key], handler);
      }
    });
  }
  return new Proxy(o, handler);
}


(item:any, index:number) => {
      if (isObject(item)) {
        o[index] = addProxy(item, handler);
      }
    }


(key) => {
      if (isObject(o[key])) {
        o[key] = addProxy(o[key], handler);
      }
    }


export class EditTechnicalRequirementModelContext extends BSModalContext {
  public requirement: TechnicalRequirement;
}


export class VenueMapFactory {

        constructor(map: Map);

        create(options: VenueMapCreationOptions): void;
        getNearbyVenues(options: NearbyVenueOptions): void;
    }


export interface MouseResponse {
        eventArgs: MouseEventArgs;
    }


export interface PrimitiveResponse {
        eventArgs: Primitive;
    }


export interface Directory {

        addToDOM(div: HTMLElement, sortOrder: DirectorySortOrder, to_group_or_not: DirectoryGrouping): void;
        createUIElements(): void;
        handleMouseClick(e: (response: MouseResponse) => void): void;
        handleMouseClick(e: (response: PrimitiveResponse) => void): void;
        handleMouseOut(e: (response: MouseResponse) => void): void;
        handleMouseOut(e: (response: PrimitiveResponse) => void): void;
        handleMouseOver(e: (response: MouseResponse) => void): void;
        handleMouseOver(e: (response: PrimitiveResponse) => void): void;
        isInDOM(): boolean;
        removeFromDOM(): void;
        setHeight(height: number): void;
    }


export interface Floor {
        name: string;
        primitives: Array<Primitive>;
        zoomRange: Array<number>;
    }


export interface Footprint {
        polygons: Array<Polygon>;
        zoomRange: Array<number>;
    }


export interface Metadata {
        CenterLatitude: number;
        CenterLongitude: number;
        DefaultFloor: string;
        FloorHeader: string;
        Floors: Array<Floor>;
        Footprint: Footprint;
        MapId: string;
        MapType: string;
        Name: string;
        YpId: string;
    }


export interface NearbyVenue {
        distance: number;
        metadata: Metadata;
    }


export interface NearbyVenueOptions {
        callback?: (maps: Array<VenueMap>) => any;
        location?: Location;
        map?: Map;
        radius?: number;
    }


export interface Polygon {
        bounds: LocationRect;
        center: Location;
        locations: Array<Location>;
    }


export interface Primitive {

        bounds: LocationRect;
        businessId: string;
        categoryId: string;
        categoryName: string;
        center: Location;
        floor: Floor;
        id: string;
        locations: Array<Location>;
        name: string;

        highlight(): void;
        unhighlight(): void;
    }


export interface VenueMap {

        address: string;
        bestMapView: ViewOptions;
        businessId: string;
        center: Location;
        defaultFloor: string;
        directory: Directory;
        floorHeader: string;
        floors: Array<Floor>;
        footprint: Footprint;
        id: string;
        name: string;
        phoneNumber: string;
        type: string;

        dispose(): void;
        getActiveFloor(): string;
        hide(): void;
        setActiveFloor(floor: string): void;
        show(): void;
    }


export interface VenueMapCreationOptions {
        error: (errorCode: number, args: any) => any;
        success: (venueMap: VenueMap, args: any) => any;
        venueMapId: string;
    }


export enum DirectoryGrouping {
        byCategory,
        none,
    }


export enum DirectorySortOrder {
        alphabetical,
        byFloor,
    }


create(options: VenueMapCreationOptions): void;


getNearbyVenues(options: NearbyVenueOptions): void;


() => this.zoomDimensionsInOrOut(newSize)


() => {
            State.gameState.renderingEngine.run();
            this.cycleFrames(n - 1);
        }


(resolve, reject) => {
            for (const img of images) {
                img.onload = () => resolve(img);
                img.onerror = reject;
            }
        }


() => {
            method.call(scope);
        }


static setDimensions(minGameDimensions: Dimensions = State.gameState.defaultGridDimensions) {
        this.stopCurrentZoom();

        // when we set the dimensions of the game, determine the pixelsPerUnit conversion for later use
        State.gameState.currentGridDimensions = minGameDimensions;

        const dx = innerWidth / minGameDimensions.w;
        const dy = innerHeight / minGameDimensions.h;
        State.gameState.pixelsPerUnit = Math.min(dx, dy);
        State.gameState.gameUnitDimensions = {
            w: innerWidth / State.gameState.pixelsPerUnit,
            h: innerHeight / State.gameState.pixelsPerUnit
        };
        State.gameState.screenPixelDimensions = {
            w: innerWidth,
            h: innerHeight
        };
    }


/**
     *
     * @param newSize
     */
static zoomDimensionsInOrOut(newSize: number) {
        this.stopCurrentZoom();
        const adjustmentValue = 0.025;
        const zoomDelay = 10;
        const curDim = State.gameState.currentGridDimensions;
        if (Math.abs(curDim.h - newSize) <= adjustmentValue) {
            this.setDimensions({ w: newSize, h: newSize });
            State.gameState.timeoutId = null;
        } else if (curDim.h - newSize > 0) {
            this.setDimensions({ w: curDim.w - adjustmentValue, h: curDim.h - adjustmentValue });
            State.gameState.timeoutId = setTimeout(() => this.zoomDimensionsInOrOut(newSize), zoomDelay);
        } else {
            this.setDimensions({ w: curDim.w + adjustmentValue, h: curDim.h + adjustmentValue });
            State.gameState.timeoutId = setTimeout(() => this.zoomDimensionsInOrOut(newSize), zoomDelay);
        }
    }


static stopCurrentZoom() {
        if (State.gameState.timeoutId) {
            clearTimeout(State.gameState.timeoutId);
            State.gameState.timeoutId = null;
        }
    }


static toScreenCoordinates(gameCoords: Point): Point {
        return {
            x: (gameCoords.x - State.gameState.position.x) * State.gameState.pixelsPerUnit,
            y: ((State.gameState.position.y - gameCoords.y) * State.gameState.pixelsPerUnit) + State.gameState.screenPixelDimensions.h
        };
    }


/**
     * When passing coordinates from the screen or click events, you should use event.clientX and event.clientY.
     */
static toGameCoordinates({ x: cltX, y: cltY }: Point): Point {
        return {
            x: cltX / State.gameState.pixelsPerUnit + State.gameState.position.x,
            y: -cltY / State.gameState.pixelsPerUnit + State.gameState.position.y + State.gameState.gameUnitDimensions.h
        };
    }


/**
     * Will return the root of the grid position for rendering imgs in a grid space
     * e.g. { x: 3.86, y: 2.13 } => { x: 3, y: 3}
     */
static toGameCoordsImgRoot({ x, y }: Point): Point {
        return {
            x: Math.floor(x),
            y: Math.ceil(y)
        };
    }


static getRegion({ x, y }: Point): string {
        const regionColumn = Math.floor(x / State.stageState.regionSize);
        const regionRow = Math.floor(y / State.stageState.regionSize);
        return `${regionColumn}${State.stageState.colRowSeparator}${regionRow}`;
    }


static splitRegionString(region: string): string[] {
        return region.split(State.stageState.colRowSeparator);
    }


static toScreenDimensions(gameDimensions: Dimensions): Dimensions {
        return {
            w: this.toPixels(gameDimensions.w),
            h: this.toPixels(gameDimensions.h)
        };
    }


static toGameDimensions(screenDimensions: Dimensions): Dimensions {
        return {
            w: this.toUnits(screenDimensions.w),
            h: this.toUnits(screenDimensions.h)
        };
    }


static toPixels(gameLength: number): number {
        return gameLength * State.gameState.pixelsPerUnit;
    }


static toUnits(pixels: number): number {
        return pixels / State.gameState.pixelsPerUnit;
    }


static gridAxisOfPosition(position: Point): Point {
        const { x, y } = position;
        const gridX = Math.floor(x);
        const gridY = Math.floor(y);
        return { x: gridX, y: gridY };
    }


static pauseGame(pause: boolean): void {
        State.gameState.paused = pause;
        if (State.gameState.paused) {
            State.gameState.framesPerSecond = 0;
        } else {
            State.gameState.framesPerSecond = State.gameState.defaultFramesPerSecond;
        }
    }


static cycleFrames(n: number, fps = State.gameState.defaultFramesPerSecond) {
        if (!State.gameState.paused) {
            console.error('Game must be paused to cycle frames');
            return;
        }

        if (n === 0) { return; }
        setTimeout(() => {
            State.gameState.renderingEngine.run();
            this.cycleFrames(n - 1);
        }, 1000 / fps);
    }


static refreshCanvas(): void {
        State.gameState.canvas.ctx.clearRect(0, 0, innerWidth, innerHeight);
    }


static viewableStageGridArea(): GridArea {
        const { x, y } = State.gameState.position;
        const { w, h } = State.gameState.gameUnitDimensions;
        const topLeftGridUnits = { x, y: y + h };
        const topRightGridUnits = { x: x + w, y: y + h };
        const bottomLeftGridUnits = State.gameState.position;
        const bottomRightGridUnits = { x: x + w, y };

        const viewableGridArea: GridArea = {
            topLeft: topLeftGridUnits,
            topRight: topRightGridUnits,
            bottomLeft: bottomLeftGridUnits,
            bottomRight: bottomRightGridUnits
        };
        return viewableGridArea;
    }


static async loadImages(images: HTMLImageElement[]) {
        return new Promise((resolve, reject) => {
            for (const img of images) {
                img.onload = () => resolve(img);
                img.onerror = reject;
            }
        });
    }


static async resizeScreenDimensions() {
        State.gameState.canvas.canvasElement.height = innerHeight;
        State.gameState.canvas.canvasElement.width = innerWidth;
        State.backgroundState.bgCanvas.canvasElement.height = innerHeight;
        State.backgroundState.bgCanvas.canvasElement.width = innerWidth;
        RenderingUtilities.setDimensions(State.gameState.currentGridDimensions);
        Background.draw();
        if (State.gameState.paused && !State.builderState.builderMode) {
            State.gameState.renderingEngine.run();
        }
    }


static debounce(method: any, scope: any) {
        clearTimeout(method._tId);
        method._tId = setTimeout(() => {
            method.call(scope);
        }, 400);
    }


/**
     * Center the screen horizontally and 5 units up from the bottom.
     * @param point
     */
static setScreenPositionFromCenter(point: Point) {
        State.gameState.position = { x: point.x - State.gameState.gameUnitDimensions.w / 2, y: point.y - 5 };
    }


static stringifyColAndRow(col: number, row: number): string {
        return `${col}${State.stageState.colRowSeparator}${row}`;
    }


(privateKey: string) =>
  createClient({
    fetcher: ({ query, variables }, fetch) =>
      fetch(`${root}/api/v2/admin`, {
        method: 'POST',
        body: JSON.stringify({ query, variables }),
        headers: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${privateKey}`,
        },
      }).then(r => r.json()),
  })


({ query, variables }, fetch) =>
      fetch(`${root}/api/v2/admin`, {
        method: 'POST',
        body: JSON.stringify({ query, variables }),
        headers: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${privateKey}`,
        },
      }).then(r => r.json())


r => r.json()


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

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

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

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


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


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


() => {
    observers.forEach(n => n.disconnect());
    observers.clear();
    restoreHistory();
  }


n => n.disconnect()


async () => {
    type A = [string, string][];

    const newUrlOptions: A = [
      ['/test/123', ':default'],
      ['/test/456', ':test-1'],
    ];

    const observer = init({
      routes: Object.values(routes),
    });

    const result: A = [];

    for (const [newUrl, newUrlScope] of newUrlOptions) {
      observer.add({
        pathRegExp: routes.section,
        handleEvent() {
          result.push([newUrl, newUrlScope]);
          return true;
        },
        scope: newUrlScope,
      });

      await waitForEvent(pushStateEventKey, async () => {
        await observer.updateHistory(newUrl, newUrlScope);
      });
    }

    assert.deepStrictEqual(result, newUrlOptions);
    assert.deepStrictEqual<URLChangedStatus[]>(
      observer.takeRecords().map(n => n.entryType),
      [
        'init',
        ...Array.from<unknown, URLChangedStatus>(Array(newUrlOptions.length), () => 'manual'),
      ]
    );
  }


async () => {
        await observer.updateHistory(newUrl, newUrlScope);
      }


n => n.entryType


() => 'manual'


async () => {
    type A = [string, Record<string, string>][];

    const newUrlOptions: A = [
      ['/test/123', { [linkScopeKey]: ':default' }],
      ['/test/123a', { [linkScopeKey]: '' }],
      ['/test/456', { [`.${linkScopeKey}`]: ':default' }],
      ['/test/456a', { [`.${linkScopeKey}`]: '' }],
      ['/test/789', { [linkScopeKey]: 'test-1' }],
      ['/test/789a', { [`.${linkScopeKey}`]: 'test-1' }],
    ];

    const observer = init({
      routes: Object.values(routes),
    });

    const result: A = [];
    for (const [newUrl, newUrlScope] of newUrlOptions) {
      const { removeLink } = appendLink(newUrl, newUrlScope);

      observer.add({
        pathRegExp: routes.section,
        handleEvent() {
          result.push([newUrl, newUrlScope]);
          return true;
        },
        scope: newUrlScope?.[linkScopeKey] ?? newUrlScope?.[`.${linkScopeKey}`],
      });

      await waitForEvent(pushStateEventKey, async () => {
        await pageClick(`a[href="${newUrl}"]`, {
          button: 'left',
        });
      });

      removeLink();
    }

    assert.deepStrictEqual(result, newUrlOptions);
    assert.deepStrictEqual<URLChangedStatus[]>(
      observer.takeRecords().map(n => n.entryType),
      [
        'init',
        ...Array.from<unknown, URLChangedStatus>(Array(newUrlOptions.length), () => 'click'),
      ]
    );
  }


async () => {
        await pageClick(`a[href="${newUrl}"]`, {
          button: 'left',
        });
      }


() => 'click'


async () => {
      type A = [string, string | undefined][];

      const newUrlOptions: A = [
        ['/test/123', ''],
        ['/test/456', undefined],
      ];

      const observer = init({
        routes: Object.values(routes),
      });

      const result: A = [];
      for (const [newUrl, newUrlScope] of newUrlOptions) {
        observer.add({
          pathRegExp: routes.section,
          handleEvent() {
            result.push([newUrl, newUrlScope]);
            return true;
          },
          scope: newUrlScope,
        });

        await waitForEvent(pushStateEventKey, async () => {
          await observer.updateHistory(newUrl, newUrlScope);
        });
      }

      assert.deepStrictEqual(result, []);
      assert.deepStrictEqual<URLChangedStatus[]>(
        observer.takeRecords().map(n => n.entryType),
        [
          'init',
          ...Array.from<unknown, URLChangedStatus>(Array(newUrlOptions.length), () => 'manual'),
        ]
      );
    }


async () => {
          await observer.updateHistory(newUrl, newUrlScope);
        }


async () => {
      type A = [string, string][];

      const newUrlOptions: A = [
        ['/test/123', ''],
        ['/test/456', ':default'],
        ['/test/789', 'test-1'],
      ];

      const observer = init({
        routes: Object.values(routes),
      });

      const result: A = [];
      for (const [newUrl, newUrlScope] of newUrlOptions) {
        const { removeLink } = appendLink(newUrl);

        observer.add({
          pathRegExp: routes.section,
          handleEvent() {
            result.push([newUrl, newUrlScope]);
            return true;
          },
          scope: newUrlScope,
        });

        await waitForEvent(pushStateEventKey, async () => {
          await pageClick(`a[href="${newUrl}"]`, {
            button: 'left',
          });
        });

        removeLink();
      }

      assert.deepStrictEqual(result, []);
      assert.deepStrictEqual<URLChangedStatus[]>(
        observer.takeRecords().map(n => n.entryType),
        [
          'init',
          ...Array.from<unknown, URLChangedStatus>(Array(newUrlOptions.length), () => 'click'),
        ]
      );
    }


async () => {
          await pageClick(`a[href="${newUrl}"]`, {
            button: 'left',
          });
        }


async () => {
      type A = [string, Record<string, string>];

      const newUrlOptions: A[] = [
        ['/test/123', { [linkScopeKey]: ':default' }],
        ['/test/123a', { [linkScopeKey]: '' }],
        ['/test/456', { [`.${linkScopeKey}`]: ':default' }],
        ['/test/456a', { [`.${linkScopeKey}`]: '' }],
        ['/test/789', { [linkScopeKey]: 'test-1' }],
        ['/test/789a', { [`.${linkScopeKey}`]: 'test-1' }],
      ];

      const observer = init({
        routes: Object.values(routes),
      });

      const result: A[] = [];
      for (const [newUrl, newUrlScope] of newUrlOptions) {
        const { removeLink } = appendLink(newUrl, newUrlScope);

        let temp: A = ['', {}];

        observer.add({
          pathRegExp: routes.section,
          handleEvent() {
            temp = [newUrl, newUrlScope];

            return false;
          },
          scope: newUrlScope?.[linkScopeKey] ?? newUrlScope?.[`.${linkScopeKey}`],
        });

        const ev = await waitForEvent(pushStateEventKey, async () => {
          await pageClick(`a[href="${newUrl}"]`, {
            button: 'left',
          });
        });

        removeLink();

        if (ev) result.push(temp);
      }

      assert.deepStrictEqual(result, []);
      assert.deepStrictEqual<URLChangedStatus[]>(
        observer.takeRecords().map(n => n.entryType),
        ['init']
      );
    }


async () => {
      type A = [string, string];

      const newUrlOptions: A[] = [
        ['/test/123', ':default'],
        ['/test/456', 'test-1'],
      ];

      const observer = init({
        routes: Object.values(routes),
      });

      const historyRecords: string[] = [];
      const result: A[] = [];
      for (const [newUrl, newUrlScope] of newUrlOptions) {
        let temp: A = ['', ''];

        observer.add({
          pathRegExp: routes.section,
          handleEvent() {
            temp = [newUrl, newUrlScope];

            return false;
          },
          scope: newUrlScope,
        });

        const ev = await waitForEvent(pushStateEventKey, async () => {
          await observer.updateHistory(newUrl, newUrlScope);
        });

        if (ev) result.push(temp);

        historyRecords.push(window.location.pathname);
      }

      assert.deepStrictEqual(result, []);
      assert.deepStrictEqual(
        historyRecords,
        Array.from<unknown, string>(Array(newUrlOptions.length), () => '/')
      );
      assert.deepStrictEqual<URLChangedStatus[]>(
        observer.takeRecords().map(n => n.entryType),
        ['init']
      );
    }


async () => {
    type A = (keyof typeof routes)[];

    const newUrls: [string, string][] = [
      ['/test2', ''],
      ['/test2', ':test'],
    ];

    const result: A[] = [];
    const clicked: boolean[] = [];

    for (const [newUrl, newScope] of newUrls) {
      const observer = init({
        routes: Object.values(routes),
      });

      const temp: A = [];

      observer.add({
        pathRegExp: routes.test,
        handleEvent() {
          temp.push('test');
          return true;
        },
        scope: newScope || undefined,
      });
      observer.add({
        pathRegExp: routes.section,
        handleEvent() {
          temp.push('section');
          return true;
        },
        scope: newScope || undefined,
      });

      const didClick = Boolean(
        await waitForEvent(pushStateEventKey, async () => {
          await observer.updateHistory(newUrl, newScope || undefined);
        })
      );

      if (temp.length) result.push(temp);

      clicked.push(didClick);
    }

    assert.deepStrictEqual(clicked, [true, true]);
    assert.deepStrictEqual(result, []);
  }


async () => {
          await observer.updateHistory(newUrl, newScope || undefined);
        }


type A = [string, string][];


type A = [string, Record<string, string>][];


type A = [string, string | undefined][];


type A = [string, Record<string, string>];


type A = [string, string];


type A = (keyof typeof routes)[];


handleEvent() {
          result.push([newUrl, newUrlScope]);
          return true;
        }


handleEvent() {
            result.push([newUrl, newUrlScope]);
            return true;
          }


handleEvent() {
            temp = [newUrl, newUrlScope];

            return false;
          }


handleEvent() {
          temp.push('test');
          return true;
        }


handleEvent() {
          temp.push('section');
          return true;
        }


() => (
  <div id="benefits">
    <div className