export interface SortedSet<T> extends Set<T> {

    /**
     * The number of items in this SortedSet.
     */
    readonly size: number;

    // Persistent changes

    /**
     * Returns a new `SortedSet` containing the values of the provided
     * collection-like. The values will be organized in an optimized tree structure
     * with internal nodes and leaves defragmented as much as possible
     * while keeping all the consistency rules enforced.
     *
     * If the collection argument is undefined then the current content
     * of this `SortedSet` will be reorganized into an optimized tree structure.
     *
     * The pack procedure is actually called from the `SortedSet` constructor
     * as it is usually faster than a series of add operations. It is recommended
     * to explicitly call this method after a large batch of add or delete operations
     * to release a portion of the allocated memory and to speed up the consequent get
     * operations.
     */
    pack(collection?: Iterable<T>): this;

    /**
     * Returns a sequence representing a subset of this sorted set starting with value
     * up to the last element in the set.
     *
     * If the optional parameter backwards is set to true, the returned sequence will
     * list the entries backwards, starting with value down to the first element in the set.
     *
     * Example:
     * ```js
     * const { SortedSet } = require('immutable-sorted');
     *
     * const abc = SortedSet(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]);
     *
     * > abc.from("R");
     * Seq { "R", "S", "T", "U", "V", "W", "X", "Y", "Z" }
     *
     * > abc.from("R", true);
     * Seq { "R", "Q", "P", "O", "N", "M", "L", "K", "J", "I", "H", "G", "F", "E", "D", "C", "B", "A" }
     * ```
     *
     * The method from() can be efficiently combined with take() to retrieve the desired number of values or with takeWhile() to retrieve a specific range:
     * ```js
     * > abc.from("R").take(5);
     * Seq { "R", "S", "T", "U", "V" }
     *
     * > abc.from("R").takeWhile(s => s < "W");
     * Seq { "R", "S", "T", "U", "V" }
     *
     * > abc.from("R", true).take(5);
     * Seq { "R", "Q", "P", "O", "N" }
     *
     * > abc.from("R", true).takeWhile(s => s > "K");
     * Seq { "R", "Q", "P", "O", "N", "M", "L" }
     * ```
     */
    from(value: T, backwards?: boolean): Seq.Set<T>;

  /**
     * Returns a sequence representing a portion of this sorted set starting from numeric index position,
     * as if the collection was an array.
     * If the optional parameter backwards is set to true, the returned sequence will
     * list the entries backwards.
     *
     * The method is optimized to quickly find the n-th entry inside the b-tree structure
     * by checking the computed sizes of underlying nodes.
     * Even though the algorithm is not as fast as working with a native array,
     * it is faster by orders of magnitude than walking through the first n elements
     * of unindexed collection to just skip them. The access time is O(log N).

     * Example:
     * ```js
     * > abc.fromIndex(4).take(5);
     * Seq { "E", "F", "G", "H", "I" }
     *
     * > abc.fromIndex(4, true).take(5);
     * Seq { "E", "D", "C", "B", "A" }
     * ```
     */
    fromIndex(index: number, backwards?: boolean): Seq.Set<T>;
  }


export interface OrderedSet<T> extends Set<T> {

    /**
     * The number of items in this OrderedSet.
     */
    readonly size: number;

    /**
     * Returns an OrderedSet including any value from `collections` that does
     * not already exist in this OrderedSet.
     *
     * Note: `union` can be used in `withMutations`.
     * @alias merge
     * @alias concat
     */
    union<C>(...collections: Array<Iterable<C>>): OrderedSet<T | C>;
    merge<C>(...collections: Array<Iterable<C>>): OrderedSet<T | C>;
    concat<C>(...collections: Array<Iterable<C>>): OrderedSet<T | C>;

    // Sequence algorithms

    /**
     * Returns a new Set with values passed through a
     * `mapper` function.
     *
     *     OrderedSet([ 1, 2 ]).map(x => 10 * x)
     *     // OrderedSet [10, 20]
     */
    map<M>(
      mapper: (value: T, key: T, iter: this) => M,
      context?: any
    ): OrderedSet<M>;

    /**
     * Flat-maps the OrderedSet, returning a new OrderedSet.
     *
     * Similar to `set.map(...).flatten(true)`.
     */
    flatMap<M>(
      mapper: (value: T, key: T, iter: this) => Iterable<M>,
      context?: any
    ): OrderedSet<M>;

    /**
     * Returns a new OrderedSet with only the values for which the `predicate`
     * function returns true.
     *
     * Note: `filter()` always returns a new instance, even if it results in
     * not filtering out any values.
     */
    filter<F extends T>(
      predicate: (value: T, key: T, iter: this) => value is F,
      context?: any
    ): OrderedSet<F>;
    filter(
      predicate: (value: T, key: T, iter: this) => any,
      context?: any
    ): this;

    /**
     * Returns an OrderedSet of the same type "zipped" with the provided
     * collections.
     *
     * Like `zipWith`, but using the default `zipper`: creating an `Array`.
     *
     * ```js
     * const a = OrderedSet([ 1, 2, 3 ])
     * const b = OrderedSet([ 4, 5, 6 ])
     * const c = a.zip(b)
     * // OrderedSet [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ]
     * ```
     */
    zip<U>(other: Collection<any, U>): OrderedSet<[T,U]>;
    zip<U,V>(other1: Collection<any, U>, other2: Collection<any, V>): OrderedSet<[T,U,V]>;
    zip(...collections: Array<Collection<any, any>>): OrderedSet<any>;

    /**
     * Returns a OrderedSet of the same type "zipped" with the provided
     * collections.
     *
     * Unlike `zip`, `zipAll` continues zipping until the longest collection is
     * exhausted. Missing values from shorter collections are filled with `undefined`.
     *
     * ```js
     * const a = OrderedSet([ 1, 2 ]);
     * const b = OrderedSet([ 3, 4, 5 ]);
     * const c = a.zipAll(b); // OrderedSet [ [ 1, 3 ], [ 2, 4 ], [ undefined, 5 ] ]
     * ```
     *
     * Note: Since zipAll will return a collection as large as the largest
     * input, some results may contain undefined values. TypeScript cannot
     * account for these without cases (as of v2.5).
     */
    zipAll<U>(other: Collection<any, U>): OrderedSet<[T,U]>;
    zipAll<U,V>(other1: Collection<any, U>, other2: Collection<any, V>): OrderedSet<[T,U,V]>;
    zipAll(...collections: Array<Collection<any, any>>): OrderedSet<any>;

    /**
     * Returns an OrderedSet of the same type "zipped" with the provided
     * collections by using a custom `zipper` function.
     *
     * @see Seq.Indexed.zipWith
     */
    zipWith<U, Z>(
      zipper: (value: T, otherValue: U) => Z,
      otherCollection: Collection<any, U>
    ): OrderedSet<Z>;
    zipWith<U, V, Z>(
      zipper: (value: T, otherValue: U, thirdValue: V) => Z,
      otherCollection: Collection<any, U>,
      thirdCollection: Collection<any, V>
    ): OrderedSet<Z>;
    zipWith<Z>(
      zipper: (...any: Array<any>) => Z,
      ...collections: Array<Collection<any, any>>
    ): OrderedSet<Z>;

  }


export interface Stack<T> extends Collection.Indexed<T> {

    /**
     * The number of items in this Stack.
     */
    readonly size: number;

    // Reading values

    /**
     * Alias for `Stack.first()`.
     */
    peek(): T | undefined;

    // Persistent changes

    /**
     * Returns a new Stack with 0 size and no values.
     *
     * Note: `clear` can be used in `withMutations`.
     */
    clear(): Stack<T>;

    /**
     * Returns a new Stack with the provided `values` prepended, shifting other
     * values ahead to higher indices.
     *
     * This is very efficient for Stack.
     *
     * Note: `unshift` can be used in `withMutations`.
     */
    unshift(...values: Array<T>): Stack<T>;

    /**
     * Like `Stack#unshift`, but accepts a collection rather than varargs.
     *
     * Note: `unshiftAll` can be used in `withMutations`.
     */
    unshiftAll(iter: Iterable<T>): Stack<T>;

    /**
     * Returns a new Stack with a size ones less than this Stack, excluding
     * the first item in this Stack, shifting all other values to a lower index.
     *
     * Note: this differs from `Array#shift` because it returns a new
     * Stack rather than the removed value. Use `first()` or `peek()` to get the
     * first value in this Stack.
     *
     * Note: `shift` can be used in `withMutations`.
     */
    shift(): Stack<T>;

    /**
     * Alias for `Stack#unshift` and is not equivalent to `List#push`.
     */
    push(...values: Array<T>): Stack<T>;

    /**
     * Alias for `Stack#unshiftAll`.
     */
    pushAll(iter: Iterable<T>): Stack<T>;

    /**
     * Alias for `Stack#shift` and is not equivalent to `List#pop`.
     */
    pop(): Stack<T>;

    // Transient changes

    /**
     * Note: Not all methods can be used on a mutable collection or within
     * `withMutations`! Check the documentation for each method to see if it
     * mentions being safe to use in `withMutations`.
     *
     * @see `Map#withMutations`
     */
    withMutations(mutator: (mutable: this) => any): this;

    /**
     * Note: Not all methods can be used on a mutable collection or within
     * `withMutations`! Check the documentation for each method to see if it
     * mentions being safe to use in `withMutations`.
     *
     * @see `Map#asMutable`
     */
    asMutable(): this;

    /**
     * @see `Map#wasAltered`
     */
    wasAltered(): boolean;

    /**
     * @see `Map#asImmutable`
     */
    asImmutable(): this;

    // Sequence algorithms

    /**
     * Returns a new Stack with other collections concatenated to this one.
     */
    concat<C>(...valuesOrCollections: Array<Iterable<C> | C>): Stack<T | C>;

    /**
     * Returns a new Stack with values passed through a
     * `mapper` function.
     *
     *     Stack([ 1, 2 ]).map(x => 10 * x)
     *     // Stack [ 10, 20 ]
     *
     * Note: `map()` always returns a new instance, even if it produced the same
     * value at every step.
     */
    map<M>(
      mapper: (value: T, key: number, iter: this) => M,
      context?: any
    ): Stack<M>;

    /**
     * Flat-maps the Stack, returning a new Stack.
     *
     * Similar to `stack.map(...).flatten(true)`.
     */
    flatMap<M>(
      mapper: (value: T, key: number, iter: this) => Iterable<M>,
      context?: any
    ): Stack<M>;

    /**
     * Returns a new Set with only the values for which the `predicate`
     * function returns true.
     *
     * Note: `filter()` always returns a new instance, even if it results in
     * not filtering out any values.
     */
    filter<F extends T>(
      predicate: (value: T, index: number, iter: this) => value is F,
      context?: any
    ): Set<F>;
    filter(
      predicate: (value: T, index: number, iter: this) => any,
      context?: any
    ): this;

    /**
     * Returns a Stack "zipped" with the provided collections.
     *
     * Like `zipWith`, but using the default `zipper`: creating an `Array`.
     *
     * ```js
     * const a = Stack([ 1, 2, 3 ]);
     * const b = Stack([ 4, 5, 6 ]);
     * const c = a.zip(b); // Stack [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ]
     * ```
     */
    zip<U>(other: Collection<any, U>): Stack<[T,U]>;
    zip<U,V>(other: Collection<any, U>, other2: Collection<any,V>): Stack<[T,U,V]>;
    zip(...collections: Array<Collection<any, any>>): Stack<any>;

    /**
     * Returns a Stack "zipped" with the provided collections.
     *
     * Unlike `zip`, `zipAll` continues zipping until the longest collection is
     * exhausted. Missing values from shorter collections are filled with `undefined`.
     *
     * ```js
     * const a = Stack([ 1, 2 ]);
     * const b = Stack([ 3, 4, 5 ]);
     * const c = a.zipAll(b); // Stack [ [ 1, 3 ], [ 2, 4 ], [ undefined, 5 ] ]
     * ```
     *
     * Note: Since zipAll will return a collection as large as the largest
     * input, some results may contain undefined values. TypeScript cannot
     * account for these without cases (as of v2.5).
     */
    zipAll<U>(other: Collection<any, U>): Stack<[T,U]>;
    zipAll<U,V>(other: Collection<any, U>, other2: Collection<any,V>): Stack<[T,U,V]>;
    zipAll(...collections: Array<Collection<any, any>>): Stack<any>;

    /**
     * Returns a Stack "zipped" with the provided collections by using a
     * custom `zipper` function.
     *
     * ```js
     * const a = Stack([ 1, 2, 3 ]);
     * const b = Stack([ 4, 5, 6 ]);
     * const c = a.zipWith((a, b) => a + b, b);
     * // Stack [ 5, 7, 9 ]
     * ```
     */
    zipWith<U, Z>(
      zipper: (value: T, otherValue: U) => Z,
      otherCollection: Collection<any, U>
    ): Stack<Z>;
    zipWith<U, V, Z>(
      zipper: (value: T, otherValue: U, thirdValue: V) => Z,
      otherCollection: Collection<any, U>,
      thirdCollection: Collection<any, V>
    ): Stack<Z>;
    zipWith<Z>(
      zipper: (...any: Array<any>) => Z,
      ...collections: Array<Collection<any, any>>
    ): Stack<Z>;
  }


export interface Factory<TProps extends Object> {
      (values?: Partial<TProps> | Iterable<[string, any]>): Record<TProps> & Readonly<TProps>;
      new (values?: Partial<TProps> | Iterable<[string, any]>): Record<TProps> & Readonly<TProps>;

      /**
       * The name provided to `Record(values, name)` can be accessed with
       * `displayName`.
       */
      displayName: string;
    }


export interface Record<TProps extends Object> {

    // Reading values

    has(key: string): key is keyof TProps & string;

    /**
     * Returns the value associated with the provided key, which may be the
     * default value defined when creating the Record factory function.
     *
     * If the requested key is not defined by this Record type, then
     * notSetValue will be returned if provided. Note that this scenario would
     * produce an error when using Flow or TypeScript.
     */
    get<K extends keyof TProps>(key: K, notSetValue?: any): TProps[K];
    get<T>(key: string, notSetValue: T): T;

    // Reading deep values

    hasIn(keyPath: Iterable<any>): boolean;
    getIn(keyPath: Iterable<any>): any;

    // Value equality

    equals(other: any): boolean;
    hashCode(): number;

    // Persistent changes

    set<K extends keyof TProps>(key: K, value: TProps[K]): this;
    update<K extends keyof TProps>(key: K, updater: (value: TProps[K]) => TProps[K]): this;
    merge(...collections: Array<Partial<TProps> | Iterable<[string, any]>>): this;
    mergeDeep(...collections: Array<Partial<TProps> | Iterable<[string, any]>>): this;

    mergeWith(
      merger: (oldVal: any, newVal: any, key: keyof TProps) => any,
      ...collections: Array<Partial<TProps> | Iterable<[string, any]>>
    ): this;
    mergeDeepWith(
      merger: (oldVal: any, newVal: any, key: any) => any,
      ...collections: Array<Partial<TProps> | Iterable<[string, any]>>
    ): this;

    /**
     * Returns a new instance of this Record type with the value for the
     * specific key set to its default value.
     *
     * @alias remove
     */
    delete<K extends keyof TProps>(key: K): this;
    remove<K extends keyof TProps>(key: K): this;

    /**
     * Returns a new instance of this Record type with all values set
     * to their default values.
     */
    clear(): this;

    // Deep persistent changes

    setIn(keyPath: Iterable<any>, value: any): this;
    updateIn(keyPath: Iterable<any>, updater: (value: any) => any): this;
    mergeIn(keyPath: Iterable<any>, ...collections: Array<any>): this;
    mergeDeepIn(keyPath: Iterable<any>, ...collections: Array<any>): this;

    /**
     * @alias removeIn
     */
    deleteIn(keyPath: Iterable<any>): this;
    removeIn(keyPath: Iterable<any>): this;

    // Conversion to JavaScript types

    /**
     * Deeply converts this Record to equivalent native JavaScript Object.
     *
     * Note: This method may not be overridden. Objects with custom
     * serialization to plain JS may override toJSON() instead.
     */
    toJS(): { [K in keyof TProps]: any };

    /**
     * Shallowly converts this Record to equivalent native JavaScript Object.
     */
    toJSON(): TProps;

    /**
     * Shallowly converts this Record to equivalent JavaScript Object.
     */
    toObject(): TProps;

    // Transient changes

    /**
     * Note: Not all methods can be used on a mutable collection or within
     * `withMutations`! Only `set` may be used mutatively.
     *
     * @see `Map#withMutations`
     */
    withMutations(mutator: (mutable: this) => any): this;

    /**
     * @see `Map#asMutable`
     */
    asMutable(): this;

    /**
     * @see `Map#wasAltered`
     */
    wasAltered(): boolean;

    /**
     * @see `Map#asImmutable`
     */
    asImmutable(): this;

    // Sequence algorithms

    toSeq(): Seq.Keyed<keyof TProps, TProps[keyof TProps]>;

    [Symbol.iterator](): IterableIterator<[keyof TProps, TProps[keyof TProps]]>;
  }


export interface Keyed<K, V> extends Seq<K, V>, Collection.Keyed<K, V> {
      /**
       * Deeply converts this Keyed Seq to equivalent native JavaScript Object.
       *
       * Converts keys to Strings.
       */
      toJS(): Object;

      /**
       * Shallowly converts this Keyed Seq to equivalent native JavaScript Object.
       *
       * Converts keys to Strings.
       */
      toJSON(): { [key: string]: V };

      /**
       * Shallowly converts this collection to an Array.
       */
      toArray(): Array<[K, V]>;

      /**
       * Returns itself
       */
      toSeq(): this;

      /**
       * Returns a new Seq with other collections concatenated to this one.
       *
       * All entries will be present in the resulting Seq, even if they
       * have the same key.
       */
      concat<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): Seq.Keyed<K | KC, V | VC>;
      concat<C>(...collections: Array<{[key: string]: C}>): Seq.Keyed<K | string, V | C>;

      /**
       * Returns a new Seq.Keyed with values passed through a
       * `mapper` function.
       *
       * ```js
       * const { Seq } = require('immutable')
       * Seq.Keyed({ a: 1, b: 2 }).map(x => 10 * x)
       * // Seq { "a": 10, "b": 20 }
       * ```
       *
       * Note: `map()` always returns a new instance, even if it produced the
       * same value at every step.
       */
      map<M>(
        mapper: (value: V, key: K, iter: this) => M,
        context?: any
      ): Seq.Keyed<K, M>;

      /**
       * @see Collection.Keyed.mapKeys
       */
      mapKeys<M>(
        mapper: (key: K, value: V, iter: this) => M,
        context?: any
      ): Seq.Keyed<M, V>;

      /**
       * @see Collection.Keyed.mapEntries
       */
      mapEntries<KM, VM>(
        mapper: (entry: [K, V], index: number, iter: this) => [KM, VM],
        context?: any
      ): Seq.Keyed<KM, VM>;

      /**
       * Flat-maps the Seq, returning a Seq of the same type.
       *
       * Similar to `seq.map(...).flatten(true)`.
       */
      flatMap<KM, VM>(
        mapper: (value: V, key: K, iter: this) => Iterable<[KM, VM]>,
        context?: any
      ): Seq.Keyed<KM, VM>;

      /**
       * Returns a new Seq with only the entries for which the `predicate`
       * function returns true.
       *
       * Note: `filter()` always returns a new instance, even if it results in
       * not filtering out any values.
       */
      filter<F extends V>(
        predicate: (value: V, key: K, iter: this) => value is F,
        context?: any
      ): Seq.Keyed<K, F>;
      filter(
        predicate: (value: V, key: K, iter: this) => any,
        context?: any
      ): this;

      /**
       * @see Collection.Keyed.flip
       */
      flip(): Seq.Keyed<V, K>;
    }


export interface Indexed<T> extends Seq<number, T>, Collection.Indexed<T> {
      /**
       * Deeply converts this Indexed Seq to equivalent native JavaScript Array.
       */
      toJS(): Array<any>;

      /**
       * Shallowly converts this Indexed Seq to equivalent native JavaScript Array.
       */
      toJSON(): Array<T>;

      /**
       * Shallowly converts this collection to an Array.
       */
      toArray(): Array<T>;

      /**
       * Returns itself
       */
      toSeq(): this

      /**
       * Returns a new Seq with other collections concatenated to this one.
       */
      concat<C>(...valuesOrCollections: Array<Iterable<C> | C>): Seq.Indexed<T | C>;

      /**
       * Returns a new Seq.Indexed with values passed through a
       * `mapper` function.
       *
       * ```js
       * const { Seq } = require('immutable')
       * Seq.Indexed([ 1, 2 ]).map(x => 10 * x)
       * // Seq [ 10, 20 ]
       * ```
       *
       * Note: `map()` always returns a new instance, even if it produced the
       * same value at every step.
       */
      map<M>(
        mapper: (value: T, key: number, iter: this) => M,
        context?: any
      ): Seq.Indexed<M>;

      /**
       * Flat-maps the Seq, returning a a Seq of the same type.
       *
       * Similar to `seq.map(...).flatten(true)`.
       */
      flatMap<M>(
        mapper: (value: T, key: number, iter: this) => Iterable<M>,
        context?: any
      ): Seq.Indexed<M>;

      /**
       * Returns a new Seq with only the values for which the `predicate`
       * function returns true.
       *
       * Note: `filter()` always returns a new instance, even if it results in
       * not filtering out any values.
       */
      filter<F extends T>(
        predicate: (value: T, index: number, iter: this) => value is F,
        context?: any
      ): Seq.Indexed<F>;
      filter(
        predicate: (value: T, index: number, iter: this) => any,
        context?: any
      ): this;

      /**
       * Returns a Seq "zipped" with the provided collections.
       *
       * Like `zipWith`, but using the default `zipper`: creating an `Array`.
       *
       * ```js
       * const a = Seq([ 1, 2, 3 ]);
       * const b = Seq([ 4, 5, 6 ]);
       * const c = a.zip(b); // Seq [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ]
       * ```
       */
      zip<U>(other: Collection<any, U>): Seq.Indexed<[T,U]>;
      zip<U,V>(other: Collection<any, U>, other2: Collection<any, V>): Seq.Indexed<[T,U,V]>;
      zip(...collections: Array<Collection<any, any>>): Seq.Indexed<any>;

      /**
       * Returns a Seq "zipped" with the provided collections.
       *
       * Unlike `zip`, `zipAll` continues zipping until the longest collection is
       * exhausted. Missing values from shorter collections are filled with `undefined`.
       *
       * ```js
       * const a = Seq([ 1, 2 ]);
       * const b = Seq([ 3, 4, 5 ]);
       * const c = a.zipAll(b); // Seq [ [ 1, 3 ], [ 2, 4 ], [ undefined, 5 ] ]
       * ```
       */
      zipAll<U>(other: Collection<any, U>): Seq.Indexed<[T,U]>;
      zipAll<U,V>(other: Collection<any, U>, other2: Collection<any, V>): Seq.Indexed<[T,U,V]>;
      zipAll(...collections: Array<Collection<any, any>>): Seq.Indexed<any>;

      /**
       * Returns a Seq "zipped" with the provided collections by using a
       * custom `zipper` function.
       *
       * ```js
       * const a = Seq([ 1, 2, 3 ]);
       * const b = Seq([ 4, 5, 6 ]);
       * const c = a.zipWith((a, b) => a + b, b);
       * // Seq [ 5, 7, 9 ]
       * ```
       */
      zipWith<U, Z>(
        zipper: (value: T, otherValue: U) => Z,
        otherCollection: Collection<any, U>
      ): Seq.Indexed<Z>;
      zipWith<U, V, Z>(
        zipper: (value: T, otherValue: U, thirdValue: V) => Z,
        otherCollection: Collection<any, U>,
        thirdCollection: Collection<any, V>
      ): Seq.Indexed<Z>;
      zipWith<Z>(
        zipper: (...any: Array<any>) => Z,
        ...collections: Array<Collection<any, any>>
      ): Seq.Indexed<Z>;
    }


export interface Set<T> extends Seq<T, T>, Collection.Set<T> {
      /**
       * Deeply converts this Set Seq to equivalent native JavaScript Array.
       */
      toJS(): Array<any>;

      /**
       * Shallowly converts this Set Seq to equivalent native JavaScript Array.
       */
      toJSON(): Array<T>;

      /**
       * Shallowly converts this collection to an Array.
       */
      toArray(): Array<T>;

      /**
       * Returns itself
       */
      toSeq(): this

      /**
       * Returns a new Seq with other collections concatenated to this one.
       *
       * All entries will be present in the resulting Seq, even if they
       * are duplicates.
       */
      concat<U>(...collections: Array<Iterable<U>>): Seq.Set<T | U>;

      /**
       * Returns a new Seq.Set with values passed through a
       * `mapper` function.
       *
       * ```js
       * Seq.Set([ 1, 2 ]).map(x => 10 * x)
       * // Seq { 10, 20 }
       * ```
       *
       * Note: `map()` always returns a new instance, even if it produced the
       * same value at every step.
       */
      map<M>(
        mapper: (value: T, key: T, iter: this) => M,
        context?: any
      ): Seq.Set<M>;

      /**
       * Flat-maps the Seq, returning a Seq of the same type.
       *
       * Similar to `seq.map(...).flatten(true)`.
       */
      flatMap<M>(
        mapper: (value: T, key: T, iter: this) => Iterable<M>,
        context?: any
      ): Seq.Set<M>;

      /**
       * Returns a new Seq with only the values for which the `predicate`
       * function returns true.
       *
       * Note: `filter()` always returns a new instance, even if it results in
       * not filtering out any values.
       */
      filter<F extends T>(
        predicate: (value: T, key: T, iter: this) => value is F,
        context?: any
      ): Seq.Set<F>;
      filter(
        predicate: (value: T, key: T, iter: this) => any,
        context?: any
      ): this;
    }


export interface Seq<K, V> extends Collection<K, V> {

    /**
     * Some Seqs can describe their size lazily. When this is the case,
     * size will be an integer. Otherwise it will be undefined.
     *
     * For example, Seqs returned from `map()` or `reverse()`
     * preserve the size of the original `Seq` while `filter()` does not.
     *
     * Note: `Range`, `Repeat` and `Seq`s made from `Array`s and `Object`s will
     * always have a size.
     */
    readonly size: number | undefined;

    // Force evaluation

    /**
     * Because Sequences are lazy and designed to be chained together, they do
     * not cache their results. For example, this map function is called a total
     * of 6 times, as each `join` iterates the Seq of three values.
     *
     *     var squares = Seq([ 1, 2, 3 ]).map(x => x * x)
     *     squares.join() + squares.join()
     *
     * If you know a `Seq` will be used multiple times, it may be more
     * efficient to first cache it in memory. Here, the map function is called
     * only 3 times.
     *
     *     var squares = Seq([ 1, 2, 3 ]).map(x => x * x).cacheResult()
     *     squares.join() + squares.join()
     *
     * Use this method judiciously, as it must fully evaluate a Seq which can be
     * a burden on memory and possibly performance.
     *
     * Note: after calling `cacheResult`, a Seq will always have a `size`.
     */
    cacheResult(): this;

    // Sequence algorithms

    /**
     * Returns a new Seq with values passed through a
     * `mapper` function.
     *
     * ```js
     * const { Seq } = require('immutable')
     * Seq([ 1, 2 ]).map(x => 10 * x)
     * // Seq [ 10, 20 ]
     * ```
     *
     * Note: `map()` always returns a new instance, even if it produced the same
     * value at every step.
     */
    map<M>(
      mapper: (value: V, key: K, iter: this) => M,
      context?: any
    ): Seq<K, M>;

    /**
     * Returns a new Seq with values passed through a
     * `mapper` function.
     *
     * ```js
     * const { Seq } = require('immutable')
     * Seq([ 1, 2 ]).map(x => 10 * x)
     * // Seq [ 10, 20 ]
     * ```
     *
     * Note: `map()` always returns a new instance, even if it produced the same
     * value at every step.
     * Note: used only for sets.
     */
    map<M>(
      mapper: (value: V, key: K, iter: this) => M,
      context?: any
    ): Seq<M, M>;

    /**
     * Flat-maps the Seq, returning a Seq of the same type.
     *
     * Similar to `seq.map(...).flatten(true)`.
     */
    flatMap<M>(
      mapper: (value: V, key: K, iter: this) => Iterable<M>,
      context?: any
    ): Seq<K, M>;

    /**
     * Flat-maps the Seq, returning a Seq of the same type.
     *
     * Similar to `seq.map(...).flatten(true)`.
     * Note: Used only for sets.
     */
    flatMap<M>(
      mapper: (value: V, key: K, iter: this) => Iterable<M>,
      context?: any
    ): Seq<M, M>;

    /**
     * Returns a new Seq with only the values for which the `predicate`
     * function returns true.
     *
     * Note: `filter()` always returns a new instance, even if it results in
     * not filtering out any values.
     */
    filter<F extends V>(
      predicate: (value: V, key: K, iter: this) => value is F,
      context?: any
    ): Seq<K, F>;
    filter(
      predicate: (value: V, key: K, iter: this) => any,
      context?: any
    ): this;
  }


export interface Keyed<K, V> extends Collection<K, V> {
      /**
       * Deeply converts this Keyed collection to equivalent native JavaScript Object.
       *
       * Converts keys to Strings.
       */
      toJS(): Object;

      /**
       * Shallowly converts this Keyed collection to equivalent native JavaScript Object.
       *
       * Converts keys to Strings.
       */
      toJSON(): { [key: string]: V };

      /**
       * Shallowly converts this collection to an Array.
       */
      toArray(): Array<[K, V]>;

      /**
       * Returns Seq.Keyed.
       * @override
       */
      toSeq(): Seq.Keyed<K, V>;

      // Sequence functions

      /**
       * Returns a new Collection.Keyed of the same type where the keys and values
       * have been flipped.
       *
       * <!-- runkit:activate -->
       * ```js
       * const { Map } = require('immutable')
       * Map({ a: 'z', b: 'y' }).flip()
       * // Map { "z": "a", "y": "b" }
       * ```
       */
      flip(): Collection.Keyed<V, K>;

      /**
       * Returns a new Collection with other collections concatenated to this one.
       */
      concat<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): Collection.Keyed<K | KC, V | VC>;
      concat<C>(...collections: Array<{[key: string]: C}>): Collection.Keyed<K | string, V | C>;

      /**
       * Returns a new Collection.Keyed with values passed through a
       * `mapper` function.
       *
       * ```js
       * const { Collection } = require('immutable')
       * Collection.Keyed({ a: 1, b: 2 }).map(x => 10 * x)
       * // Seq { "a": 10, "b": 20 }
       * ```
       *
       * Note: `map()` always returns a new instance, even if it produced the
       * same value at every step.
       */
      map<M>(
        mapper: (value: V, key: K, iter: this) => M,
        context?: any
      ): Collection.Keyed<K, M>;

      /**
       * Returns a new Collection.Keyed of the same type with keys passed through
       * a `mapper` function.
       *
       * <!-- runkit:activate -->
       * ```js
       * const { Map } = require('immutable')
       * Map({ a: 1, b: 2 }).mapKeys(x => x.toUpperCase())
       * // Map { "A": 1, "B": 2 }
       * ```
       *
       * Note: `mapKeys()` always returns a new instance, even if it produced
       * the same key at every step.
       */
      mapKeys<M>(
        mapper: (key: K, value: V, iter: this) => M,
        context?: any
      ): Collection.Keyed<M, V>;

      /**
       * Returns a new Collection.Keyed of the same type with entries
       * ([key, value] tuples) passed through a `mapper` function.
       *
       * <!-- runkit:activate -->
       * ```js
       * const { Map } = require('immutable')
       * Map({ a: 1, b: 2 })
       *   .mapEntries(([ k, v ]) => [ k.toUpperCase(), v * 2 ])
       * // Map { "A": 2, "B": 4 }
       * ```
       *
       * Note: `mapEntries()` always returns a new instance, even if it produced
       * the same entry at every step.
       */
      mapEntries<KM, VM>(
        mapper: (entry: [K, V], index: number, iter: this) => [KM, VM],
        context?: any
      ): Collection.Keyed<KM, VM>;

      /**
       * Flat-maps the Collection, returning a Collection of the same type.
       *
       * Similar to `collection.map(...).flatten(true)`.
       */
      flatMap<KM, VM>(
        mapper: (value: V, key: K, iter: this) => Iterable<[KM, VM]>,
        context?: any
      ): Collection.Keyed<KM, VM>;

      /**
       * Returns a new Collection with only the values for which the `predicate`
       * function returns true.
       *
       * Note: `filter()` always returns a new instance, even if it results in
       * not filtering out any values.
       */
      filter<F extends V>(
        predicate: (value: V, key: K, iter: this) => value is F,
        context?: any
      ): Collection.Keyed<K, F>;
      filter(
        predicate: (value: V, key: K, iter: this) => any,
        context?: any
      ): this;

      [Symbol.iterator](): IterableIterator<[K, V]>;
    }


export interface Set<T> extends Collection<T, T> {
      /**
       * Deeply converts this Set collection to equivalent native JavaScript Array.
       */
      toJS(): Array<any>;

      /**
       * Shallowly converts this Set collection to equivalent native JavaScript Array.
       */
      toJSON(): Array<T>;

      /**
       * Shallowly converts this collection to an Array.
       */
      toArray(): Array<T>;

      /**
       * Returns Seq.Set.
       * @override
       */
      toSeq(): Seq.Set<T>;

      // Sequence algorithms

      /**
       * Returns a new Collection with other collections concatenated to this one.
       */
      concat<U>(...collections: Array<Iterable<U>>): Collection.Set<T | U>;

      /**
       * Returns a new Collection.Set with values passed through a
       * `mapper` function.
       *
       * ```
       * Collection.Set([ 1, 2 ]).map(x => 10 * x)
       * // Seq { 1, 2 }
       * ```
       *
       * Note: `map()` always returns a new instance, even if it produced the
       * same value at every step.
       */
      map<M>(
        mapper: (value: T, key: T, iter: this) => M,
        context?: any
      ): Collection.Set<M>;

      /**
       * Flat-maps the Collection, returning a Collection of the same type.
       *
       * Similar to `collection.map(...).flatten(true)`.
       */
      flatMap<M>(
        mapper: (value: T, key: T, iter: this) => Iterable<M>,
        context?: any
      ): Collection.Set<M>;

      /**
       * Returns a new Collection with only the values for which the `predicate`
       * function returns true.
       *
       * Note: `filter()` always returns a new instance, even if it results in
       * not filtering out any values.
       */
      filter<F extends T>(
        predicate: (value: T, key: T, iter: this) => value is F,
        context?: any
      ): Collection.Set<F>;
      filter(
        predicate: (value: T, key: T, iter: this) => any,
        context?: any
      ): this;

      [Symbol.iterator](): IterableIterator<T>;
    }


/**
   * The interface to fulfill to qualify as a Value Object.
   */
export interface ValueObject {
    /**
     * True if this and the other Collection have value equality, as defined
     * by `Immutable.is()`.
     *
     * Note: This is equivalent to `Immutable.is(this, other)`, but provided to
     * allow for chained expressions.
     */
    equals(other: any): boolean;

    /**
     * Computes and returns the hashed identity for this Collection.
     *
     * The `hashCode` of a Collection is used to determine potential equality,
     * and is used when adding this to a `Set` or as a key in a `Map`, enabling
     * lookup via a different instance.
     *
     * <!-- runkit:activate -->
     * ```js
     * const { List, Set } = require('immutable');
     * const a = List([ 1, 2, 3 ]);
     * const b = List([ 1, 2, 3 ]);
     * assert.notStrictEqual(a, b); // different instances
     * const set = Set([ a ]);
     * assert.equal(set.has(b), true);
     * ```
     *
     * Note: hashCode() MUST return a Uint32 number. The easiest way to
     * guarantee this is to return `myHash | 0` from a custom implementation.
     *
     * If two values have the same `hashCode`, they are [not guaranteed
     * to be equal][Hash Collision]. If two values have different `hashCode`s,
     * they must not be equal.
     *
     * Note: `hashCode()` is not guaranteed to always be called before
     * `equals()`. Most but not all Immutable.js collections use hash codes to
     * organize their internal data structures, while all Immutable.js
     * collections use equality during lookups.
     *
     * [Hash Collision]: http://en.wikipedia.org/wiki/Collision_(computer_science)
     */
    hashCode(): number;
  }


/**
   * RecordOf<T> is used in TypeScript to define interfaces expecting an
   * instance of record with type T.
   *
   * This is equivalent to an instance of a record created by a Record Factory.
   */
export type RecordOf<TProps extends Object> = Record<TProps> &
    Readonly<TProps>;


export class HelpCategory {
	constructor(private jar: HttpService) {}

	public getAll(): Observable<IHelpCategory[]> {
		return this.jar.get<IHelpCategory[]>('help/categories');
	}

	public create(data: { name: string; description: string }): Observable<IHelpCategory> {
		return this.jar.post<IHelpCategory>('help/categories', data);
	}

	public update(category: IHelpCategory): Observable<IHelpCategory> {
		return this.jar.patch<IHelpCategory>(`help/categories/${category.id}`, pick(category, ['name', 'description', 'order']));
	}

	public destroy(category: IHelpCategory): Observable<void> {
		return this.jar.delete<void>(`help/categories/${category.id}`);
	}
}


export interface IHelpCategory extends Identifiable, Dated {
	name: string;
	description: string;
	order: number;
	slug: string;
}


public getAll(): Observable<IHelpCategory[]> {
		return this.jar.get<IHelpCategory[]>('help/categories');
	}


public create(data: { name: string; description: string }): Observable<IHelpCategory> {
		return this.jar.post<IHelpCategory>('help/categories', data);
	}


public update(category: IHelpCategory): Observable<IHelpCategory> {
		return this.jar.patch<IHelpCategory>(`help/categories/${category.id}`, pick(category, ['name', 'description', 'order']));
	}


public destroy(category: IHelpCategory): Observable<void> {
		return this.jar.delete<void>(`help/categories/${category.id}`);
	}


export interface comments{
    uid?: string;
    stars?: number;
    uidUser?: string;
    uidRecipe?: string;
    comment?: string;
    difficult?: number;
    timeStamp?: any;
    displayName?: string;
    userRecipe?: string;
}


interface Jovo {
    $googleAction?: GoogleAction;

    /**
     * Returns googleAction instance
     * @returns {GoogleAction}
     */
    googleAction(): GoogleAction;

    /**
     * Type of platform is Google Action
     * @public
     * @return {boolean} isGoogleAction
     */
    isGoogleAction(): boolean;
  }


/**
   * Sets alexa handlers
   * @public
   * @param {*} handler
   */
interface BaseApp {
    setGoogleAssistantHandler(...handler: Handler[]): this;
  }


interface GoogleAction {
    /**
     * Ask for name
     * @public
     * @param {string} optContext
     */
    askForName(optContext?: string): this;

    /**
     * Ask for zipcode and city
     * @public
     * @param {string} optContext
     */
    askForZipCodeAndCity(optContext?: string): this;

    /**
     * Ask for name permission
     * @public
     * @param {string} optContext
     */
    askForNamePermission(optContext?: string): this;

    /**
     * Ask for coarse location permission
     * @public
     * @param {string} optContext
     */
    askForCoarseLocation(optContext?: string): this;

    /**
     * Ask for precise permissions
     * @public
     * @param {string} optContext
     */
    askForPreciseLocation(optContext?: string): this;

    /**
     * Calls askForNotification(intent, name, text)
     *
     * @public
     * @param {string} intent // intent for which you want to send notifications
     */
    askForUpdate(intent: string): this;

    /**
     * Ask for notification permission
     * @public
     * @param {string} intent // intent for which you want to send notifications
     */
    askForNotification(intent: string): this;

    /**
     * Ask for permissions
     * @public
     * @param {'NAME'|'DEVICE_COARSE_LOCATION'|'DEVICE_PRECISE_LOCATION'} permissions
     * @param {string} optContext
     */
    askForPermission(permissions: string[], optContext?: string): this;

    /**
     * Returns true if permission granted
     * @return {boolean}
     */
    isPermissionGranted(): boolean;

    /**
     * Ask form sign in
     * @public
     * @param {string} optContext
     */
    askForSignIn(optContext?: string): this;

    /**
     * Returns sign in status after sign in
     * @public
     * @return {boolean}
     */
    getSignInStatus(): string;

    /**
     * Returns sign in cancelled
     * @public
     * @return {boolean}
     */
    isSignInCancelled(): boolean;

    /**
     * Returns sign in denied
     * @public
     * @return {boolean}
     */
    isSignInDenied(): boolean;

    /**
     * Returns sign in ok
     * @public
     * @return {null|string}
     */
    isSignInOk(): boolean;

    /**
     * Ask for date time
     * @public
     * @param {*} questions
     */
    askForDateTime(questions: {
      requestDatetimeText: string;
      requestDateText: string;
      requestTimeText: string;
    }): this;

    /**
     * Return date time confirmation value
     * @returns {string}
     */
    getDateTime(): string;

    /**
     * Return place confirmation value
     * @return {object}
     */
    getPlace(): object | undefined;

    /**
     * Ask for confirmation
     * @public
     * @param {*} text
     */
    askForConfirmation(text: string): this;

    /**
     * Return confirmation status
     * @returns {boolean}
     */
    isConfirmed(): boolean;

    /**
     *  Ask for place
     * @param {string} requestPrompt
     * @param {string} permissionContext
     * @returns {this}
     */
    askForPlace(requestPrompt: string, permissionContext?: string): this;

    /**
     * Return device object
     * @returns {Device}
     */
    getDevice(): Device;
  }


interface GoogleAction {
    /**
     * Adds basic card to response
     * Works only with SCREEN_OUTPUT devices
     * @public
     * @param {BasicCard} basicCard
     * @return {GoogleAction}
     */
    showBasicCard(basicCard: BasicCard): this;

    /**
     * Adds suggestion chips to response
     * Works only with SCREEN_OUTPUT devices
     * @public
     * @param {Array<String>} chips
     * @return {GoogleAction}
     */
    showSuggestionChips(chips: string[]): this;

    /**
     * Adds link out suggestion chip to response
     * @public
     * @param {string} destinationName
     * @param {string} url
     * @return {GoogleAction}
     */
    showLinkOutSuggestion(destinationName: string, url: string): this;

    /**
     * Adds carousel element to response
     * Works only with SCREEN_OUTPUT devices
     * @public
     * @param {Carousel} carousel
     * @return {GoogleAction}
     */
    showCarousel(carousel: Carousel): this;

    /**
     * Adds carousel browse element to response
     * Works only with SCREEN_OUTPUT devices
     * @public
     * @param {Carousel} carouselBrowse
     * @return {GoogleAction}
     */
    showCarouselBrowse(carouselBrowse: CarouselBrowse): this;

    /**
     * Implementation of generic withSimpleTable
     * Shows a simple table card to the response object
     * @public
     * @param {string} title
     * @param {string} subtitle
     * @param {array} columnHeaders
     * @param {array} rowsText
     * @return {GoogleAction} this
     */
    showSimpleTable(
      title: string,
      subtitle: string,
      columnHeaders: string[],
      rowsText: string[][],
    ): this;

    /**
     * Adds table to response
     * Works only with SCREEN_OUTPUT devices
     * @public
     * @param {Table} table
     * @return {GoogleAction}
     */
    showTable(table: Table): this;

    /**
     * Adds list element to response
     * Works only with SCREEN_OUTPUT devices
     * @public
     * @param {List} list
     * @return {GoogleAction}
     */
    showList(list: List): this;

    /**
     * Returns token of the request
     * (Touched/Selected Element )
     * @public
     * @return {*}
     */
    getSelectedElementId(): string;
  }


interface GoogleAction {
    displayText(displayText: string): this;
    richResponse(richResponse: RichResponse): this;
    appendResponse(responseItem: Item): this;
    appendSimpleResponse(simpleResponse: SimpleResponse): this;

    addSessionEntity(
      name: string,
      value: string,
      synonyms: string[],
      entityOverrideMode?: EntityOverrideMode,
    ): this;
    addSessionEntityTypes(sessionEntityTypes: SessionEntityType[]): this;
    addSessionEntityType(sessionEntityType: SessionEntityType): this;
  }


interface GoogleAction {
    $audioPlayer?: MediaResponse;
    $mediaResponse?: MediaResponse;
    $updates?: Updates;

    audioPlayer(): MediaResponse | undefined;
    mediaResponse(): MediaResponse | undefined;
  }


interface GoogleAction {
    $transaction?: Transaction;
  }


interface GoogleAction {
    htmlResponse(obj: {
      url?: string;
      data?: Record<string, any>; // tslint:disable-line
      suppress?: boolean;
    }): this;
  }


interface GoogleAction {
    newSurface(capabilities: string[], context: string, notificationTitle: string): this;
    isNewSurfaceConfirmed(): boolean;
  }


interface GoogleAction {
    $notification?: Notification;
    notification(): Notification | undefined;
  }


export interface AppGoogleAssistantConfig {
  GoogleAssistant?: Config;
}


interface Output {
    GoogleAssistant: {
      AskForPermission?: {
        permissions: string[];
        optContext: string;
      };
      AskForUpdatePermission?: {
        intent: string;
        arguments?: object;
      };

      AskForRegisterUpdate?: {
        intent: string;
        frequency: string;
      };

      AskForSignIn?: {
        optContext: string;
      };
      AskForDateTime?: {
        requestDatetimeText: string;
        requestDateText: string;
        requestTimeText: string;
      };
      AskForConfirmation?: string;
      AskForPlace?: {
        requestPrompt: string;
        permissionContext: string;
      };
      card?: {
        BasicCard?: BasicCard;
      };
      SuggestionChips?: string[];
      LinkOutSuggestion?: {
        destinationName: string;
        url: string;
      };
      CarouselBrowse?: CarouselBrowse;
      Carousel?: Carousel;

      Table?: Table;
      List?: List;
      MediaResponse?: MediaObject;

      // transactions
      AskForDeliveryAddress?: {
        reason: string;
      };

      TransactionDecision?: {
        orderOptions?: OrderOptions;
        paymentOptions: PaymentOptions;
        proposedOrder: any; // tslint:disable-line
      };

      TransactionRequirementsCheck?: {};

      TransactionDigitalPurchaseRequirementsCheck?: {};

      TransactionOrder?: {
        order: Order;
        presentationOptions?: PresentationOptions;
        orderOptions?: OrderOptions;
        paymentParameters?: PaymentParameters;
      };

      TransactionOrderUpdate?: {
        orderUpdate: OrderUpdateV3;
      };

      OrderUpdate?: {
        orderUpdate: OrderUpdate;
        speech: string;
      };

      CompletePurchase?: {
        skuId: SkuId;
      };

      HtmlResponse?: {
        url?: string;
        data?: Record<string, any>; // tslint:disable-line
        suppress?: boolean;
      };

      NewSurface?: {
        capabilities: string[];
        context: string;
        notificationTitle: string;
      };

      RichResponse?: RichResponse;
      ResponseAppender?: Item[];

      SessionEntityTypes?: SessionEntityType[];
    };
  }


export interface AppPlatformConfig extends AppGoogleAssistantConfig {}


export interface ExtensiblePluginConfigs extends AppGoogleAssistantConfig {}


export interface ProdutorModel {
    categoria: string;
    cep: string;
    cidade: string;
    cpf: string;
    endereco: string;
    nascimento: string;
    nome: string;
    telefone: string;
}


/**
 * This class represents the main application component.
 */
@Component({
  moduleId: module.id,
  selector: 'jg-app',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css'],
})
export class AppComponent {
}


(secret: string): boolean => {
  try {
    return isValidPrivate(Buffer.from(filterOx(secret), "hex"));
  } catch (error) {
    return false;
  }
}


(address: string): boolean => {
  return /^(0x)?[0-9a-fA-F]{40}$/.test(filterOx(address));
}


(secret: string): string | null => {
  secret = filterOx(secret);
  if (!isValidSecret(secret)) {
    return null;
  }
  const buffer = privateToAddress(Buffer.from(secret, "hex"));
  const decodeAddress = bufferToHex(buffer);
  return decodeAddress;
}


(): IWalletModel => {
  const _w = Wallet.generate();
  return { address: _w.getAddressString(), secret: _w.getPrivateKeyString() };
}


export class Mutable extends TestSuite {
  constructor() {
    super(false); // override useFreeze
  }

  set(obj, key, val) {
    obj[key] = val;
    return obj;
  }

  setDeep(obj, key1, key2, val) {
    obj[key1][key2] = val;
    return obj;
  }

  setIn(obj, path, val) {
    let idx, j, ptr, ref1;
    ptr = obj;
    for (idx = j = 0, ref1 = path.length - 1; 0 <= ref1 ? j < ref1 : j > ref1; idx = 0 <= ref1 ? ++j : --j) {
        ptr = ptr[path[idx]];
    }
    ptr[path[path.length - 1]] = val;
    return obj;
  }

  merge(obj1, obj2) {
    const ref1 = Object.keys(obj2);
    const results1: any[] = [];
    for (let j = 0, len = ref1.length; j < len; j++) {
      const key = ref1[j];
      results1.push(obj1[key] = obj2[key]);
    }
    return results1;
  }

  setAt(arr, idx, val) {
    arr[idx] = val;
    return arr;
  }

  setAtDeep(arr, idx1, idx2, val) {
    arr[idx1][idx2] = val;
    return arr;
  }
}


set(obj, key, val) {
    obj[key] = val;
    return obj;
  }


setDeep(obj, key1, key2, val) {
    obj[key1][key2] = val;
    return obj;
  }


setIn(obj, path, val) {
    let idx, j, ptr, ref1;
    ptr = obj;
    for (idx = j = 0, ref1 = path.length - 1; 0 <= ref1 ? j < ref1 : j > ref1; idx = 0 <= ref1 ? ++j : --j) {
        ptr = ptr[path[idx]];
    }
    ptr[path[path.length - 1]] = val;
    return obj;
  }


merge(obj1, obj2) {
    const ref1 = Object.keys(obj2);
    const results1: any[] = [];
    for (let j = 0, len = ref1.length; j < len; j++) {
      const key = ref1[j];
      results1.push(obj1[key] = obj2[key]);
    }
    return results1;
  }


setAt(arr, idx, val) {
    arr[idx] = val;
    return arr;
  }


setAtDeep(arr, idx1, idx2, val) {
    arr[idx1][idx2] = val;
    return arr;
  }


/**
     * @deprecated v1.7.6
     *
     */
setup(): void;


/**
     * Register options and optgroups
     *
     */
setupOptions(options?: TomOption[], optgroups?: TomOption[]): void;


/**
     * Sets up default rendering functions.
     */
setupTemplates(): void;


/**
     * Maps fired events to callbacks provided
     * in the settings used when creating the control.
     */
setupCallbacks(): void;


/**
     * Triggered when the main control element
     * has a click event.
     *
     */
onClick(): void;


/**
     * @deprecated v1.7
     *
     */
onMouseDown(): void;


/**
     * Triggered when the value of the control has been changed.
     * This should propagate the event to the original DOM
     * input / select element.
     */
onChange(): void;


/**
     * Triggered on <input> paste.
     *
     */
onPaste(e: MouseEvent | KeyboardEvent): void;


/**
     * Triggered on <input> keypress.
     *
     */
onKeyPress(e: KeyboardEvent): void;


/**
     * Triggered on <input> keydown.
     *
     */
onKeyDown(e: KeyboardEvent): void;


/**
     * Triggered on <input> keyup.
     *
     */
onKeyUp(e: MouseEvent | KeyboardEvent): void;


/**
     * Triggered on <input> focus.
     *
     */
onFocus(e?: MouseEvent | KeyboardEvent): void;


/**
     * Triggered on <input> blur.
     *
     */
onBlur(): void;


/**
     * Triggered when the user clicks on an option
     * in the autocomplete dropdown menu.
     *
     */
onOptionSelect(evt: MouseEvent | KeyboardEvent, option: HTMLElement): void;


/**
     * Triggered when the user clicks on an item
     * that has been selected.
     *
     */
onItemSelect(evt?: MouseEvent, item?: TomItem): boolean;


/**
     * Determines whether or not to invoke
     * the user-provided option provider / loader
     *
     * Note, there is a subtle difference between
     * this.canLoad() and this.settings.shouldLoad();
     *
     *	- settings.shouldLoad() is a user-input validator.
     *	When false is returned, the not_loading template
     *	will be added to the dropdown
     *
     *	- canLoad() is lower level validator that checks
     * 	the Tom Select instance. There is no inherent user
     *	feedback when canLoad returns false
     *
     */
canLoad(value: string): boolean;


/**
     * Invokes the user-provided option provider / loader.
     *
     */
load(value: string): void;


/**
     * Invoked by the user-provided option provider
     *
     */
loadCallback(options: TomOption[], optgroups: TomOption[]): void;


/**
     * Sets the input field of the control to the specified value.
     *
     */
setTextboxValue(value?: string): void;


/**
     * Returns the value of the control. If multiple items
     * can be selected (e.g. <select multiple>), this returns
     * an array. If only one item can be selected, this
     * returns a string.
     *
     */
getValue(): string | string[];


/**
     * Resets the selected items to the given value.
     *
     */
setValue(value: string | string[], silent?: boolean): void;


/**
     * Resets the number of max items to the given value
     *
     */
setMaxItems(value: null | number): void;


/**
     * Sets the selected item.
     *
     */
setActiveItem(item?: TomItem, e?: MouseEvent | KeyboardEvent): void;


/**
     * Set the active and last-active classes
     *
     */
setActiveItemClass(item: TomItem): void;


/**
     * Remove active item
     *
     */
removeActiveItem(item: TomItem): void;


/**
     * Clears all the active items
     *
     */
clearActiveItems(): void;


/**
     * Sets the selected item in the dropdown menu
     * of available options.
     *
     */
setActiveOption(option: null | HTMLElement): void;


/**
     * Sets the dropdown_content scrollTop to display the option
     *
     */
scrollToOption(option: null | HTMLElement, behavior?: string): void;


/**
     * Scroll the dropdown to the given position
     *
     */
scroll(scrollTop: number, behavior?: string): void;


/**
     * Clears the active option
     *
     */
clearActiveOption(): void;


/**
     * Selects all items (CTRL + A).
     */
selectAll(): void;


/**
     * Determines if the control_input should be in a hidden or visible state
     *
     */
inputState(): void;


/**
     * Hides the input element out of view, while
     * retaining its focus.
     * @deprecated 1.3
     */
hideInput(): void;


/**
     * Restores input visibility.
     * @deprecated 1.3
     */
showInput(): void;


/**
     * Get the input value
     */
inputValue(): string;


/**
     * Gives the control focus.
     */
focus(): void;


/**
     * Forces the control out of focus.
     *
     */
blur(): void;


/**
     * Returns a function that scores an object
     * to show how good of a match it is to the
     * provided query.
     *
     * @return {function}
     */
getScoreFunction(query: string): (data: {}) => any;


/**
     * Returns search options for sifter (the system
     * for scoring and sorting results).
     *
     * @see https://github.com/orchidjs/sifter.js
     * @return {object}
     */
getSearchOptions(): {
        fields: string[];
        conjunction: string;
        sort: string | any[];
        nesting: boolean;
    };


/**
     * Searches through available options and returns
     * a sorted array of matches.
     *
     */
search(query: string): ReturnType<Sifter['search']>;


/**
     * Refreshes the list of available options shown
     * in the autocomplete dropdown menu.
     *
     */
refreshOptions(triggerDropdown?: boolean): void;


/**
     * Return list of selectable options
     *
     */
selectable(): NodeList;


/**
     * Adds an available option. If it already exists,
     * nothing will happen. Note: this does not refresh
     * the options list dropdown (use `refreshOptions`
     * for that).
     *
     * Usage:
     *
     *   this.addOption(data)
     *
     */
addOption(data: TomOption | TomOption[]): void;


/**
     * Registers an option to the pool of options.
     *
     */
registerOption(data: TomOption): false | string;


/**
     * Registers an option group to the pool of option groups.
     *
     * @return {boolean|string}
     */
registerOptionGroup(data: TomOption): string | false;


/**
     * Registers a new optgroup for options
     * to be bucketed into.
     *
     */
addOptionGroup(id: string, data: TomOption): void;


/**
     * Removes an existing option group.
     *
     */
removeOptionGroup(id: string): void;


/**
     * Clears all existing option groups.
     */
clearOptionGroups(): void;


/**
     * Updates an option available for selection. If
     * it is visible in the selected items or options
     * dropdown, it will be re-rendered automatically.
     *
     */
updateOption(value: string, data: TomOption): void;


/**
     * Removes a single option.
     *
     */
removeOption(value: string, silent?: boolean): void;


/**
     * Clears all options.
     */
clearOptions(): void;


/**
     * Removes a value from item and option caches
     *
     */
uncacheValue(value: string, remove_node?: boolean): void;


/**
     * Returns the dom element of the option
     * matching the given value.
     *
     */
getOption(value: null | string, create?: boolean): null | HTMLElement;


/**
     * Returns the dom element of the next or previous dom element of the same type
     * Note: adjacent options may not be adjacent DOM elements (optgroups)
     *
     */
getAdjacent(option: null | HTMLElement, direction: number, type?: string): HTMLElement | null;


/**
     * Returns the dom element of the item
     * matching the given value.
     *
     */
getItem(item: string | TomItem | null): null | TomItem;


/**
     * "Selects" multiple items at once. Adds them to the list
     * at the current caret position.
     *
     */
addItems(values: string | string[], silent?: boolean): void;


/**
     * "Selects" an item. Adds it to the list
     * at the current caret position.
     *
     */
addItem(value: string, silent?: boolean): void;


/**
     * Removes the selected item matching
     * the provided value.
     *
     */
removeItem(item?: string | TomItem | null, silent?: boolean): void;


/**
     * Invokes the `create` method provided in the
     * TomSelect options that should provide the data
     * for the new item, given the user input.
     *
     * Once this completes, it will be added
     * to the item list.
     *
     */
createItem(input?: null | string, triggerDropdown?: boolean, callback?: TomCreateCallback): boolean;


/**
     * Re-renders the selected item lists.
     */
refreshItems(): void;


/**
     * Updates all state-dependent attributes
     * and CSS classes.
     */
refreshState(): void;


/**
     * Update the `required` attribute of both input and control input.
     *
     * The `required` property needs to be activated on the control input
     * for the error to be displayed at the right place. `required` also
     * needs to be temporarily deactivated on the input since the input is
     * hidden and can't show errors.
     */
refreshValidityState(): void;


/**
     * Determines whether or not more items can be added
     * to the control without exceeding the user-defined maximum.
     *
     * @returns {boolean}
     */
isFull(): boolean;


/**
     * Refreshes the original <select> or <input>
     * element to reflect the current state.
     *
     */
updateOriginalInput(opts?: TomArgObject): void;


/**
     * Shows the autocomplete dropdown containing
     * the available options.
     */
open(): void;


/**
     * Closes the autocomplete dropdown menu.
     */
close(setTextboxValue?: boolean): void;


/**
     * Calculates and applies the appropriate
     * position of the dropdown if dropdownParent = 'body'.
     * Otherwise, position is determined by css
     */
positionDropdown(): void;


/**
     * Resets / clears all selected items
     * from the control.
     *
     */
clear(silent?: boolean): void;


/**
     * A helper method for inserting an element
     * at the current caret position.
     *
     */
insertAtCaret(el: HTMLElement): void;


/**
     * Removes the current selected item(s).
     *
     */
deleteSelection(e: KeyboardEvent): boolean;


/**
     * Selects the previous / next item (depending on the `direction` argument).
     *
     * > 0 - right
     * < 0 - left
     *
     */
advanceSelection(direction: number, e?: MouseEvent | KeyboardEvent): void;


/**
     * Get the last active item
     *
     */
getLastActive(direction?: number): any;


/**
     * Moves the caret to the specified index.
     *
     * The input must be moved by leaving it in place and moving the
     * siblings, due to the fact that focus cannot be restored once lost
     * on mobile webkit devices
     *
     */
setCaret(new_pos: number): void;


/**
     * Return list of item dom elements
     *
     */
controlChildren(): TomItem[];


/**
     * Disables user input on the control. Used while
     * items are being asynchronously created.
     */
lock(): void;


/**
     * Re-enables user input on the control.
     */
unlock(): void;


/**
     * Disables user input on the control completely.
     * While disabled, it cannot receive focus.
     */
disable(): void;


/**
     * Enables the control so that it can respond
     * to focus and user input.
     */
enable(): void;


/**
     * Completely destroys the control and
     * unbinds all event listeners so that it can
     * be garbage collected.
     */
destroy(): void;


/**
     * A helper method for rendering "item" and
     * "option" templates, given the data.
     *
     */
render(templateName: TomTemplateNames, data?: any): null | HTMLElement;


/**
     * _render() can be called directly when we know we don't want to hit the cache
     * return type could be null for some templates, we need https://github.com/microsoft/TypeScript/issues/33014
     */
_render(templateName: TomTemplateNames, data?: any): HTMLElement;


/**
     * Return the previously rendered item or option
     *
     */
rendered(templateName: TomTemplateNames, value: null | string): null | HTMLElement;


/**
     * Clears the render cache for a template. If
     * no template is given, clears all render
     * caches.
     *
     */
clearCache(templateName?: 'item' | 'option'): void;


/**
     * Determines whether or not to display the
     * create item prompt, given a user input.
     *
     */
canCreate(input: string): boolean;


/**
     * Wraps this.`method` so that `new_fn` can be invoked 'before', 'after', or 'instead' of the original method
     *
     * this.hook('instead','onKeyDown',function( arg1, arg2 ...){
     *
     * });
     */
hook(when: string, method: string, new_fn: any): void;


/** Describes a `GetInvoice` response. */
export interface GetInvoiceResponse {
    /**
     * Stores information about an invoice. You use the Invoices API to create and manage
     * invoices. For more information, see [Manage Invoices Using the Invoices API](https://developer.squareup.com/docs/invoices-api/overview).
     */
    invoice?: Invoice;
    /** Information about errors encountered during the request. */
    errors?: Error[];
}


(props: LinkProps) => (
      <LinkWrapper href={props.url} >
            {props.label}
      </LinkWrapper>


export interface LinkProps {
      url: string;
      label: string;
}


() => {
  beforeEach(() => {
    // Set up some mocked out file info before each test
    (path as any).__setBaseDir('./tests/tsconfig-test');
  });

  describe('new behaviour (tsConfigFile & tsConfig)', () => {
    it('should correctly read my-tsconfig.json', () => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'my-tsconfig.json',
        },
      });

      expect(result).toMatchObject({
        inlineSourceMap: true,
        inlineSources: true,
        target: ts.ScriptTarget.ES2015,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: true,
        jsx: ts.JsxEmit.React,
      });
    });

    it('should not read tsconfig.json', () => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'my-tsconfig.json',
        },
      });

      expect(result).not.toEqual({
        target: ts.ScriptTarget.ES2015,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: false,
        jsx: ts.JsxEmit.React,
      });
    });

    it('should not read inline tsconfig options', () => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'my-tsconfig.json',
        },
      });

      expect(result).not.toEqual({
        target: ts.ScriptTarget.ES5,
        jsx: ts.JsxEmit.React,
      });
    });

    it('should correctly resolve the "extends" directive', () => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'extends-tsconfig.json',
        },
      });

      expect(result).toEqual({
        inlineSourceMap: true,
        inlineSources: true,
        target: ts.ScriptTarget.ES2015,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: true,
        jsx: ts.JsxEmit.React,
      });
    });

    it('should correctly override any config in the "extends" directive', () => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'extends-with-overrides-tsconfig.json',
        },
      });

      expect(result).toEqual({
        inlineSourceMap: true,
        inlineSources: true,
        target: ts.ScriptTarget.ES5,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: true,
        jsx: ts.JsxEmit.React,
        noImplicitAny: true,
      });
    });
  });
}


() => {
    // Set up some mocked out file info before each test
    (path as any).__setBaseDir('./tests/tsconfig-test');
  }


() => {
    it('should correctly read my-tsconfig.json', () => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'my-tsconfig.json',
        },
      });

      expect(result).toMatchObject({
        inlineSourceMap: true,
        inlineSources: true,
        target: ts.ScriptTarget.ES2015,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: true,
        jsx: ts.JsxEmit.React,
      });
    });

    it('should not read tsconfig.json', () => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'my-tsconfig.json',
        },
      });

      expect(result).not.toEqual({
        target: ts.ScriptTarget.ES2015,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: false,
        jsx: ts.JsxEmit.React,
      });
    });

    it('should not read inline tsconfig options', () => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'my-tsconfig.json',
        },
      });

      expect(result).not.toEqual({
        target: ts.ScriptTarget.ES5,
        jsx: ts.JsxEmit.React,
      });
    });

    it('should correctly resolve the "extends" directive', () => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'extends-tsconfig.json',
        },
      });

      expect(result).toEqual({
        inlineSourceMap: true,
        inlineSources: true,
        target: ts.ScriptTarget.ES2015,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: true,
        jsx: ts.JsxEmit.React,
      });
    });

    it('should correctly override any config in the "extends" directive', () => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'extends-with-overrides-tsconfig.json',
        },
      });

      expect(result).toEqual({
        inlineSourceMap: true,
        inlineSources: true,
        target: ts.ScriptTarget.ES5,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: true,
        jsx: ts.JsxEmit.React,
        noImplicitAny: true,
      });
    });
  }


() => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'my-tsconfig.json',
        },
      });

      expect(result).toMatchObject({
        inlineSourceMap: true,
        inlineSources: true,
        target: ts.ScriptTarget.ES2015,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: true,
        jsx: ts.JsxEmit.React,
      });
    }


() => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'my-tsconfig.json',
        },
      });

      expect(result).not.toEqual({
        target: ts.ScriptTarget.ES2015,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: false,
        jsx: ts.JsxEmit.React,
      });
    }


() => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'my-tsconfig.json',
        },
      });

      expect(result).not.toEqual({
        target: ts.ScriptTarget.ES5,
        jsx: ts.JsxEmit.React,
      });
    }


() => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'extends-tsconfig.json',
        },
      });

      expect(result).toEqual({
        inlineSourceMap: true,
        inlineSources: true,
        target: ts.ScriptTarget.ES2015,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: true,
        jsx: ts.JsxEmit.React,
      });
    }


() => {
      const result = getTSConfig({
        'ts-jest': {
          tsConfigFile: 'extends-with-overrides-tsconfig.json',
        },
      });

      expect(result).toEqual({
        inlineSourceMap: true,
        inlineSources: true,
        target: ts.ScriptTarget.ES5,
        module: ts.ModuleKind.CommonJS,
        moduleResolution: ts.ModuleResolutionKind.NodeJs,
        noEmitOnError: true,
        jsx: ts.JsxEmit.React,
        noImplicitAny: true,
      });
    }


(items: string[]) => {
    const role = this.props.role;

    const options = items.map(i => ({
      label: i,
    }));

    const selectedOptions = (role.elasticsearch.cluster || []).map(k => ({ label: k }));

    return (
      <EuiFlexItem key={'clusterPrivs'}>
        <EuiComboBox
          options={options}
          selectedOptions={selectedOptions}
          onChange={this.onClusterPrivilegesChange}
          isDisabled={isReadOnlyRole(role)}
        />
      </EuiFlexItem>
    );
  }


i => ({
      label: i,
    })


k => ({ label: k })


(selectedPrivileges: any) => {
    this.props.onChange(selectedPrivileges.map((priv: any) => priv.label));
  }


(priv: any) => priv.label


export class ClusterPrivileges extends Component<Props, {}> {
  public render() {
    const clusterPrivileges = getClusterPrivileges();

    return <EuiFlexGroup>{this.buildComboBox(clusterPrivileges)}</EuiFlexGroup>;
  }

  public buildComboBox = (items: string[]) => {
    const role = this.props.role;

    const options = items.map(i => ({
      label: i,
    }));

    const selectedOptions = (role.elasticsearch.cluster || []).map(k => ({ label: k }));

    return (
      <EuiFlexItem key={'clusterPrivs'}>
        <EuiComboBox
          options={options}
          selectedOptions={selectedOptions}
          onChange={this.onClusterPrivilegesChange}
          isDisabled={isReadOnlyRole(role)}
        />
      </EuiFlexItem>
    );
  };

  public onClusterPrivilegesChange = (selectedPrivileges: any) => {
    this.props.onChange(selectedPrivileges.map((priv: any) => priv.label));
  };
}


interface Props {
  role: Role;
  onChange: (privs: string[]) => void;
}


public render() {
    const clusterPrivileges = getClusterPrivileges();

    return <EuiFlexGroup>{this.buildComboBox(clusterPrivileges)}</EuiFlexGroup>;
  }


isReadOnlyRole(role)


export interface Request {
			client: Clients;
		}


res => res.json()


data => {
        this.claimRequestData = data["resource"];
        console.log(this.claimRequestData)
        if (this.claimRequestData[0].SOC_GUID === null) {
          this.claimFor = 'customer'
          this.storeCustomers.forEach(element => {
            if (element.CUSTOMER_GUID === this.claimRequestData[0].CUSTOMER_GUID) {
              this.Customer_Lookup_ngModel = element.NAME
            }
          });
        }
        else {
          this.claimFor = 'project'
          this.storeProjects.forEach(element => {
            if (element.SOC_GUID === this.claimRequestData[0].SOC_GUID) {
              this.Project_Lookup_ngModel = element.project_name
              this.Travel_SOC_No_ngModel = element.soc
            }
          });
        }
        this.Travel_Date_ngModel = this.claimRequestData[0].TRAVEL_DATE;
        this.Travel_From_ngModel = this.claimRequestData[0].FROM;
        this.Travel_Destination_ngModel = this.claimRequestData[0].DESTINATION;
        this.Travel_Distance_ngModel = this.claimRequestData[0].DISTANCE_KM;
        //this.travelAmount = this.claimRequestData[0].MILEAGE_AMOUNT
        this.Travel_Amount_ngModel = this.claimRequestData[0].CLAIM_AMOUNT;
        this.Travel_Description_ngModel = this.claimRequestData[0].DESCRIPTION;

        this.vehicles.forEach(element => {
          if (element.MILEAGE_GUID === this.claimRequestData[0].MILEAGE_GUID) {
            this.Travel_Mode_ngModel = element.CATEGORY
          }
        });
        console.table(this.claimRequestData)
        console.log(this.claimRequestData[0].SOC_GUID)
        console.log(this.claimRequestData[0].MILEAGE_GUID)
        console.log(this.claimRequestData[0].DESCRIPTION)
      }


element => {
            if (element.CUSTOMER_GUID === this.claimRequestData[0].CUSTOMER_GUID) {
              this.Customer_Lookup_ngModel = element.NAME
            }
          }


element => {
            if (element.SOC_GUID === this.claimRequestData[0].SOC_GUID) {
              this.Project_Lookup_ngModel = element.project_name
              this.Travel_SOC_No_ngModel = element.soc
            }
          }


element => {
          if (element.MILEAGE_GUID === this.claimRequestData[0].MILEAGE_GUID) {
            this.Travel_Mode_ngModel = element.CATEGORY
          }
        }


data => {
      this.storeProjects=  this.projects = data["resource"];
        console.table(this.projects)
      }


data => {
        this.storeCustomers = this.customers = data["resource"];
         console.table(this.projects)
      }


data => {
        this.vehicles = data["resource"];
        console.table(this.vehicles);
      }


data => {
      let temp = data["rows"][0]["elements"][0];
      // console.table(data)
      if (temp["distance"] != null) {
        let DistKm: string = data["rows"][0]["elements"][0]["distance"]["text"];
        // console.log(DistKm)
        DistKm = DistKm.replace(',', '')
        this.Travel_Distance_ngModel = DistKm.substring(0, DistKm.length - 2)
      }
      else
        alert('Please select Valid Origin & Destination Places');

    }


data => {
      this.currentItems = data["predictions"];
      console.table(this.currentItems);
    }


(item) => {
      for (let key in params) {
        let field = item[key];
        if (typeof field == 'string' && field.toLowerCase().indexOf(params[key].toLowerCase()) >= 0) {
          return item;
        } else if (field == params[key]) {
          return item;
        }
      }
      return null;
    }


claimRefdata => {
        if (claimRefdata["resource"][0] == null) {
          let claimReqRef: ClaimRefMain_Model = new ClaimRefMain_Model();
          claimReqRef.CLAIM_REF_GUID = UUID.UUID();
          claimReqRef.USER_GUID = this.userGUID;
          claimReqRef.TENANT_GUID = tenantGUID;
          claimReqRef.REF_NO = this.userGUID + '/' + month + '/' + year;
          claimReqRef.MONTH = month;
          claimReqRef.YEAR = year;
          claimReqRef.CREATION_TS = new Date().toISOString();
          claimReqRef.UPDATE_TS = new Date().toISOString();

          this.api.postData('main_claim_ref', claimReqRef.toJson(true)).subscribe((response) => {
            var postClaimRef = response.json();
            claimRefGUID = postClaimRef["resource"][0].CLAIM_REF_GUID;

            let claimReqMainRef: ClaimReqMain_Model = new ClaimReqMain_Model();
            claimReqMainRef.CLAIM_REQUEST_GUID = UUID.UUID();
            claimReqMainRef.TENANT_GUID = tenantGUID;
            claimReqMainRef.CLAIM_REF_GUID = claimRefGUID;
            claimReqMainRef.MILEAGE_GUID = this.VehicleId;
            claimReqMainRef.CLAIM_TYPE_GUID = '58c59b56-289e-31a2-f708-138e81a9c823';
            claimReqMainRef.TRAVEL_DATE = value.travel_date;
            claimReqMainRef.START_TS = value.start_DT;
            claimReqMainRef.END_TS = value.end_DT;
            claimReqMainRef.DESCRIPTION = value.description;
            claimReqMainRef.MILEAGE_AMOUNT = this.Travel_Amount_ngModel
            claimReqMainRef.CLAIM_AMOUNT = this.Travel_Amount_ngModel
            claimReqMainRef.CREATION_TS = new Date().toISOString();
            claimReqMainRef.UPDATE_TS = new Date().toISOString();
            claimReqMainRef.FROM = this.Travel_From_ngModel;
            claimReqMainRef.DESTINATION = this.Travel_Destination_ngModel;
            claimReqMainRef.DISTANCE_KM = this.Travel_Distance_ngModel;
            claimReqMainRef.ASSIGNED_TO = this.assignedTo;
            claimReqMainRef.PROFILE_LEVEL = this.profileLevel;
            claimReqMainRef.PROFILE_JSON = this.profileJSON;
            claimReqMainRef.STATUS = 'Pending';
            claimReqMainRef.STAGE = this.stage;
           // claimReqMainRef.SOC_GUID = this.Travel_SOC_No_ngModel;
           if(this.isCustomer){
            claimReqMainRef.CUSTOMER_GUID = this.Customer_GUID ;
          }
          else{
            claimReqMainRef.SOC_GUID = this.Soc_GUID;
          }
          // claimReqMainRef.CUSTOMER_GUID = this.isCustomer ? this.Customer_GUID : this.Soc_GUID;
          // claimReqMainRef.SOC_GUID = this.isCustomer ? this.Customer_GUID : this.Soc_GUID;

            this.api.postData('main_claim_request', claimReqMainRef.toJson(true)).subscribe((response) => {
              var postClaimMain = response.json();
              this.ClaimRequestMain = postClaimMain["resource"][0].CLAIM_REQUEST_GUID;
              this.MainClaimSaved = true;
              console.table( claimReqMainRef);
              alert('Claim Has Registered.')
            })
          })
        }
        else {
          claimRefGUID = claimRefdata["resource"][0].CLAIM_REF_GUID;

          let claimReqMainRef: ClaimReqMain_Model = new ClaimReqMain_Model();
          claimReqMainRef.CLAIM_REQUEST_GUID = UUID.UUID();
          claimReqMainRef.TENANT_GUID = tenantGUID;
          claimReqMainRef.CLAIM_REF_GUID = claimRefGUID;
          claimReqMainRef.MILEAGE_GUID = this.VehicleId;
          claimReqMainRef.CLAIM_TYPE_GUID = '58c59b56-289e-31a2-f708-138e81a9c823';
          claimReqMainRef.TRAVEL_DATE = value.travel_date;
          claimReqMainRef.START_TS = value.start_DT;
          claimReqMainRef.END_TS = value.end_DT;
          claimReqMainRef.DESCRIPTION = value.description;
          claimReqMainRef.MILEAGE_AMOUNT = this.Travel_Amount_ngModel;
          claimReqMainRef.CLAIM_AMOUNT = this.Travel_Amount_ngModel;
          claimReqMainRef.CREATION_TS = new Date().toISOString();
          claimReqMainRef.UPDATE_TS = new Date().toISOString();
          claimReqMainRef.FROM = this.Travel_From_ngModel;
          claimReqMainRef.DESTINATION = this.Travel_Destination_ngModel;
          claimReqMainRef.ASSIGNED_TO = this.assignedTo;
          claimReqMainRef.DISTANCE_KM = this.Travel_Distance_ngModel;
          claimReqMainRef.PROFILE_LEVEL = this.profileLevel;
          claimReqMainRef.PROFILE_JSON = this.profileJSON;
          claimReqMainRef.STATUS = 'Pending';
          //claimReqMainRef.STATUS = 'Pending';
          claimReqMainRef.STAGE = this.stage;
          //claimReqMainRef.SOC_GUID = this.Travel_SOC_No_ngModel;
          if(this.isCustomer){
            claimReqMainRef.CUSTOMER_GUID = this.Customer_GUID ;
          }
          else{
            claimReqMainRef.SOC_GUID = this.Soc_GUID;
          }
        this.api.postData('main_claim_request', claimReqMainRef.toJson(true)).subscribe((response) => {
            var postClaimMain = response.json();
            this.ClaimRequestMain = postClaimMain["resource"][0].CLAIM_REQUEST_GUID;

            this.MainClaimSaved = true;
            alert('Claim Has Registered.')
          })
        }

      }


(response) => {
            var postClaimRef = response.json();
            claimRefGUID = postClaimRef["resource"][0].CLAIM_REF_GUID;

            let claimReqMainRef: ClaimReqMain_Model = new ClaimReqMain_Model();
            claimReqMainRef.CLAIM_REQUEST_GUID = UUID.UUID();
            claimReqMainRef.TENANT_GUID = tenantGUID;
            claimReqMainRef.CLAIM_REF_GUID = claimRefGUID;
            claimReqMainRef.MILEAGE_GUID = this.VehicleId;
            claimReqMainRef.CLAIM_TYPE_GUID = '58c59b56-289e-31a2-f708-138e81a9c823';
            claimReqMainRef.TRAVEL_DATE = value.travel_date;
            claimReqMainRef.START_TS = value.start_DT;
            claimReqMainRef.END_TS = value.end_DT;
            claimReqMainRef.DESCRIPTION = value.description;
            claimReqMainRef.MILEAGE_AMOUNT = this.Travel_Amount_ngModel
            claimReqMainRef.CLAIM_AMOUNT = this.Travel_Amount_ngModel
            claimReqMainRef.CREATION_TS = new Date().toISOString();
            claimReqMainRef.UPDATE_TS = new Date().toISOString();
            claimReqMainRef.FROM = this.Travel_From_ngModel;
            claimReqMainRef.DESTINATION = this.Travel_Destination_ngModel;
            claimReqMainRef.DISTANCE_KM = this.Travel_Distance_ngModel;
            claimReqMainRef.ASSIGNED_TO = this.assignedTo;
            claimReqMainRef.PROFILE_LEVEL = this.profileLevel;
            claimReqMainRef.PROFILE_JSON = this.profileJSON;
            claimReqMainRef.STATUS = 'Pending';
            claimReqMainRef.STAGE = this.stage;
           // claimReqMainRef.SOC_GUID = this.Travel_SOC_No_ngModel;
           if(this.isCustomer){
            claimReqMainRef.CUSTOMER_GUID = this.Customer_GUID ;
          }
          else{
            claimReqMainRef.SOC_GUID = this.Soc_GUID;
          }
          // claimReqMainRef.CUSTOMER_GUID = this.isCustomer ? this.Customer_GUID : this.Soc_GUID;
          // claimReqMainRef.SOC_GUID = this.isCustomer ? this.Customer_GUID : this.Soc_GUID;

            this.api.postData('main_claim_request', claimReqMainRef.toJson(true)).subscribe((response) => {
              var postClaimMain = response.json();
              this.ClaimRequestMain = postClaimMain["resource"][0].CLAIM_REQUEST_GUID;
              this.MainClaimSaved = true;
              console.table( claimReqMainRef);
              alert('Claim Has Registered.')
            })
          }


(response) => {
              var postClaimMain = response.json();
              this.ClaimRequestMain = postClaimMain["resource"][0].CLAIM_REQUEST_GUID;
              this.MainClaimSaved = true;
              console.table( claimReqMainRef);
              alert('Claim Has Registered.')
            }


(response) => {
            var postClaimMain = response.json();
            this.ClaimRequestMain = postClaimMain["resource"][0].CLAIM_REQUEST_GUID;

            this.MainClaimSaved = true;
            alert('Claim Has Registered.')
          }


data => {
        // this.result= data["resource"];
        alert(JSON.stringify(data));
      }


(response) => response.json()


data => {
      this.profileJSON = JSON.stringify(data);
      //levels: any[];
       let levels: any[] = data.profile.levels.level
      console.table(levels)
      levels.forEach(element => {
        if (element['-id'] == '1') {
          this.profileLevel = '1';
          if (element['approver']['-directManager'] === '1') {
            this.http
              .get(Services.getUrl('user_info', 'filter=USER_GUID=' + this.userGUID))
              .map(res => res.json())
              .subscribe(data => {
                let userInfo: any[] = data["resource"]
                userInfo.forEach(userElm => {
                  this.assignedTo = userElm.MANAGER_USER_GUID
                  this.http
                    .get(Services.getUrl('user_info', 'filter=USER_GUID=' + userElm.MANAGER_USER_GUID))
                    .map(res => res.json())
                    .subscribe(data => {
                      let userInfo: any[] = data["resource"]
                      userInfo.forEach(approverElm => {
                        this.stage = approverElm.DEPT_GUID
                      });
                    });
                });
                // console.log('Direct Manager Exists')
              });
            // console.log('Direct Manager ' + element['approver']['-directManager'])
            let varf: any[]= element['conditions']['condition']
            varf.forEach(condElement => {
              if (condElement['-status'] === 'approved') {
                console.log('Next Level ' + condElement['nextlevel']['#text'])
              }
              console.log('Status ' + condElement['-status'])
            });
          }
          else {
            this.assignedTo = element['approver']['#text']
            this.http
              .get(Services.getUrl('user_info', 'filter=USER_GUID=' + this.assignedTo))
              .map(res => res.json())
              .subscribe(data => {
                let userInfo: any[] = data["resource"]
                userInfo.forEach(approverElm => {
                  this.stage = approverElm.DEPT_GUID
                });
              });

          }
        }
      });
    }


element => {
        if (element['-id'] == '1') {
          this.profileLevel = '1';
          if (element['approver']['-directManager'] === '1') {
            this.http
              .get(Services.getUrl('user_info', 'filter=USER_GUID=' + this.userGUID))
              .map(res => res.json())
              .subscribe(data => {
                let userInfo: any[] = data["resource"]
                userInfo.forEach(userElm => {
                  this.assignedTo = userElm.MANAGER_USER_GUID
                  this.http
                    .get(Services.getUrl('user_info', 'filter=USER_GUID=' + userElm.MANAGER_USER_GUID))
                    .map(res => res.json())
                    .subscribe(data => {
                      let userInfo: any[] = data["resource"]
                      userInfo.forEach(approverElm => {
                        this.stage = approverElm.DEPT_GUID
                      });
                    });
                });
                // console.log('Direct Manager Exists')
              });
            // console.log('Direct Manager ' + element['approver']['-directManager'])
            let varf: any[]= element['conditions']['condition']
            varf.forEach(condElement => {
              if (condElement['-status'] === 'approved') {
                console.log('Next Level ' + condElement['nextlevel']['#text'])
              }
              console.log('Status ' + condElement['-status'])
            });
          }
          else {
            this.assignedTo = element['approver']['#text']
            this.http
              .get(Services.getUrl('user_info', 'filter=USER_GUID=' + this.assignedTo))
              .map(res => res.json())
              .subscribe(data => {
                let userInfo: any[] = data["resource"]
                userInfo.forEach(approverElm => {
                  this.stage = approverElm.DEPT_GUID
                });
              });

          }
        }
      }


data => {
                let userInfo: any[] = data["resource"]
                userInfo.forEach(userElm => {
                  this.assignedTo = userElm.MANAGER_USER_GUID
                  this.http
                    .get(Services.getUrl('user_info', 'filter=USER_GUID=' + userElm.MANAGER_USER_GUID))
                    .map(res => res.json())
                    .subscribe(data => {
                      let userInfo: any[] = data["resource"]
                      userInfo.forEach(approverElm => {
                        this.stage = approverElm.DEPT_GUID
                      });
                    });
                });
                // console.log('Direct Manager Exists')
              }


userElm => {
                  this.assignedTo = userElm.MANAGER_USER_GUID
                  this.http
                    .get(Services.getUrl('user_info', 'filter=USER_GUID=' + userElm.MANAGER_USER_GUID))
                    .map(res => res.json())
                    .subscribe(data => {
                      let userInfo: any[] = data["resource"]
                      userInfo.forEach(approverElm => {
                        this.stage = approverElm.DEPT_GUID
                      });
                    });
                }


data => {
                      let userInfo: any[] = data["resource"]
                      userInfo.forEach(approverElm => {
                        this.stage = approverElm.DEPT_GUID
                      });
                    }


approverElm => {
                        this.stage = approverElm.DEPT_GUID
                      }


condElement => {
              if (condElement['-status'] === 'approved') {
                console.log('Next Level ' + condElement['nextlevel']['#text'])
              }
              console.log('Status ' + condElement['-status'])
            }


data => {
                let userInfo: any[] = data["resource"]
                userInfo.forEach(approverElm => {
                  this.stage = approverElm.DEPT_GUID
                });
              }


approverElm => {
                  this.stage = approverElm.DEPT_GUID
                }


ngOnInit(): void {
     this.userGUID = localStorage.getItem('g_USER_GUID');
     this.isFormEdit = this.navParams.get('isFormEdit');
      this.claimRequestGUID = this.navParams.get('cr_GUID'); //dynamic
     //this.claimRequestGUID = 'aa124ed8-5c2d-4c39-d3bd-066857c45617';
     if (this.isFormEdit)
       this.GetDataforEdit();
   }


GetDataforEdit() {
    this.http
      .get(Services.getUrl('main_claim_request', 'filter=CLAIM_REQUEST_GUID=' + this.claimRequestGUID))
      .map(res => res.json())
      .subscribe(data => {
        this.claimRequestData = data["resource"];
        console.log(this.claimRequestData)
        if (this.claimRequestData[0].SOC_GUID === null) {
          this.claimFor = 'customer'
          this.storeCustomers.forEach(element => {
            if (element.CUSTOMER_GUID === this.claimRequestData[0].CUSTOMER_GUID) {
              this.Customer_Lookup_ngModel = element.NAME
            }
          });
        }
        else {
          this.claimFor = 'project'
          this.storeProjects.forEach(element => {
            if (element.SOC_GUID === this.claimRequestData[0].SOC_GUID) {
              this.Project_Lookup_ngModel = element.project_name
              this.Travel_SOC_No_ngModel = element.soc
            }
          });
        }
        this.Travel_Date_ngModel = this.claimRequestData[0].TRAVEL_DATE;
        this.Travel_From_ngModel = this.claimRequestData[0].FROM;
        this.Travel_Destination_ngModel = this.claimRequestData[0].DESTINATION;
        this.Travel_Distance_ngModel = this.claimRequestData[0].DISTANCE_KM;
        //this.travelAmount = this.claimRequestData[0].MILEAGE_AMOUNT
        this.Travel_Amount_ngModel = this.claimRequestData[0].CLAIM_AMOUNT;
        this.Travel_Description_ngModel = this.claimRequestData[0].DESCRIPTION;

        this.vehicles.forEach(element => {
          if (element.MILEAGE_GUID === this.claimRequestData[0].MILEAGE_GUID) {
            this.Travel_Mode_ngModel = element.CATEGORY
          }
        });
        console.table(this.claimRequestData)
        console.log(this.claimRequestData[0].SOC_GUID)
        console.log(this.claimRequestData[0].MILEAGE_GUID)
        console.log(this.claimRequestData[0].DESCRIPTION)
      }
      );
  }


GetSocNo(item: any){
    this.Travel_SOC_No_ngModel = item.soc;
    this.Project_Lookup_ngModel = item.project_name;
    this.Soc_GUID = item.SOC_GUID;
    this.CloseProjectLookup();
  }


GetCustomer(guid: any, name: any) {
    this.Customer_Lookup_ngModel = name;
    this.Customer_GUID = guid;
    this.CloseCustomerLookup();
  }


public translateToEnglish() {
    this.translate.use('en');
    this.translateToMalayClicked = !this.translateToMalayClicked;
    this.translateToEnglishClicked = !this.translateToEnglishClicked;
  }


public translateToMalay() {
    this.translate.use('ms');
    this.translateToEnglishClicked = !this.translateToEnglishClicked;
    this.translateToMalayClicked = !this.translateToMalayClicked;
  }


//---------------------Language module end---------------------//
claimForChanged() {
    // console.log(this.claimFor)
    if (this.claimFor == 'customer') this.isCustomer = true;
    else this.isCustomer = false;
  }


LoadProjects() {
    this.http
      .get(Services.getUrl('soc_registration'))
      .map(res => res.json())
      .subscribe(data => {
      this.storeProjects=  this.projects = data["resource"];
        console.table(this.projects)
      }
      );
  }


LoadCustomers() {
    this.http
      .get(Services.getUrl('main_customer'))
      .map(res => res.json())
      .subscribe(data => {
        this.storeCustomers = this.customers = data["resource"];
         console.table(this.projects)
      }
      );
  }


//console.log(TenantGUID);
LoadVehicles() {
    console.log(this.TenantGUID);
    this.http
      .get(Services.getUrl('main_mileage', 'filter=TENANT_GUID=' + this.TenantGUID))
      .map(res => res.json())
      .subscribe(data => {
        this.vehicles = data["resource"];
        console.table(this.vehicles);
      }
      );
  }


GetDistance() {
    var origin = this.Travel_From_ngModel;
    var destination;
    var url = 'http://api.zen.com.my/api/v2/google/distancematrix/json?destinations=place_id:' + this.DestinationPlaceID + '&origins=place_id:' + this.OriginPlaceID + '&api_key=' + constants.DREAMFACTORY_API_KEY;
    this.http.get(url).map(res => res.json()).subscribe(data => {
      let temp = data["rows"][0]["elements"][0];
      // console.table(data)
      if (temp["distance"] != null) {
        let DistKm: string = data["rows"][0]["elements"][0]["distance"]["text"];
        // console.log(DistKm)
        DistKm = DistKm.replace(',', '')
        this.Travel_Distance_ngModel = DistKm.substring(0, DistKm.length - 2)
      }
      else
        alert('Please select Valid Origin & Destination Places');

    });
  }


public CloseTravelClick() {
    this.AddToLookupClicked = false;
    this.AddTravelClicked = false;
  }


public CloseLookupClick() {
    if (this.AddLookupClicked == true) {
      this.AddLookupClicked = false;
    }
    if (this.AddToLookupClicked == true) {
      this.AddToLookupClicked = false;
    }
    let origin = this.Travel_From_ngModel;
    let destination = this.Travel_Distance_ngModel;
    if (origin != '' && destination != '') {
      this.GetDistance();
      // this.Travel_Mode_ngModel = this.vehicleCategory ;
    }
  }


public CloseProjectLookup() {
    if (this.ProjectLookupClicked == true) {
      this.ProjectLookupClicked = false;
    }
  }


public CloseCustomerLookup() {
    if (this.CustomerLookupClicked == true) {
      this.CustomerLookupClicked = false;
    }
  }


public AddLookupClick() {
    this.AddLookupClicked = true;
    this.currentItems = null;
  }


public AddToLookupClick() {
    this.AddLookupClicked = true;
    this.AddToLookupClicked = true;
    this.currentItems = null;
  }


public ProjectLookup() {
    this.ProjectLookupClicked = true;

    // this.projects = null;
  }


public CustomerLookup() {
    this.CustomerLookupClicked = true;
    // this.projects = null;
  }


openItem(item: any) {
    if (this.AddToLookupClicked) {
      this.Travel_Destination_ngModel = item.description;
      this.DestinationPlaceID = item.place_id
    }
    else {
      this.Travel_From_ngModel = item.description;
      this.OriginPlaceID = item.place_id;
    }
    this.CloseLookupClick();
  }


searchLocation(searchLocationString: any) {
    let val = searchLocationString.target.value;
    val = val.replace(/ /g, '');
    if (!val || !val.trim()) {
      this.currentItems = [];
      return;
    }
    var url = 'http://api.zen.com.my/api/v2/google/place/autocomplete/json?json?radius=50000&input=' + val + '&api_key=' + constants.DREAMFACTORY_API_KEY;
    this.http.get(url).map(res => res.json()).subscribe(data => {
      this.currentItems = data["predictions"];
      console.table(this.currentItems);
    });
  }


//   onSearchInput(ev: any) {
//     let val = ev.target.value;
//     if (val && val.trim() != '') {
//      this.projects = this.projects.filter((item) => {
//        console.log(item);
//        return ((item.FULLNAME.toLowerCase().indexOf(val.toLowerCase()) > -1)
//        || ((item.MONTH.toString().toLowerCase().indexOf(val.toLowerCase()) > -1)
//        || (item.YEAR.toString().toLowerCase().indexOf(val.toLowerCase()) > -1))
//        || (item.CLAIM_AMOUNT.toString().toLowerCase().indexOf(val.toLowerCase()) > -1
//      )
//      );
//      })
//    }
//    else
//    {
//     //  this.BindData();
//     return null;
//    }
// }
// Search project start:
searchProject(searchString: any) {
    let val = searchString.target.value;
    if (!val || !val.trim()) {
      this.projects = this.storeProjects;
      return;
    }
   this.projects=  this.filterProjects({
    project_name: val
    });
  }


filterProjects(params?: any) {
    if (!params) {
      return this.storeProjects;
    }

    return this.projects.filter((item) => {
      for (let key in params) {
        let field = item[key];
        if (typeof field == 'string' && field.toLowerCase().indexOf(params[key].toLowerCase()) >= 0) {
          return item;
        } else if (field == params[key]) {
          return item;
        }
      }
      return null;
    });
  }