() => {
    const mockCallback = jest.fn();
    const mockObj = { name: 'John', age: 20 };
    const elm = document.createElement('input');
    elm.className = 'custom-class';
    div.appendChild(elm);

    service = new BindingService({ variable: mockObj, property: 'name' });
    service.bind(elm, 'value', 'change', mockCallback);
    elm.value = 'Jane';
    const mockEvent = new CustomEvent('change', { bubbles: true, detail: { target: { value: 'Jane' } } });
    elm.dispatchEvent(mockEvent);

    expect(service.property).toBe('name');
    expect(mockObj.name).toBe('Jane');
    expect(mockCallback).toHaveBeenCalled();
  }


() => {
    const mockCallback = jest.fn();
    const mockObj = { name: 'John', age: 20 };
    const elm = document.createElement('input');
    elm.className = 'custom-class';
    div.appendChild(elm);

    service = new BindingService({ variable: mockObj, property: 'invalidProperty' });
    service.bind(elm, 'value', 'change', mockCallback);
    elm.value = 'Jane';
    const mockEvent = new CustomEvent('change', { bubbles: true, detail: { target: { value: 'Jane' } } });
    elm.dispatchEvent(mockEvent);

    expect(service.property).toBe('invalidProperty');
    expect(mockObj.name).toBe('John');
    expect(mockCallback).toHaveBeenCalled();
  }


() => {
    const mockCallback = jest.fn();
    const mockObj = { name: 'John', age: 20 };
    const elm = document.createElement('input');
    elm.className = 'custom-class';
    div.appendChild(elm);

    service = new BindingService({ variable: mockObj, property: 'name' });
    service.bind(elm, 'value', 'change', mockCallback);
    mockObj.name = 'Jane';

    expect(service.property).toBe('name');
    expect(elm.value).toBe('Jane');
  }


() => {
    const mockElm = { addEventListener: jest.fn(), removeEventListener: jest.fn() } as unknown as HTMLElement;
    const mockCallback = jest.fn();
    const removeEventSpy = jest.spyOn(mockElm, 'removeEventListener');
    const mockObj = { name: 'John', age: 20 };
    const elm = document.createElement('input');
    div.appendChild(elm);

    service = new BindingService({ variable: mockObj, property: 'name' });
    service.bind(mockElm, 'value', 'keyup');
    service.unbind(mockElm, 'click', mockCallback, false, service.boundedEventWithListeners[0].uid);

    expect(service.property).toBe('name');
    expect(removeEventSpy).toHaveBeenCalledWith('click', mockCallback, false);
  }


() => {
    const mockElm = { addEventListener: jest.fn(), removeEventListener: jest.fn() } as unknown as HTMLElement;
    const removeEventSpy = jest.spyOn(mockElm, 'removeEventListener');
    const mockObj = { name: 'John', age: 20 };
    const elm = document.createElement('input');
    div.appendChild(elm);

    service = new BindingService({ variable: mockObj, property: 'name' });
    service.bind(mockElm, 'value', 'keyup');
    service.unbindAll();

    expect(service.property).toBe('name');
    expect(removeEventSpy).toHaveBeenCalledWith('keyup', expect.toBeFunction(), undefined);
  }


() => {
  test('turns a regular string into camelCase', () => {
    let testString = "a bunch of words";
    let camelized = camelize(testString);
    let expected = "aBunchOfWords";
    expect(camelized).toBe(expected);
  });

  test('works with numbers', () => {
    let testString = "2 bunches of words and 3 numbers";
    let camelized = camelize(testString);
    let expected = "2BunchesOfWordsAnd3Numbers" ;
    expect(camelized).toBe(expected);
  });

  test('strips out special characters (excluding underscore)' , () => {
    let testString = "UPC/EAN/GTIN";
    let camelized = camelize(testString);
    let expected = "upcEanGtin" ;
    expect(camelized).toBe(expected);
  })
}


() => {
    let testString = "a bunch of words";
    let camelized = camelize(testString);
    let expected = "aBunchOfWords";
    expect(camelized).toBe(expected);
  }


() => {
    let testString = "2 bunches of words and 3 numbers";
    let camelized = camelize(testString);
    let expected = "2BunchesOfWordsAnd3Numbers" ;
    expect(camelized).toBe(expected);
  }


() => {
    let testString = "UPC/EAN/GTIN";
    let camelized = camelize(testString);
    let expected = "upcEanGtin" ;
    expect(camelized).toBe(expected);
  }


() => {
  test("returns a sheet's headers as an object with camelized names as keys and indices as values", () => {
    let sheetData = [['header one', 'header 2', 'a very long header three', 'item inventory', 'quantity ordered']];
    let headerMap = reduceHeaders(sheetData);
    expect(headerMap).toHaveProperty('header2');
    expect(headerMap).toHaveProperty(["itemInventory"], 3);
  });
}


() => {
    let sheetData = [['header one', 'header 2', 'a very long header three', 'item inventory', 'quantity ordered']];
    let headerMap = reduceHeaders(sheetData);
    expect(headerMap).toHaveProperty('header2');
    expect(headerMap).toHaveProperty(["itemInventory"], 3);
  }


() => {
  test("returns an array of objects that contain properties for headerName and index", () => {
    let sheetData = [['header one', 'header 2', 'a very long header three', 'item inventory', 'quantity ordered']];
    let headerMap = mapHeaders(sheetData);
    expect(headerMap.length).toBe(sheetData[0].length);
    expect(headerMap[0]).toHaveProperty('headerName');
    expect(headerMap[3]).toHaveProperty('headerIndex');
    expect(headerMap[4]).toHaveProperty(['headerIndex'], 4)
  });
}


() => {
    let sheetData = [['header one', 'header 2', 'a very long header three', 'item inventory', 'quantity ordered']];
    let headerMap = mapHeaders(sheetData);
    expect(headerMap.length).toBe(sheetData[0].length);
    expect(headerMap[0]).toHaveProperty('headerName');
    expect(headerMap[3]).toHaveProperty('headerIndex');
    expect(headerMap[4]).toHaveProperty(['headerIndex'], 4)
  }


() => {
  test("returns the index of a camelized column name", () => {
    let sheetData = [['header one', 'header 2', 'a very long header three', 'item inventory', 'quantity ordered']];
    let headerMap = mapHeaders(sheetData);
    let firstIndex = getIndexByHeader("headerOne", headerMap)
    let itemIndex = getIndexByHeader('itemInventory', headerMap)
    expect(firstIndex).toBe(0)
    expect(itemIndex).toBe(3)
  })
}


() => {
    let sheetData = [['header one', 'header 2', 'a very long header three', 'item inventory', 'quantity ordered']];
    let headerMap = mapHeaders(sheetData);
    let firstIndex = getIndexByHeader("headerOne", headerMap)
    let itemIndex = getIndexByHeader('itemInventory', headerMap)
    expect(firstIndex).toBe(0)
    expect(itemIndex).toBe(3)
  }


() => {
  test('Removes M US from size string', () => {
    let sizeWithoutDesc = '5 M US'
    let finalSize = cleanSize(sizeWithoutDesc)
    expect(finalSize).toBe('5')
  })
  test('Removes all extra words', () => {
    let sizeWithDesc = '5.5 M US Little Kid'
    let finalSize = cleanSize(sizeWithDesc)
    expect(finalSize).toBe('5.5')
  })
  test("Returns size if there are no extra words", () => {
    let sizeWithoutExtra = '5'
    let finalSize = cleanSize(sizeWithoutExtra)
    expect(finalSize).toBe('5')
  })
}


() => {
    let sizeWithoutDesc = '5 M US'
    let finalSize = cleanSize(sizeWithoutDesc)
    expect(finalSize).toBe('5')
  }


() => {
    let sizeWithDesc = '5.5 M US Little Kid'
    let finalSize = cleanSize(sizeWithDesc)
    expect(finalSize).toBe('5.5')
  }


() => {
    let sizeWithoutExtra = '5'
    let finalSize = cleanSize(sizeWithoutExtra)
    expect(finalSize).toBe('5')
  }


() => {
  let size10 = '14598-b_10'
  let above10 = '14598-b_12.5'
  let under10 = '14598-b_7.5'
  test('returns sku when size 10 or over', () => {
    let padded = getPaddedSku(size10)
    expect(padded).toBe('14598-b_10')
    padded = getPaddedSku(above10)
    expect(padded).toBe('14598-b_12.5')
  })
  test('returns padded sku (extra 0 before the size) for sizes under 10', () => {
    let padded = getPaddedSku(under10)
    expect(padded).toBe('14598-b_07.5')
  })
}


() => {
    let padded = getPaddedSku(size10)
    expect(padded).toBe('14598-b_10')
    padded = getPaddedSku(above10)
    expect(padded).toBe('14598-b_12.5')
  }


() => {
    let padded = getPaddedSku(under10)
    expect(padded).toBe('14598-b_07.5')
  }


() => {
  let sku = '14598-b_5'
  test('returns an array with style and size', () => {
    let style = splitSku(sku)[0]
    let size = splitSku(sku)[1]
    expect(style).toBe('14598-b')
    expect(size).toBe('5')
  })
}


() => {
    let style = splitSku(sku)[0]
    let size = splitSku(sku)[1]
    expect(style).toBe('14598-b')
    expect(size).toBe('5')
  }


() => {

  test('fills rows with blanks to meet max', () => {
    const data: any[][] = [
      [1, 2, "3"],
      [1]
    ]
    const result = padAllRows(data)
    const expected = [
      [1, 2, "3"],
      [1, '', '']
    ]
    expect(result).toEqual(expected)
  })
}


() => {
    const data: any[][] = [
      [1, 2, "3"],
      [1]
    ]
    const result = padAllRows(data)
    const expected = [
      [1, 2, "3"],
      [1, '', '']
    ]
    expect(result).toEqual(expected)
  }


() => {
  it("finds the first row without blanks", () => {
    const data = [
      ['a', ''],
      ['a', 'b'],
      ['a', 'b']
    ]
    const expected = 1
    const result = detectHeaderRow(data)
    expect(result).toBe(expected)
  })
}


() => {
    const data = [
      ['a', ''],
      ['a', 'b'],
      ['a', 'b']
    ]
    const expected = 1
    const result = detectHeaderRow(data)
    expect(result).toBe(expected)
  }


() => {
  it('should create an instance', () => {
    const directive = new ClipboardDirective();
    expect(directive).toBeTruthy();
  });
}


() => {
    const directive = new ClipboardDirective();
    expect(directive).toBeTruthy();
  }


export default class A extends HTMLElement {
  count: number = 10;
  text: Text;
  constructor(opts: any) {
    super();
    this.text = new Text(`Count: ${this.count}`);
    this.append(this.text);
  }
  static ret(arr: string) {}
  attributeChangedCallback(prop: string, value: any) {
    this.text.data = `Count: ${this.count}`;
  }
}


static ret(arr: string) {}


attributeChangedCallback(prop: string, value: any) {
    this.text.data = `Count: ${this.count}`;
  }


() => SelectComponent


_ => {
                    this._setOptionsArray();
                    this._setOptionsProperties();
                    this._setSelectedOption();
                    this._listenOnOptionKeydown();
                    setTimeout(() => {
                        if (this.selected === undefined && this.unselectMissingOption) {
                            this._updateValue(undefined);
                            this._setSelectViewValue();
                            this._changeDetectorRef.markForCheck();
                        }
                    });
                }


() => {
                        if (this.selected === undefined && this.unselectMissingOption) {
                            this._updateValue(undefined);
                            this._setSelectViewValue();
                            this._changeDetectorRef.markForCheck();
                        }
                    }


option => {
            this._subscriptions.add(
                option.selectionEvent.pipe(
                    takeUntil(this._refresh$),
                    filter(event => !!event)
                ).subscribe(event => this.keydownHandler(event))
            )
        }


event => !!event


event => this.keydownHandler(event)


_ => this.onTouched()


option => option.selected


(change: OptionStatusChange) => this.setSelectedOption(change)


_ => this.isInteractive


(event: KeyboardEvent) => KeyUtil.isKeyType(event, 'numeric') || KeyUtil.isKeyType(event, 'alphabetical')


event => event.key


keys => keys.join('')


query => this._searchOption(query)


options => options.viewValueText.toLowerCase().startsWith(query)


(option: OptionComponent) => setTimeout(() => option.focus(), 10)


() => option.focus()


option => option.setExtendedTemplate(this.extendedBodyTemplate)


option => option.getHtmlElement()


export interface OptionStatusChange {
    option: OptionComponent,
    controlChange: boolean
}


export type SelectControlState = 'error' | 'success' | 'warning' | 'information';


/** @hidden */
@HostListener('keydown', ['$event'])
    keydownHandler(event: KeyboardEvent): void {
        if (KeyUtil.isKeyCode(event, UP_ARROW)) {
            if (this.isInteractive) {
                this._interactWithOptions('previous');
            }
            event.preventDefault();

        } else if (KeyUtil.isKeyCode(event, DOWN_ARROW)) {
            if (this.isInteractive) {
                this._interactWithOptions('next');
            }
            event.preventDefault();

        } else if (KeyUtil.isKeyCode(event, ESCAPE)) {
            if (this.isInteractive) {
                this.close();
            }
            event.preventDefault();

        } else if (KeyUtil.isKeyCode(event, [SPACE, ENTER])) {
            if (this.isInteractive) {
                this.toggle();
            }
            event.preventDefault();
        }
    }


/** @hidden */
@HostListener('window:resize')
    resizeScrollHandler(): void {
        this.calculatedMaxHeight = this.mobile ? null : window.innerHeight * 0.45;
    }


/** @hidden */
ngOnInit(): void {
        this._listenOnSelectedOption();
        this._listenOptionFiltering();
    }


/** @hidden */
ngAfterContentInit(): void {
        this.resizeScrollHandler();
        this._listenOnOptionChanges();
        this._listenOnOptionKeydown();
        this._setSelectViewValue();
    }


/** @hidden */
ngAfterViewInit(): void {
        this._listenOnControlTouched();
        this._setOptionsArray();
        this._setOptionsProperties();
        this._setupMobileMode();
    }


/** @hidden */
ngOnDestroy(): void {
        this._subscriptions.unsubscribe();
    }


/** @hidden */
popoverOpenChangeHandle(isOpen: boolean): void {
        isOpen ? this.open() : this.close();
    }


/** Toggles the open state of the select. */
toggle(): void {
        this.isOpen ? this.close() : this.open();
    }


/** Opens the select popover body. */
open(): void {
        if (this.isInteractive) {
            this.isOpen = true;
            this.isOpenChange.emit(this.isOpen);
            this._focusOption('onOpen');
            this._changeDetectorRef.markForCheck();
        }
    }


/** Closes the select popover body. */
close(): void {
        this.isOpen = false;
        this.isOpenChange.emit(this.isOpen);
        this.focus();
        this._changeDetectorRef.markForCheck();
    }


/** Focuses select control. */
focus(): void {
        if (this.controlElementRef) {
            (this.controlElementRef.nativeElement as HTMLElement).focus();
        }
    }


/** @hidden */
registerOnChange(fn: any): void {
        this.onChange = fn;
    }


/** @hidden */
registerOnTouched(fn: any): void {
        this.onTouched = fn;
    }


/** @hidden */
setDisabledState(isDisabled: boolean): void {
        this.disabled = isDisabled;
        this._changeDetectorRef.markForCheck();
    }


/** @hidden */
writeValue(value: any): void {
        this._selectProxy.value$.next(value);
    }


/** @hidden */
setSelectedOption({option, controlChange}: OptionStatusChange, forceMobileSelect?: boolean): void {
        this.selected = option;
        this._setSelectViewValue();

        if (controlChange) {
            this._updateValue(option.value, !forceMobileSelect && this.isCancelableMobileSelect);
            if (!this.isCancelableMobileSelect) {
                this.close();
            }
        }
        this._changeDetectorRef.markForCheck();
    }


/** @hidden */
private _listenOnOptionChanges(): void {
        this._subscriptions.add(
            this.options.changes
                .subscribe(_ => {
                    this._setOptionsArray();
                    this._setOptionsProperties();
                    this._setSelectedOption();
                    this._listenOnOptionKeydown();
                    setTimeout(() => {
                        if (this.selected === undefined && this.unselectMissingOption) {
                            this._updateValue(undefined);
                            this._setSelectViewValue();
                            this._changeDetectorRef.markForCheck();
                        }
                    });
                })
        )
    }


/** @hidden */
private _listenOnOptionKeydown(): void {
        this._refresh$.next();

        this.options.forEach(option => {
            this._subscriptions.add(
                option.selectionEvent.pipe(
                    takeUntil(this._refresh$),
                    filter(event => !!event)
                ).subscribe(event => this.keydownHandler(event))
            )
        })
    }


private _listenOnControlTouched(): void {
        this._subscriptions.add(
            fromEvent(this.controlElementRef.nativeElement, 'blur').subscribe(_ => this.onTouched())
        )
    }


/** @hidden */
private _setSelectedOption(): void {
        this.selected = this._options.find(option => option.selected);
    }


/** @hidden */
private _updateValue(value: any, silent?: boolean): void {
        this._selectProxy.value$.next(value);
        if (!silent) {
            this.valueChange.emit(value);
            this.onChange(value);
        }
    }


/** @hidden Function used to setup new listener reacting on option select events.*/
private _listenOnSelectedOption(): void {
        this._subscriptions.add(
            this._selectProxy.optionStateChange$.asObservable()
                .subscribe((change: OptionStatusChange) => this.setSelectedOption(change))
        );
    }


/** @hidden Listen on alphabetical or numerical keys and interact with options */
private _listenOptionFiltering(): void {
        const source = fromEvent(this._elementRef.nativeElement, 'keydown').pipe(
            filter(_ => this.isInteractive),
            filter((event: KeyboardEvent) => KeyUtil.isKeyType(event, 'numeric') || KeyUtil.isKeyType(event, 'alphabetical'))
        );
        const trigger = source.pipe(debounceTime(this.typeaheadDebounceInterval));

        this._subscriptions.add(
            source.pipe(
                map(event => event.key),
                buffer(trigger),
                map(keys => keys.join(''))
            ).subscribe(query => this._searchOption(query))
        );
    }


/** @hidden Search for options by query */
private _searchOption(query: string): void {
        const validOptions = this._options.filter(options => options.viewValueText.toLowerCase().startsWith(query));

        if (!validOptions.length) {
            return;
        }

        if (this.isOpen) {
            const focusedOptionIndex = this._focusedOptionIndex(validOptions, document.activeElement);
            if (focusedOptionIndex !== -1) {
                validOptions[(focusedOptionIndex + 1) % validOptions.length].focus();
            } else {
                validOptions[0].focus();
            }
        } else {
            const selectedOptionIndex = validOptions.indexOf(this.selected);
            if (selectedOptionIndex !== -1) {
                this.setSelectedOption({
                    option: validOptions[(selectedOptionIndex + 1) % validOptions.length],
                    controlChange: true
                });
            } else {
                this.setSelectedOption({option: validOptions[0], controlChange: true});
            }
        }
    }


/** @hidden */
private _interactWithOptions(action: 'previous' | 'next'): void {
        if (!this._options.length) {
            return;
        }

        if (this.isOpen) {
            this._focusOption(action);
        } else {
            this._selectOption(action);
        }
    }


/** @hidden Method used to focus options
     * @param action
     * 'onOpen'     - focus currently selected or first
     * 'next'       - focus next element
     * 'previous'   - focus previous element
     * */
private _focusOption(action: 'onOpen' | 'next' | 'previous'): void {
        let activeIndex: number;
        const focusAsync = (option: OptionComponent) => setTimeout(() => option.focus(), 10);

        switch (action) {
            case 'onOpen':
                focusAsync(this.selected || this._options[0]);
                break;
            case 'next':
                activeIndex = this._focusedOptionIndex(this._options, document.activeElement);
                if (activeIndex < this._options.length - 1) {
                    this._options[++activeIndex].focus();
                }
                break;
            case 'previous':
                activeIndex = this._focusedOptionIndex(this._options, document.activeElement);
                if (activeIndex > 0) {
                    this._options[--activeIndex].focus();
                }
                break;
        }
    }


/** @hidden Method used to select next/previous options
     * @param action
     * 'next'       - select next element
     * 'previous'   - select previous element
     * */
private _selectOption(action: 'next' | 'previous'): void {
        let activeIndex = this._options.indexOf(this.selected);

        switch (action) {
            case 'next':
                if (activeIndex < this._options.length - 1) {
                    this.setSelectedOption({option: this._options[++activeIndex], controlChange: true});
                }
                break;
            case 'previous':
                if (activeIndex > 0) {
                    this.setSelectedOption({option: this._options[--activeIndex], controlChange: true});
                }
                break;
        }
    }


/** @hidden */
private _setOptionsArray(): void {
        this._options = this.options.toArray();
    }


/** @hidden */
private _setOptionsProperties(): void {
        this._options.forEach(option => option.setExtendedTemplate(this.extendedBodyTemplate));
    }


/** @hidden */
private _focusedOptionIndex(options: OptionComponent[], activeOption: Element): number {
        return options.map(option => option.getHtmlElement())
            .indexOf(activeOption as HTMLElement);
    }


/** @hidden Sets new select control text */
private _setSelectViewValue(): void {
        this.selectViewValue = this.selected ? this.selected.viewValueText : this.placeholder;
    }


private _setupMobileMode(): void {
        if (this.mobile) {
            this._dynamicComponentService.createDynamicComponent(
                this.selectOptionsListTemplate,
                SelectMobileComponent,
                {container: this._elementRef.nativeElement},
                {injector: Injector.create({providers: [{provide: SELECT_COMPONENT, useValue: this}]})}
            )
        }
    }


function fetchBlobCacheKey(parsed: ParsedRepoURI & { disableTimeout: boolean }): string {
    return makeRepoURI(parsed) + String(parsed.disableTimeout)
}


(args: {
        repoName: string
        commitID: string
        filePath: string
        disableTimeout: boolean
    }): Observable<BlobFileFields | null> =>
        requestGraphQL<BlobResult, BlobVariables>(
            gql`
                query Blob($repoName: String!, $commitID: String!, $filePath: String!, $disableTimeout: Boolean!) {
                    repository(name: $repoName) {
                        commit(rev: $commitID) {
                            file(path: $filePath) {
                                ...BlobFileFields
                            }
                        }
                    }
                }

                fragment BlobFileFields on File2 {
                    content
                    richHTML
                    highlight(disableTimeout: $disableTimeout) {
                        aborted
                        html
                    }
                }
            `,
            args
        ).pipe(
            map(dataOrThrowErrors),
            map(data => {
                if (!data.repository?.commit) {
                    throw new Error('Commit not found')
                }
                return data.repository.commit.file
            })
        )


data => {
                if (!data.repository?.commit) {
                    throw new Error('Commit not found')
                }
                return data.repository.commit.file
            }


@Controller('tools')
export class ToolsController {}


export class Highlight extends React.Component<{
    className: string;
    highlightClassName: string;
    text: string;
    highlightText: string;
}> {

    render() {
        if ( !this.props.highlightText ) {
            return

                {this.props.text}

;
        }

        const lowerText = this.props.text.toLowerCase();
        const lowerHighlightPhrase = this.props.text;
        const startHighlight = lowerText.indexOf(lowerHighlightPhrase);
        const endHighlight =  startHighlight + lowerHighlightPhrase.length;

        if ( startHighlight === -1 ) {
            return

                {this.props.text}

;
        }

        const beforeText = this.props.text.slice(0, startHighlight);
        const highlightedText = this.props.text.slice(
            startHighlight,
            endHighlight
        );
        const afterText = this.props.text.slice(endHighlight);

        return

            {beforeText}
            { highlightedText }
            {afterText}

;
    }

}


render() {
        if ( !this.props.highlightText ) {
            return

                {this.props.text}

;
        }

        const lowerText = this.props.text.toLowerCase();
        const lowerHighlightPhrase = this.props.text;
        const startHighlight = lowerText.indexOf(lowerHighlightPhrase);
        const endHighlight =  startHighlight + lowerHighlightPhrase.length;

        if ( startHighlight === -1 ) {
            return

                {this.props.text}

;
        }

        const beforeText = this.props.text.slice(0, startHighlight);
        const highlightedText = this.props.text.slice(
            startHighlight,
            endHighlight
        );
        const afterText = this.props.text.slice(endHighlight);

        return

            {beforeText}
            { highlightedText }
            {afterText}

;
    }


@Controller('authors')
export class AuthorController {
  constructor(private readonly authorService: AuthorService) {}

  @Get()
  getAuthors() {
    return this.authorService.getAuthors();
  }
}


@Get()
  getAuthors() {
    return this.authorService.getAuthors();
  }


(games) => {
			this.setState({games});
		}


(element: any, index: number) => {
		return (
			<TableRow key={index}>
				<TableCell>
					<LinkIconButton to={"/games/" + element.id}>
						<PlayIcon style={{cursor: "pointer"}}/>
					</LinkIconButton>
				</TableCell>
				<TableCell padding="none"><Link to={"/games/" + element.id}>{element.name}</Link></TableCell>
			</TableRow>
		);
	}


() => {
		if (null === this.state.sets) {
			this.setState({sets: []});
			this.props.loadSets()
				.then((sets) => {
					this.setState({sets});
				});
		}
		this.setState({dialogVisible: true});
	}


(sets) => {
					this.setState({sets});
				}


() => {
		this.setState({dialogVisible: false});
	}


(matchSetId: string, name: string) => {
		this.setState({dialogVisible: false});
		this.props.createGame(matchSetId, name)
			.then(() => {
				this.loadGames();
			});
	}


() => {
				this.loadGames();
			}


export class GameList extends React.PureComponent<GameListProps, State> {
	public constructor(props: GameListProps) {
		super(props);
		this.state = {
			games: [],
			dialogVisible: false,
			sets: null
		};
	}

	public render(): JSX.Element {
		return (

					<TableHead>
						<TableRow>
							<TableCell style={{width: 1}}


export interface GameListProps {
	loadGames: () => Promise<Game[]>;
	loadSets: () => Promise<MatchSet[]>;
	createGame: (matchSetId: string, name: string) => Promise<Game>;
}


interface State {
	games: Game[];
	sets: MatchSet[];
	dialogVisible: boolean;
}


public render(): JSX.Element {
		return (

					<TableHead>
						<TableRow>
							<TableCell style={{width: 1}}


@Exclude()
export class UpdateGatewayDto {
    @Expose()
    @IsNotEmpty()
    @IsString()
    readonly id: string;
    @Expose()
    @IsNotEmpty()
    @IsString()
    readonly serial_number: string;
    @Expose()
    @IsNotEmpty()
    @IsString()
    readonly name: string;
    @Expose()
    @IsNotEmpty()
    @IsString()
    readonly IPv4: string;

}


/** Мод "Auth". Страницы. Начало. Сервис. */
@Injectable({
  providedIn: 'root'
})
export class AppModAuthPageIndexService {

  /**
   * Настройки.
   * @type {AppModAuthPageIndexSettings}
   */
  settings = new AppModAuthPageIndexSettings();
}


class CommandGenerator extends Generator {
  pjson!: any

  get _path() {
    return this.options.name.split(':').join('/')
  }

  get _ts() {
    return this.pjson.devDependencies.typescript
  }

  get _ext() {
    return this._ts ? 'ts' : 'js'
  }

  get _mocha() {
    return this.pjson.devDependencies.mocha
  }

  constructor(args: any, public options: Options) {
    super(args, options)
  }

  async prompting() {
    this.pjson = this.fs.readJSON('package.json')
    if (!this.pjson) throw new Error('not in a project directory')
    this.pjson.oclif = this.pjson.oclif || {}
    this.log(yosay(`Adding a command to ${this.pjson.name} Version: ${version}`))
  }

  writing() {
    this.sourceRoot(path.join(__dirname, '../../templates'))
    let bin = this.pjson.oclif.bin || this.pjson.oclif.dirname || this.pjson.name
    if (bin.includes('/')) bin = bin.split('/').pop()
    const cmd = `${bin} ${this.options.name}`
    const commandPath = this.destinationPath(`src/commands/${this._path}.${this._ext}`)
    const opts = {...this.options, bin, cmd, _, type: 'command', path: commandPath}
    this.fs.copyTpl(this.templatePath(`src/command.${this._ext}.ejs`), commandPath, opts)
    // this.fs.copyTpl(this.templatePath(`plugin/src/hooks/init.${this._ext}`), this.destinationPath(`src/hooks/init.${this._ext}`), this)
    if (this._mocha) {
      // this.fs.copyTpl(this.templatePath(`plugin/test/hooks/init.test.${this._ext}`), this.destinationPath(`test/hooks/init.test.${this._ext}`), this)
      this.fs.copyTpl(this.templatePath(`test/command.test.${this._ext}.ejs`), this.destinationPath(`test/commands/${this._path}.test.${this._ext}`), opts)
    }
    // this.fs.writeJSON(this.destinationPath('./package.json'), this.pjson)
  }

  end() {
    this.spawnCommandSync(path.join('.', 'node_modules/.bin/oclif-dev'), ['readme'])
  }
}


async prompting() {
    this.pjson = this.fs.readJSON('package.json')
    if (!this.pjson) throw new Error('not in a project directory')
    this.pjson.oclif = this.pjson.oclif || {}
    this.log(yosay(`Adding a command to ${this.pjson.name} Version: ${version}`))
  }


writing() {
    this.sourceRoot(path.join(__dirname, '../../templates'))
    let bin = this.pjson.oclif.bin || this.pjson.oclif.dirname || this.pjson.name
    if (bin.includes('/')) bin = bin.split('/').pop()
    const cmd = `${bin} ${this.options.name}`
    const commandPath = this.destinationPath(`src/commands/${this._path}.${this._ext}`)
    const opts = {...this.options, bin, cmd, _, type: 'command', path: commandPath}
    this.fs.copyTpl(this.templatePath(`src/command.${this._ext}.ejs`), commandPath, opts)
    // this.fs.copyTpl(this.templatePath(`plugin/src/hooks/init.${this._ext}`), this.destinationPath(`src/hooks/init.${this._ext}`), this)
    if (this._mocha) {
      // this.fs.copyTpl(this.templatePath(`plugin/test/hooks/init.test.${this._ext}`), this.destinationPath(`test/hooks/init.test.${this._ext}`), this)
      this.fs.copyTpl(this.templatePath(`test/command.test.${this._ext}.ejs`), this.destinationPath(`test/commands/${this._path}.test.${this._ext}`), opts)
    }
    // this.fs.writeJSON(this.destinationPath('./package.json'), this.pjson)
  }


end() {
    this.spawnCommandSync(path.join('.', 'node_modules/.bin/oclif-dev'), ['readme'])
  }


@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    HttpClientModule,
    AppRoutingModule,
    SocketIoModule.forRoot(config),
    NgbModule.forRoot(),
    NbDatepickerModule.forRoot(),
    ThemeModule.forRoot(),
    CoreModule.forRoot(),
    SortablejsModule.forRoot({ animation: 150 })
  ],
  bootstrap: [AppComponent],
  providers: [
    {
      provide: ENVIRONMENT_TOKEN,
      useValue: environment
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    },
  ]
})
export class AppModule {
}


export class Router {
    public nodesController = new StatusController()

    public routes(server: express.Application): void {
        server.route('/').get(this.nodesController.index)
        server.route('/nodes').get(this.nodesController.index)
    }
}


public routes(server: express.Application): void {
        server.route('/').get(this.nodesController.index)
        server.route('/nodes').get(this.nodesController.index)
    }


/**
     * True if the provided value is a List
     *
     * <!-- runkit:activate -->
     * ```js
     * const { List } = require('immutable');
     * List.isList([]); // false
     * List.isList(List()); // true
     * ```
     */
function isList(maybeList: any): maybeList is List<any>;


/**
     * Creates a new List containing `values`.
     *
     * <!-- runkit:activate -->
     * ```js
     * const { List } = require('immutable');
     * List.of(1, 2, 3, 4)
     * // List [ 1, 2, 3, 4 ]
     * ```
     *
     * Note: Values are not altered or converted in any way.
     *
     * <!-- runkit:activate -->
     * ```js
     * const { List } = require('immutable');
     * List.of({x:1}, 2, [3], 4)
     * // List [ { x: 1 }, 2, [ 3 ], 4 ]
     * ```
     */
function of<T>(...values: Array<T>): List<T>;


/**
   * Create a new immutable List containing the values of the provided
   * collection-like.
   *
   * Note: `List` is a factory function and not a class, and does not use the
   * `new` keyword during construction.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { List, Set } = require('immutable')
   *
   * const emptyList = List()
   * // List []
   *
   * const plainArray = [ 1, 2, 3, 4 ]
   * const listFromPlainArray = List(plainArray)
   * // List [ 1, 2, 3, 4 ]
   *
   * const plainSet = Set([ 1, 2, 3, 4 ])
   * const listFromPlainSet = List(plainSet)
   * // List [ 1, 2, 3, 4 ]
   *
   * const arrayIterator = plainArray[Symbol.iterator]()
   * const listFromCollectionArray = List(arrayIterator)
   * // List [ 1, 2, 3, 4 ]
   *
   * listFromPlainArray.equals(listFromCollectionArray) // true
   * listFromPlainSet.equals(listFromCollectionArray) // true
   * listFromPlainSet.equals(listFromPlainArray) // true
   * ```
   */
export function List(): List<any>;


export function List<T>(): List<T>;


export function List<T>(collection: Iterable<T>): List<T>;


/**
     * True if the provided value is a Map
     *
     * <!-- runkit:activate -->
     * ```js
     * const { Map } = require('immutable')
     * Map.isMap({}) // false
     * Map.isMap(Map()) // true
     * ```
     */
function isMap(maybeMap: any): boolean;


/**
     * Creates a new Map from alternating keys and values
     *
     * <!-- runkit:activate -->
     * ```js
     * const { Map } = require('immutable')
     * Map.of(
     *   'key', 'value',
     *   'numerical value', 3,
     *    0, 'numerical key'
     * )
     * // Map { 0: "numerical key", "key": "value", "numerical value": 3 }
     * ```
     *
     * @deprecated Use Map([ [ 'k', 'v' ] ]) or Map({ k: 'v' })
     */
function of(...keyValues: Array<any>): Map<any, any>;


/**
   * Creates a new Immutable Map.
   *
   * Created with the same key value pairs as the provided Collection.Keyed or
   * JavaScript Object or expects a Collection of [K, V] tuple entries.
   *
   * Note: `Map` is a factory function and not a class, and does not use the
   * `new` keyword during construction.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { Map } = require('immutable')
   * Map({ key: "value" })
   * Map([ [ "key", "value" ] ])
   * ```
   *
   * Keep in mind, when using JS objects to construct Immutable Maps, that
   * JavaScript Object properties are always strings, even if written in a
   * quote-less shorthand, while Immutable Maps accept keys of any type.
   *
   * <!-- runkit:activate
   *      { "preamble": "const { Map } = require('immutable');" }
   * -->
   * ```js
   * let obj = { 1: "one" }
   * Object.keys(obj) // [ "1" ]
   * assert.equal(obj["1"], obj[1]) // "one" === "one"
   *
   * let map = Map(obj)
   * assert.notEqual(map.get("1"), map.get(1)) // "one" !== undefined
   * ```
   *
   * Property access for JavaScript Objects first converts the key to a string,
   * but since Immutable Map keys can be of any type the argument to `get()` is
   * not altered.
   */
export function Map<K, V>(collection: Iterable<[K, V]>): Map<K, V>;


export function Map<V>(obj: {[key: string]: V}): Map<string, V>;


export function Map<K, V>(): Map<K, V>;


export function Map(): Map<any, any>;


/**
     * True if the provided value is a SortedMap
     *
     * ```js
     * > const { SortedMap, SortedSet, List, Map, Set } = require('immutable-sorted');
     * > SortedMap.isSortedMap(SortedMap());
     * true
     * > SortedMap.isSortedMap(SortedSet());
     * false
     * > SortedMap.isSortedMap(Map());
     * false
     * > SortedMap.isSortedMap(Set());
     * false
     * > SortedMap.isSortedMap(List());
     * false
     * ```
     */
function isSortedMap(maybeSortedMap: any): boolean;


/**
     * Creates a new SortedMap from alternating keys and values
     *
     * ```js
     * > const { SortedMap } = require('immutable-sorted')
     * > let sortedMap=SortedMap.of('orange','orange', 'apple','red', 'banana','yellow');
     * SortedMap { "apple": "red", "banana": "yellow", "orange": "orange" }
     * ```
     *
     * @deprecated Use SortedMap([ [ 'k', 'v' ] ]) or SortedMap({ k: 'v' })
     */
function of(...keyValues: Array<any>): SortedMap<any, any>;


/**
   * Creates a new immutable `SortedMap` containing the entries of the provided
   * collection-like. The keys will be sorted by the provided comparator.
   *
   * The comparator is a function that takes two arguments (a, b) and
   * returns 0 if a and b are equal, returns positive number when a > b
   * and returns negative number if a < b.
   *
   * If comparator is undefined, the `defaultComparator` will be applied.
   * This comparator is different than the default comparator used by `Collection.sort`
   * because more stringent comparison rules have to be applied to support all the types
   * and marginal values like NaN or Infinity.
   *
   * The `defaultComparator` first determines equality by calling `Immutable.is`,
   * then compares the types of both values. If both values are of the same type,
   * then it compares the values by using the javascript comparison operators > and <,
   * but before that the objects, functions, and symbols are converted to string.
   *
   * The internal data structures will be created according to the given options. If options
   * are undefined then `defaultOptions` will be applied.
   *
   * The default options are:
   * ```js
   * {type: 'btree', btreeOrder: 33}
   * ```
   * Currently the only type implemented is `btree`. It is a classic [B-Tree](https://en.wikipedia.org/wiki/B-tree)
   * structure with keys and values not only in leaves but also in internal nodes.
   * The option `btreeOrder` is defined as the maximum number of children that any internal nodes can have
   * and also implies maximum number of entries (key/value pairs) in any node which is (`btreeOrder` - 1).
   * The `btreeOrder` option can be changed in a constructor and can be any integer greater or equal 3.
   *
   * There are many ways to quickly and conveniently create a `SortedMap` by calling a constructor.
   * Below are some examples.
   *
   * Create a `SortedMap` from any array of [K,V]:
   * ```js
   * > const { SortedMap } = require('immutable-sorted');
   * > let a=SortedMap([['a','A'], ['c','C'], ['z','Z'], ['u','U'], ['b','B']]);
   * SortedMap { "a": "A", "b": "B", "c": "C", "u": "U", "z": "Z" }
   * ```
   *
   * From a keyed sequence:
   * ```js
   * > const { SortedMap, SortedSet, List, Map, Seq, Set } = require('immutable-sorted');
   *
   * > let seq=Seq({x:'X', c:'B', m:'M', anylabel:'K', f:'F'});
   * Seq { "x": "X", "c": "B", "m": "M", "anylabel": "K", "f": "F" }
   *
   * > let b=SortedMap(seq);
   * SortedMap { "anylabel": "K", "c": "B", "f": "F", "m": "M", "x": "X" }
   * ```
   *
   * From other collections (List, Range, Set, Map):
   * ```js
   * > const { SortedMap, List, Map, Range, Seq, Set } = require('immutable-sorted');
   * > let list=List(['orange', 'apple', 'banana']);
   * List [ "orange", "apple", "banana" ]
   * > let c=SortedMap(list.toKeyedSeq());
   * SortedMap { 0: "orange", 1: "apple", 2: "banana" }
   *
   * > c=SortedMap(list.toKeyedSeq().flip());
   * SortedMap { "apple": 1, "banana": 2, "orange": 0 }
   *
   * > let range=Range(30, 0, 5);
   * Range [ 30...0 by -5 ]
   * > c=SortedMap(range.toKeyedSeq());
   * SortedMap { 0: 30, 1: 25, 2: 20, 3: 15, 4: 10, 5: 5 }
   * > c=SortedMap(range.toKeyedSeq().flip());
   * SortedMap { 5: 5, 10: 4, 15: 3, 20: 2, 25: 1, 30: 0 }
   *
   * > let set=Set(['orange', 'apple', 'banana']);
   * Set { "orange", "apple", "banana" }
   * > c=SortedMap(set.toKeyedSeq());
   * SortedMap { "apple": "apple", "banana": "banana", "orange": "orange" }
   *
   * > let map=Map({x:'X', c:'B', m:'M', anylabel:'K', f:'F'});
   * Map { "x": "X", "c": "B", "m": "M", "anylabel": "K", "f": "F" }
   * > c=SortedMap(map);
   * SortedMap { "anylabel": "K", "c": "B", "f": "F", "m": "M", "x": "X" }
   * ```
   *
   * Use a custom comparator (reverse order):
   * ```js
   * > let reverseComparator=(a, b)=>(a > b ? -1 : a < b ? 1 : 0);
   * > let d=SortedMap(list.toKeyedSeq().flip(), reverseComparator);
   * SortedMap { "orange": 0, "banana": 2, "apple": 1 }
   *
   * // Create an empty map with custom comparator
   * > d=SortedMap(undefined, reverseComparator);
   * ```
   *
   * Change the `btreeOrder` option:
   * ```js
   * > let options={type: 'btree', btreeOrder: 17};
   * > let e=SortedMap(list.toKeyedSeq().flip(), reverseComparator, options);
   * SortedMap { "orange": 0, "banana": 2, "apple": 1 }
   *
   * // Create an empty set with default comparator and custom options
   * > e=SortedMap(undefined, undefined, options);
   * ```
   *
   * You can also conveniently create a `SortedMap` within a chain of sequence operations:
   * ```js
   * > seq.toSortedMap();
   * SortedMap { "anylabel": "K", "c": "B", "f": "F", "m": "M", "x": "X" }
   *
   * > seq.toSortedMap(reverseComparator);
   * SortedMap { "x": "X", "m": "M", "f": "F", "c": "B", "anylabel": "K" }
   * ```
   */
export function SortedMap<K, V>(collection?: Iterable<[K, V]>,
    comparator?: (a: K, b: K) => number,
    options?: Object): SortedMap<K, V>;


export function SortedMap<T>(collection: Iterable<Iterable<T>>,
    comparator?: (a: T, b: T) => number,
    options?: Object): SortedMap<T, T>;


export function SortedMap<V>(obj: {[key: string]: V},
    comparator?: (a: string, b: string) => number,
    options?: Object): SortedMap<string, V>;


/**
     * True if the provided value is an OrderedMap.
     */
function isOrderedMap(maybeOrderedMap: any): maybeOrderedMap is OrderedMap<any, any>;


/**
   * Creates a new Immutable OrderedMap.
   *
   * Created with the same key value pairs as the provided Collection.Keyed or
   * JavaScript Object or expects a Collection of [K, V] tuple entries.
   *
   * The iteration order of key-value pairs provided to this constructor will
   * be preserved in the OrderedMap.
   *
   *     let newOrderedMap = OrderedMap({key: "value"})
   *     let newOrderedMap = OrderedMap([["key", "value"]])
   *
   * Note: `OrderedMap` is a factory function and not a class, and does not use
   * the `new` keyword during construction.
   */
export function OrderedMap<K, V>(collection: Iterable<[K, V]>): OrderedMap<K, V>;


export function OrderedMap<V>(obj: {[key: string]: V}): OrderedMap<string, V>;


export function OrderedMap<K, V>(): OrderedMap<K, V>;


export function OrderedMap(): OrderedMap<any, any>;


/**
     * True if the provided value is a Set
     */
function isSet(maybeSet: any): maybeSet is Set<any>;


/**
     * Creates a new Set containing `values`.
     */
function of<T>(...values: Array<T>): Set<T>;


/**
     * `Set.fromKeys()` creates a new immutable Set containing the keys from
     * this Collection or JavaScript Object.
     */
function fromKeys<T>(iter: Collection<T, any>): Set<T>;


function fromKeys(obj: {[key: string]: any}): Set<string>;


/**
     * `Set.intersect()` creates a new immutable Set that is the intersection of
     * a collection of other sets.
     *
     * ```js
     * const { Set } = require('immutable')
     * const intersected = Set.intersect([
     *   Set([ 'a', 'b', 'c' ])
     *   Set([ 'c', 'a', 't' ])
     * ])
     * // Set [ "a", "c"" ]
     * ```
     */
function intersect<T>(sets: Iterable<Iterable<T>>): Set<T>;


/**
     * `Set.union()` creates a new immutable Set that is the union of a
     * collection of other sets.
     *
     * ```js
     * const { Set } = require('immutable')
     * const unioned = Set.union([
     *   Set([ 'a', 'b', 'c' ])
     *   Set([ 'c', 'a', 't' ])
     * ])
     * // Set [ "a", "b", "c", "t"" ]
     * ```
     */
function union<T>(sets: Iterable<Iterable<T>>): Set<T>;


/**
   * Create a new immutable Set containing the values of the provided
   * collection-like.
   *
   * Note: `Set` is a factory function and not a class, and does not use the
   * `new` keyword during construction.
   */
export function Set(): Set<any>;


export function Set<T>(): Set<T>;


export function Set<T>(collection: Iterable<T>): Set<T>;


/**
     * True if the provided value is a `SortedSet`.
     *
     * ```js
     * > const { SortedMap, SortedSet, List, Map, Set } = require('immutable-sorted');
     * > SortedSet.isSortedSet(SortedSet());
     * true
     * > SortedSet.isSortedSet(SortedMap());
     * false
     * > SortedSet.isSortedSet(Set());
     * false
     * > SortedSet.isSortedSet(Map());
     * false
     * > SortedSet.isSortedSet(List());
     * false
     * ```
     */
function isSortedSet(maybeSortedSet: any): boolean;


/**
     * Creates a new `SortedSet` containing `values`.
     *
     * ```js
     * > const { SortedMap } = require('immutable-sorted');
     * > let sortedSet=SortedSet.of("orange", "apple", "banana");
     * SortedSet { "apple", "banana", "orange" }
     * ```
     */
function of<T>(...values: Array<T>): SortedSet<T>;


/**
     * `SortedSet.fromKeys()` creates a new immutable `SortedSet` containing
     * the keys from this Collection or JavaScript Object.
     *
     * ```js
     * > const { SortedMap, Map } = require('immutable-sorted');
     *
     * > let map=Map({x:'X', c:'B', m:'M', anylabel:'K', f:'F'});
     * > let sortedSet=SortedSet.fromKeys(map);
     * SortedSet { "anylabel", "c", "f", "m", "x" }
     *
     * > sortedSet=SortedSet.fromKeys({x:'X', c:'B', m:'M', anylabel:'K', f:'F'});
     * SortedSet { "anylabel", "c", "f", "m", "x" }
     * ```
     */
function fromKeys<T>(iter: Collection<T, any>): SortedSet<T>;


function fromKeys(obj: {[key: string]: any}): SortedSet<string>;


/**
   * Creates a new immutable `SortedSet` containing the values of the provided
   * collection-like. The values will be sorted by the provided comparator.
   *
   * The comparator is a function that takes two arguments (a, b) and
   * returns 0 if a and b are equal, returns positive number when a > b
   * and returns negative number if a < b.
   *
   * If comparator is undefined, the `defaultComparator` will be applied.
   * This comparator is different than the default comparator used by `Collection.sort`
   * because more stringent comparison rules have to be applied to support all the types
   * and marginal values like NaN or Infinity.
   *
   * The `defaultComparator` first determines equality by calling `Immutable.is`,
   * then compares the types of both values. If both values are of the same type,
   * then it compares the values by using the javascript comparison operators > and <,
   * but before that the objects, functions, and symbols are converted to string.
   *
   * The internal data structures will be created according to the given options. If options
   * are undefined then `defaultOptions` will be applied.
   *
   * The default options are:
   * ```js
   * {type: 'btree', btreeOrder: 33}
   * ```
   * Currently the only type implemented is `btree`. It is a classic [B-Tree](https://en.wikipedia.org/wiki/B-tree)
   * structure with keys and values not only in leaves but also in internal nodes.
   * The option `btreeOrder` is defined as the maximum number of children that any internal nodes can have
   * and also implies maximum number of entries (key/value pairs) in any node which is (`btreeOrder` - 1).
   * The `btreeOrder` option can be changed in a constructor and can be any integer greater or equal 3.
   *
   * There are many ways to quickly and conveniently create a `SortedSet` by calling a constructor.
   * Below are some examples.
   *
   * Create a `SortedSet` from any array:
   * ```js
   * > const { SortedMap } = require('immutable-sorted');
   * > let a=SortedSet(['a', 'c', 'z', 'u', 'b', 'q', 'd']);
   * SortedSet { "a", "b", "c", "d", "q", "u", "z" }
   * ```
   *
   * From a sequence of values:
   * ```js
   * > const { SortedMap, SortedSet, List, Map, Seq, Set } = require('immutable-sorted');
   *
   * > let seq=Seq({x:'X', c:'B', m:'M', anylabel:'K', f:'F'});
   * Seq { "x": "X", "c": "B", "m": "M", "anylabel": "K", "f": "F" }
   *
   * > let b=SortedSet(seq.keySeq());
   * SortedSet { "anylabel", "c", "f", "m", "x" }
   *
   * > let c=SortedSet(seq.valueSeq());
   * SortedSet { "B", "F", "K", "M", "X" }
   * ```
   *
   * From a string:
   * ```js
   * > let d=SortedSet('abcdefg');
   * SortedSet { "a", "b", "c", "d", "e", "f", "g" }
   *
   * > let e=SortedSet('gefdcba');
   * SortedSet { "a", "b", "c", "d", "e", "f", "g" }
   *
   * > e=SortedSet("hello");
   * SortedSet { "e", "h", "l", "o" }
   * ```
   *
   * From other collections (List, Range, Set, Map):
   * ```js
   * > let list=List(['orange', 'apple', 'banana']);
   * List [ "orange", "apple", "banana" ]
   * > let f=SortedSet(list);
   * SortedSet { "apple", "banana", "orange" }
   *
   * > let range=Range(30, 0, 5);
   * Range [ 30...0 by -5 ]
   * > f=SortedSet(range);
   * SortedSet { 5, 10, 15, 20, 25, 30 }
   *
   * > let set=Set(['orange', 'apple', 'banana']);
   * Set { "orange", "apple", "banana" }
   * > f=SortedSet(set);
   * SortedSet { "apple", "banana", "orange" }
   *
   * > let map=Map({x:'X', c:'B', m:'M', anylabel:'K', f:'F'});
   * Map { "x": "X", "c": "B", "m": "M", "anylabel": "K", "f": "F" }
   * > f=SortedSet(map.keySeq());
   * SortedSet { "anylabel", "c", "f", "m", "x" }
   * ```
   *
   * Use a custom comparator (reverse order):
   * ```js
   * > let reverseComparator=(a, b)=>(a > b ? -1 : a < b ? 1 : 0);
   * > let g=SortedSet(list, reverseComparator);
   * SortedSet { "orange", "banana", "apple" }
   *
   * // Create an empty set with custom comparator
   * > g=SortedSet(undefined, reverseComparator);
   * ```
   *
   * Change the `btreeOrder` option:
   * ```js
   * > let options={type: 'btree', btreeOrder: 17};
   * > let h=SortedSet(list, reverseComparator, options);
   * SortedSet { "orange", "banana", "apple" }
   *
   * // Create an empty set with default comparator and custom options
   * > h=SortedSet(undefined, undefined, options);
   * ```
   *
   * You can also conveniently create a `SortedSet` within a chain of sequence operations:
   * ```js
   * > seq.keySeq().toSortedSet();
   * SortedSet { "anylabel", "c", "f", "m", "x" }
   *
   * > seq.valueSeq().toSortedSet();
   * SortedSet { "B", "F", "K", "M", "X" }
   *
   * > seq.valueSeq().toSortedSet(reverseComparator);
   * SortedSet { "X", "M", "K", "F", "B" }
   * ```
   */
export function SortedSet<T>(collection?: Iterable<T>,
    comparator?: (a: T, b: T) => number,
    options?: Object): SortedSet<T>;


/**
     * True if the provided value is an OrderedSet.
     */
function isOrderedSet(maybeOrderedSet: any): boolean;


/**
     * Creates a new OrderedSet containing `values`.
     */
function of<T>(...values: Array<T>): OrderedSet<T>;


/**
     * `OrderedSet.fromKeys()` creates a new immutable OrderedSet containing
     * the keys from this Collection or JavaScript Object.
     */
function fromKeys<T>(iter: Collection<T, any>): OrderedSet<T>;


function fromKeys(obj: {[key: string]: any}): OrderedSet<string>;


/**
   * Create a new immutable OrderedSet containing the values of the provided
   * collection-like.
   *
   * Note: `OrderedSet` is a factory function and not a class, and does not use
   * the `new` keyword during construction.
   */
export function OrderedSet(): OrderedSet<any>;


export function OrderedSet<T>(): OrderedSet<T>;


export function OrderedSet<T>(collection: Iterable<T>): OrderedSet<T>;


/**
     * True if the provided value is a Stack
     */
function isStack(maybeStack: any): maybeStack is Stack<any>;


/**
     * Creates a new Stack containing `values`.
     */
function of<T>(...values: Array<T>): Stack<T>;


/**
   * Create a new immutable Stack containing the values of the provided
   * collection-like.
   *
   * The iteration order of the provided collection is preserved in the
   * resulting `Stack`.
   *
   * Note: `Stack` is a factory function and not a class, and does not use the
   * `new` keyword during construction.
   */
export function Stack(): Stack<any>;


export function Stack<T>(): Stack<T>;


export function Stack<T>(collection: Iterable<T>): Stack<T>;


/**
   * Returns a Seq.Indexed of numbers from `start` (inclusive) to `end`
   * (exclusive), by `step`, where `start` defaults to 0, `step` to 1, and `end` to
   * infinity. When `start` is equal to `end`, returns empty range.
   *
   * Note: `Range` is a factory function and not a class, and does not use the
   * `new` keyword during construction.
   *
   * ```js
   * const { Range } = require('immutable')
   * Range() // [ 0, 1, 2, 3, ... ]
   * Range(10) // [ 10, 11, 12, 13, ... ]
   * Range(10, 15) // [ 10, 11, 12, 13, 14 ]
   * Range(10, 30, 5) // [ 10, 15, 20, 25 ]
   * Range(30, 10, 5) // [ 30, 25, 20, 15 ]
   * Range(30, 30, 5) // []
   * ```
   */
export function Range(start?: number, end?: number, step?: number): Seq.Indexed<number>;


/**
   * Returns a Seq.Indexed of `value` repeated `times` times. When `times` is
   * not defined, returns an infinite `Seq` of `value`.
   *
   * Note: `Repeat` is a factory function and not a class, and does not use the
   * `new` keyword during construction.
   *
   * ```js
   * const { Repeat } = require('immutable')
   * Repeat('foo') // [ 'foo', 'foo', 'foo', ... ]
   * Repeat('bar', 4) // [ 'bar', 'bar', 'bar', 'bar' ]
   * ```
   */
export function Repeat<T>(value: T, times?: number): Seq.Indexed<T>;


/**
     * True if `maybeRecord` is an instance of a Record.
     */
export function isRecord(maybeRecord: any): maybeRecord is Record<any>;


/**
     * Records allow passing a second parameter to supply a descriptive name
     * that appears when converting a Record to a string or in any error
     * messages. A descriptive name for any record can be accessed by using this
     * method. If one was not provided, the string "Record" is returned.
     *
     * ```js
     * const { Record } = require('immutable')
     * const Person = Record({
     *   name: null
     * }, 'Person')
     *
     * var me = Person({ name: 'My Name' })
     * me.toString() // "Person { "name": "My Name" }"
     * Record.getDescriptiveName(me) // "Person"
     * ```
     */
export function getDescriptiveName(record: Record<any>): string;


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


/**
   * Unlike other types in Immutable.js, the `Record()` function creates a new
   * Record Factory, which is a function that creates Record instances.
   *
   * See above for examples of using `Record()`.
   *
   * Note: `Record` is a factory function and not a class, and does not use the
   * `new` keyword during construction.
   */
export function Record<TProps>(defaultValues: TProps, name?: string): Record.Factory<TProps>;


/**
     * True if `maybeSeq` is a Seq, it is not backed by a concrete
     * structure such as Map, List, or Set.
     */
function isSeq(maybeSeq: any): maybeSeq is Seq.Indexed<any> | Seq.Keyed<any, any> | Seq.Set<any>;


/**
     * Always returns a Seq.Keyed, if input is not keyed, expects an
     * collection of [K, V] tuples.
     *
     * Note: `Seq.Keyed` is a conversion function and not a class, and does not
     * use the `new` keyword during construction.
     */
export function Keyed<K, V>(collection: Iterable<[K, V]>): Seq.Keyed<K, V>;


export function Keyed<V>(obj: {[key: string]: V}): Seq.Keyed<string, V>;


export function Keyed<K, V>(): Seq.Keyed<K, V>;


export function Keyed(): Seq.Keyed<any, any>;


/**
       * Provides an Seq.Indexed of the values provided.
       */
function of<T>(...values: Array<T>): Seq.Indexed<T>;


/**
     * Always returns Seq.Indexed, discarding associated keys and
     * supplying incrementing indices.
     *
     * Note: `Seq.Indexed` is a conversion function and not a class, and does
     * not use the `new` keyword during construction.
     */
export function Indexed(): Seq.Indexed<any>;


export function Indexed<T>(): Seq.Indexed<T>;


export function Indexed<T>(collection: Iterable<T>): Seq.Indexed<T>;


/**
       * Returns a Seq.Set of the provided values
       */
function of<T>(...values: Array<T>): Seq.Set<T>;


/**
     * Always returns a Seq.Set, discarding associated indices or keys.
     *
     * Note: `Seq.Set` is a conversion function and not a class, and does not
     * use the `new` keyword during construction.
     */
export function Set(): Seq.Set<any>;


export function Set<T>(): Seq.Set<T>;


export function Set<T>(collection: Iterable<T>): Seq.Set<T>;


/**
   * Creates a Seq.
   *
   * Returns a particular kind of `Seq` based on the input.
   *
   *   * If a `Seq`, that same `Seq`.
   *   * If an `Collection`, a `Seq` of the same kind (Keyed, Indexed, or Set).
   *   * If an Array-like, an `Seq.Indexed`.
   *   * If an Iterable Object, an `Seq.Indexed`.
   *   * If an Object, a `Seq.Keyed`.
   *
   * Note: An Iterator itself will be treated as an object, becoming a `Seq.Keyed`,
   * which is usually not what you want. You should turn your Iterator Object into
   * an iterable object by defining a Symbol.iterator (or @@iterator) method which
   * returns `this`.
   *
   * Note: `Seq` is a conversion function and not a class, and does not use the
   * `new` keyword during construction.
   */
export function Seq<S extends Seq<any, any>>(seq: S): S;


export function Seq<K, V>(collection: Collection.Keyed<K, V>): Seq.Keyed<K, V>;


export function Seq<T>(collection: Collection.Indexed<T>): Seq.Indexed<T>;


export function Seq<T>(collection: Collection.Set<T>): Seq.Set<T>;


export function Seq<T>(collection: Iterable<T>): Seq.Indexed<T>;


export function Seq<V>(obj: {[key: string]: V}): Seq.Keyed<string, V>;


export function Seq(): Seq<any, any>;


/**
     * @deprecated use `const { isKeyed } = require('immutable')`
     */
function isKeyed(maybeKeyed: any): maybeKeyed is Collection.Keyed<any, any>;


/**
     * @deprecated use `const { isIndexed } = require('immutable')`
     */
function isIndexed(maybeIndexed: any): maybeIndexed is Collection.Indexed<any>;


/**
     * @deprecated use `const { isAssociative } = require('immutable')`
     */
function isAssociative(maybeAssociative: any): maybeAssociative is Collection.Keyed<any, any> | Collection.Indexed<any>;


/**
     * @deprecated use `const { isOrdered } = require('immutable')`
     */
function isOrdered(maybeOrdered: any): boolean;


/**
     * Creates a Collection.Keyed
     *
     * Similar to `Collection()`, however it expects collection-likes of [K, V]
     * tuples if not constructed from a Collection.Keyed or JS Object.
     *
     * Note: `Collection.Keyed` is a conversion function and not a class, and
     * does not use the `new` keyword during construction.
     */
export function Keyed<K, V>(collection: Iterable<[K, V]>): Collection.Keyed<K, V>;


export function Keyed<V>(obj: {[key: string]: V}): Collection.Keyed<string, V>;


/**
     * Creates a new Collection.Indexed.
     *
     * Note: `Collection.Indexed` is a conversion function and not a class, and
     * does not use the `new` keyword during construction.
     */
export function Indexed<T>(collection: Iterable<T>): Collection.Indexed<T>;


/**
     * Similar to `Collection()`, but always returns a Collection.Set.
     *
     * Note: `Collection.Set` is a factory function and not a class, and does
     * not use the `new` keyword during construction.
     */
export function Set<T>(collection: Iterable<T>): Collection.Set<T>;


/**
   * Creates a Collection.
   *
   * The type of Collection created is based on the input.
   *
   *   * If an `Collection`, that same `Collection`.
   *   * If an Array-like, an `Collection.Indexed`.
   *   * If an Object with an Iterator defined, an `Collection.Indexed`.
   *   * If an Object, an `Collection.Keyed`.
   *
   * This methods forces the conversion of Objects and Strings to Collections.
   * If you want to ensure that a Collection of one item is returned, use
   * `Seq.of`.
   *
   * Note: An Iterator itself will be treated as an object, becoming a `Seq.Keyed`,
   * which is usually not what you want. You should turn your Iterator Object into
   * an iterable object by defining a Symbol.iterator (or @@iterator) method which
   * returns `this`.
   *
   * Note: `Collection` is a conversion function and not a class, and does not
   * use the `new` keyword during construction.
   */
export function Collection<I extends Collection<any, any>>(collection: I): I;


export function Collection<T>(collection: Iterable<T>): Collection.Indexed<T>;


export function Collection<V>(obj: {[key: string]: V}): Collection.Keyed<string, V>;


/**
   * Deeply converts plain JS objects and arrays to Immutable Maps and Lists.
   *
   * If a `reviver` is optionally provided, it will be called with every
   * collection as a Seq (beginning with the most nested collections
   * and proceeding to the top-level collection itself), along with the key
   * referring to each collection and the parent JS object provided as `this`.
   * For the top level, object, the key will be `""`. This `reviver` is expected
   * to return a new Immutable Collection, allowing for custom conversions from
   * deep JS objects. Finally, a `path` is provided which is the sequence of
   * keys to this value from the starting value.
   *
   * `reviver` acts similarly to the [same parameter in `JSON.parse`][1].
   *
   * If `reviver` is not provided, the default behavior will convert Objects
   * into Maps and Arrays into Lists like so:
   *
   * <!-- runkit:activate -->
   * ```js
   * const { fromJS, isKeyed } = require('immutable')
   * function (key, value) {
   *   return isKeyed(value) ? value.toMap() : value.toList()
   * }
   * ```
   *
   * `fromJS` is conservative in its conversion. It will only convert
   * arrays which pass `Array.isArray` to Lists, and only raw objects (no custom
   * prototype) to Map.
   *
   * Accordingly, this example converts native JS data to OrderedMap and List:
   *
   * <!-- runkit:activate -->
   * ```js
   * const { fromJS, isKeyed } = require('immutable')
   * fromJS({ a: {b: [10, 20, 30]}, c: 40}, function (key, value, path) {
   *   console.log(key, value, path)
   *   return isKeyed(value) ? value.toOrderedMap() : value.toList()
   * })
   *
   * > "b", [ 10, 20, 30 ], [ "a", "b" ]
   * > "a", {b: [10, 20, 30]}, [ "a" ]
   * > "", {a: {b: [10, 20, 30]}, c: 40}, []
   * ```
   *
   * Keep in mind, when using JS objects to construct Immutable Maps, that
   * JavaScript Object properties are always strings, even if written in a
   * quote-less shorthand, while Immutable Maps accept keys of any type.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { Map } = require('immutable')
   * let obj = { 1: "one" };
   * Object.keys(obj); // [ "1" ]
   * assert.equal(obj["1"], obj[1]); // "one" === "one"
   *
   * let map = Map(obj);
   * assert.notEqual(map.get("1"), map.get(1)); // "one" !== undefined
   * ```
   *
   * Property access for JavaScript Objects first converts the key to a string,
   * but since Immutable Map keys can be of any type the argument to `get()` is
   * not altered.
   *
   * [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter
   *      "Using the reviver parameter"
   */
export function fromJS(
    jsValue: any,
    reviver?: (
      key: string | number,
      sequence: Collection.Keyed<string, any> | Collection.Indexed<any>,
      path?: Array<string | number>
    ) => any
  ): any;


/**
   * Value equality check with semantics similar to `Object.is`, but treats
   * Immutable `Collection`s as values, equal if the second `Collection` includes
   * equivalent values.
   *
   * It's used throughout Immutable when checking for equality, including `Map`
   * key equality and `Set` membership.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { Map, is } = require('immutable')
   * const map1 = Map({ a: 1, b: 1, c: 1 })
   * const map2 = Map({ a: 1, b: 1, c: 1 })
   * assert.equal(map1 !== map2, true)
   * assert.equal(Object.is(map1, map2), false)
   * assert.equal(is(map1, map2), true)
   * ```
   *
   * `is()` compares primitive types like strings and numbers, Immutable.js
   * collections like `Map` and `List`, but also any custom object which
   * implements `ValueObject` by providing `equals()` and `hashCode()` methods.
   *
   * Note: Unlike `Object.is`, `Immutable.is` assumes `0` and `-0` are the same
   * value, matching the behavior of ES6 Map key equality.
   */
export function is(first: any, second: any): boolean;


/**
   * The `hash()` function is an important part of how Immutable determines if
   * two values are equivalent and is used to determine how to store those
   * values. Provided with any value, `hash()` will return a 31-bit integer.
   *
   * When designing Objects which may be equal, it's important that when a
   * `.equals()` method returns true, that both values `.hashCode()` method
   * return the same value. `hash()` may be used to produce those values.
   *
   * For non-Immutable Objects that do not provide a `.hashCode()` functions
   * (including plain Objects, plain Arrays, Date objects, etc), a unique hash
   * value will be created for each *instance*. That is, the create hash
   * represents referential equality, and not value equality for Objects. This
   * ensures that if that Object is mutated over time that its hash code will
   * remain consistent, allowing Objects to be used as keys and values in
   * Immutable.js collections.
   *
   * Note that `hash()` attempts to balance between speed and avoiding
   * collisions, however it makes no attempt to produce secure hashes.
   *
   * *New in Version 4.0*
   */
export function hash(value: any): number;


/**
   * True if `maybeImmutable` is an Immutable Collection or Record.
   *
   * Note: Still returns true even if the collections is within a `withMutations()`.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { isImmutable, Map, List, Stack } = require('immutable');
   * isImmutable([]); // false
   * isImmutable({}); // false
   * isImmutable(Map()); // true
   * isImmutable(List()); // true
   * isImmutable(Stack()); // true
   * isImmutable(Map().asMutable()); // true
   * ```
   */
export function isImmutable(maybeImmutable: any): maybeImmutable is Collection<any, any>;


/**
   * True if `maybeCollection` is a Collection, or any of its subclasses.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { isCollection, Map, List, Stack } = require('immutable');
   * isCollection([]); // false
   * isCollection({}); // false
   * isCollection(Map()); // true
   * isCollection(List()); // true
   * isCollection(Stack()); // true
   * ```
   */
export function isCollection(maybeCollection: any): maybeCollection is Collection<any, any>;


/**
   * True if `maybeKeyed` is a Collection.Keyed, or any of its subclasses.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { isKeyed, Map, List, Stack } = require('immutable');
   * isKeyed([]); // false
   * isKeyed({}); // false
   * isKeyed(Map()); // true
   * isKeyed(List()); // false
   * isKeyed(Stack()); // false
   * ```
   */
export function isKeyed(maybeKeyed: any): maybeKeyed is Collection.Keyed<any, any>;


/**
   * True if `maybeIndexed` is a Collection.Indexed, or any of its subclasses.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { isIndexed, Map, List, Stack, Set } = require('immutable');
   * isIndexed([]); // false
   * isIndexed({}); // false
   * isIndexed(Map()); // false
   * isIndexed(List()); // true
   * isIndexed(Stack()); // true
   * isIndexed(Set()); // false
   * ```
   */
export function isIndexed(maybeIndexed: any): maybeIndexed is Collection.Indexed<any>;


/**
   * True if `maybeAssociative` is either a Keyed or Indexed Collection.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { isAssociative, Map, List, Stack, Set } = require('immutable');
   * isAssociative([]); // false
   * isAssociative({}); // false
   * isAssociative(Map()); // true
   * isAssociative(List()); // true
   * isAssociative(Stack()); // true
   * isAssociative(Set()); // false
   * ```
   */
export function isAssociative(maybeAssociative: any): maybeAssociative is Collection.Keyed<any, any> | Collection.Indexed<any>;


/**
   * True if `maybeOrdered` is a Collection where iteration order is well
   * defined. True for Collection.Indexed as well as OrderedMap and OrderedSet.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { isOrdered, Map, OrderedMap, List, Set } = require('immutable');
   * isOrdered([]); // false
   * isOrdered({}); // false
   * isOrdered(Map()); // false
   * isOrdered(OrderedMap()); // true
   * isOrdered(List()); // true
   * isOrdered(Set()); // false
   * ```
   */
export function isOrdered(maybeOrdered: any): boolean;


/**
   * True if `maybeSorted` is a Collection where iteration order is well
   * defined by a comparator.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { isSorted, Map, SortedMap, List, Set } = require('immutable');
   * isSorted([]); // false
   * isSorted({}); // false
   * isSorted(Map()); // false
   * isSorted(SortedMap()); // true
   * isSorted(List()); // true
   * isSorted(Set()); // false
   * ```
   */
export function isSorted(maybeSorted: any): boolean;


/**
   * True if `maybeValue` is a JavaScript Object which has *both* `equals()`
   * and `hashCode()` methods.
   *
   * Any two instances of *value objects* can be compared for value equality with
   * `Immutable.is()` and can be used as keys in a `Map` or members in a `Set`.
   */
export function isValueObject(maybeValue: any): maybeValue is ValueObject;


/**
   * True if `maybeSeq` is a Seq.
   */
export function isSeq(maybeSeq: any): maybeSeq is Seq.Indexed<any> | Seq.Keyed<any, any> | Seq.Set<any>;


/**
   * True if `maybeList` is a List.
   */
export function isList(maybeList: any): maybeList is List<any>;


/**
   * True if `maybeMap` is a Map.
   *
   * Also true for OrderedMaps and SortedMaps.
   */
export function isMap(maybeMap: any): maybeMap is Map<any, any>;


/**
   * True if `maybeOrderedMap` is an OrderedMap.
   */
export function isOrderedMap(maybeOrderedMap: any): maybeOrderedMap is OrderedMap<any, any>;


/**
   * True if `maybeSortedMap` is an SortedMap.
   */
export function isSortedMap(maybeSortedMap: any): maybeSortedMap is SortedMap<any, any>;


/**
   * True if `maybeStack` is a Stack.
   */
export function isStack(maybeStack: any): maybeStack is Stack<any>;


/**
   * True if `maybeSet` is a Set.
   *
   * Also true for OrderedSets and SortedSets.
   */
export function isSet(maybeSet: any): maybeSet is Set<any>;


/**
   * True if `maybeOrderedSet` is an OrderedSet.
   */
export function isOrderedSet(maybeOrderedSet: any): maybeOrderedSet is OrderedSet<any>;


/**
   * True if `maybeSortedSet` is an SortedSet.
   */
export function isSortedSet(maybeSortedSet: any): maybeSortedSet is SortedSet<any>;


/**
   * True if `maybeRecord` is a Record.
   */
export function isRecord(maybeRecord: any): maybeRecord is Record<any>;


/**
   * Returns the value within the provided collection associated with the
   * provided key, or notSetValue if the key is not defined in the collection.
   *
   * A functional alternative to `collection.get(key)` which will also work on
   * plain Objects and Arrays as an alternative for `collection[key]`.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { get } = require('immutable')
   * get([ 'dog', 'frog', 'cat' ], 2) // 'frog'
   * get({ x: 123, y: 456 }, 'x') // 123
   * get({ x: 123, y: 456 }, 'z', 'ifNotSet') // 'ifNotSet'
   * ```
   */
export function get<K, V>(collection: Collection<K, V>, key: K): V | undefined;


export function get<K, V, NSV>(collection: Collection<K, V>, key: K, notSetValue: NSV): V | NSV;


export function get<TProps, K extends keyof TProps>(record: Record<TProps>, key: K, notSetValue: any): TProps[K];


export function get<V>(collection: Array<V>, key: number): V | undefined;


export function get<V, NSV>(collection: Array<V>, key: number, notSetValue: NSV): V | NSV;


export function get<C extends Object, K extends keyof C>(object: C, key: K, notSetValue: any): C[K];


export function get<V>(collection: {[key: string]: V}, key: string): V | undefined;


export function get<V, NSV>(collection: {[key: string]: V}, key: string, notSetValue: NSV): V | NSV;


/**
   * Returns true if the key is defined in the provided collection.
   *
   * A functional alternative to `collection.has(key)` which will also work with
   * plain Objects and Arrays as an alternative for
   * `collection.hasOwnProperty(key)`.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { has } = require('immutable')
   * has([ 'dog', 'frog', 'cat' ], 2) // true
   * has([ 'dog', 'frog', 'cat' ], 5) // false
   * has({ x: 123, y: 456 }, 'x') // true
   * has({ x: 123, y: 456 }, 'z') // false
   * ```
   */
export function has(collection: Object, key: any): boolean;


/**
   * Returns a copy of the collection with the value at key removed.
   *
   * A functional alternative to `collection.remove(key)` which will also work
   * with plain Objects and Arrays as an alternative for
   * `delete collectionCopy[key]`.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { remove } = require('immutable')
   * const originalArray = [ 'dog', 'frog', 'cat' ]
   * remove(originalArray, 1) // [ 'dog', 'cat' ]
   * console.log(originalArray) // [ 'dog', 'frog', 'cat' ]
   * const originalObject = { x: 123, y: 456 }
   * remove(originalObject, 'x') // { y: 456 }
   * console.log(originalObject) // { x: 123, y: 456 }
   * ```
   */
export function remove<K, C extends Collection<K, any>>(collection: C, key: K): C;


export function remove<TProps, C extends Record<TProps>, K extends keyof TProps>(collection: C, key: K): C;


export function remove<C extends Array<any>>(collection: C, key: number): C;


export function remove<C, K extends keyof C>(collection: C, key: K): C;


export function remove<C extends {[key: string]: any}, K extends keyof C>(collection: C, key: K): C;


/**
   * Returns a copy of the collection with the value at key set to the provided
   * value.
   *
   * A functional alternative to `collection.set(key, value)` which will also
   * work with plain Objects and Arrays as an alternative for
   * `collectionCopy[key] = value`.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { set } = require('immutable')
   * const originalArray = [ 'dog', 'frog', 'cat' ]
   * set(originalArray, 1, 'cow') // [ 'dog', 'cow', 'cat' ]
   * console.log(originalArray) // [ 'dog', 'frog', 'cat' ]
   * const originalObject = { x: 123, y: 456 }
   * set(originalObject, 'x', 789) // { x: 789, y: 456 }
   * console.log(originalObject) // { x: 123, y: 456 }
   * ```
   */
export function set<K, V, C extends Collection<K, V>>(collection: C, key: K, value: V): C;


export function set<TProps, C extends Record<TProps>, K extends keyof TProps>(record: C, key: K, value: TProps[K]): C;


export function set<V, C extends Array<V>>(collection: C, key: number, value: V): C;


export function set<C, K extends keyof C>(object: C, key: K, value: C[K]): C;


export function set<V, C extends {[key: string]: V}>(collection: C, key: string, value: V): C;


/**
   * Returns a copy of the collection with the value at key set to the result of
   * providing the existing value to the updating function.
   *
   * A functional alternative to `collection.update(key, fn)` which will also
   * work with plain Objects and Arrays as an alternative for
   * `collectionCopy[key] = fn(collection[key])`.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { update } = require('immutable')
   * const originalArray = [ 'dog', 'frog', 'cat' ]
   * update(originalArray, 1, val => val.toUpperCase()) // [ 'dog', 'FROG', 'cat' ]
   * console.log(originalArray) // [ 'dog', 'frog', 'cat' ]
   * const originalObject = { x: 123, y: 456 }
   * update(originalObject, 'x', val => val * 6) // { x: 738, y: 456 }
   * console.log(originalObject) // { x: 123, y: 456 }
   * ```
   */
export function update<K, V, C extends Collection<K, V>>(collection: C, key: K, updater: (value: V) => V): C;


export function update<K, V, C extends Collection<K, V>, NSV>(collection: C, key: K, notSetValue: NSV, updater: (value: V | NSV) => V): C;


export function update<TProps, C extends Record<TProps>, K extends keyof TProps>(record: C, key: K, updater: (value: TProps[K]) => TProps[K]): C;


export function update<TProps, C extends Record<TProps>, K extends keyof TProps, NSV>(record: C, key: K, notSetValue: NSV, updater: (value: TProps[K] | NSV) => TProps[K]): C;


export function update<V>(collection: Array<V>, key: number, updater: (value: V) => V): Array<V>;


export function update<V, NSV>(collection: Array<V>, key: number, notSetValue: NSV, updater: (value: V | NSV) => V): Array<V>;


export function update<C, K extends keyof C>(object: C, key: K, updater: (value: C[K]) => C[K]): C;


export function update<C, K extends keyof C, NSV>(object: C, key: K, notSetValue: NSV, updater: (value: C[K] | NSV) => C[K]): C;


export function update<V, C extends {[key: string]: V}, K extends keyof C>(collection: C, key: K, updater: (value: V) => V): {[key: string]: V};


export function update<V, C extends {[key: string]: V}, K extends keyof C, NSV>(collection: C, key: K, notSetValue: NSV, updater: (value: V | NSV) => V): {[key: string]: V};


/**
   * Returns the value at the provided key path starting at the provided
   * collection, or notSetValue if the key path is not defined.
   *
   * A functional alternative to `collection.getIn(keypath)` which will also
   * work with plain Objects and Arrays.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { getIn } = require('immutable')
   * getIn({ x: { y: { z: 123 }}}, ['x', 'y', 'z']) // 123
   * getIn({ x: { y: { z: 123 }}}, ['x', 'q', 'p'], 'ifNotSet') // 'ifNotSet'
   * ```
   */
export function getIn(collection: any, keyPath: Iterable<any>, notSetValue: any): any;


/**
   * Returns true if the key path is defined in the provided collection.
   *
   * A functional alternative to `collection.hasIn(keypath)` which will also
   * work with plain Objects and Arrays.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { hasIn } = require('immutable')
   * hasIn({ x: { y: { z: 123 }}}, ['x', 'y', 'z']) // true
   * hasIn({ x: { y: { z: 123 }}}, ['x', 'q', 'p']) // false
   * ```
   */
export function hasIn(collection: any, keyPath: Iterable<any>): boolean;


/**
   * Returns a copy of the collection with the value at the key path removed.
   *
   * A functional alternative to `collection.removeIn(keypath)` which will also
   * work with plain Objects and Arrays.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { removeIn } = require('immutable')
   * const original = { x: { y: { z: 123 }}}
   * removeIn(original, ['x', 'y', 'z']) // { x: { y: {}}}
   * console.log(original) // { x: { y: { z: 123 }}}
   * ```
   */
export function removeIn<C>(collection: C, keyPath: Iterable<any>): C;


/**
   * Returns a copy of the collection with the value at the key path set to the
   * provided value.
   *
   * A functional alternative to `collection.setIn(keypath)` which will also
   * work with plain Objects and Arrays.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { setIn } = require('immutable')
   * const original = { x: { y: { z: 123 }}}
   * setIn(original, ['x', 'y', 'z'], 456) // { x: { y: { z: 456 }}}
   * console.log(original) // { x: { y: { z: 123 }}}
   * ```
   */
export function setIn<C>(collection: C, keyPath: Iterable<any>, value: any): C;


/**
   * Returns a copy of the collection with the value at key path set to the
   * result of providing the existing value to the updating function.
   *
   * A functional alternative to `collection.updateIn(keypath)` which will also
   * work with plain Objects and Arrays.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { updateIn } = require('immutable')
   * const original = { x: { y: { z: 123 }}}
   * updateIn(original, ['x', 'y', 'z'], val => val * 6) // { x: { y: { z: 738 }}}
   * console.log(original) // { x: { y: { z: 123 }}}
   * ```
   */
export function updateIn<C>(collection: C, keyPath: Iterable<any>, updater: (value: any) => any): C;


export function updateIn<C>(collection: C, keyPath: Iterable<any>, notSetValue: any, updater: (value: any) => any): C;


/**
   * Returns a copy of the collection with the remaining collections merged in.
   *
   * A functional alternative to `collection.merge()` which will also work with
   * plain Objects and Arrays.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { merge } = require('immutable')
   * const original = { x: 123, y: 456 }
   * merge(original, { y: 789, z: 'abc' }) // { x: 123, y: 789, z: 'abc' }
   * console.log(original) // { x: 123, y: 456 }
   * ```
   */
export function merge<C>(
    collection: C,
    ...collections: Array<Iterable<any> | Iterable<[any, any]> | {[key: string]: any}>
  ): C;


/**
   * Returns a copy of the collection with the remaining collections merged in,
   * calling the `merger` function whenever an existing value is encountered.
   *
   * A functional alternative to `collection.mergeWith()` which will also work
   * with plain Objects and Arrays.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { mergeWith } = require('immutable')
   * const original = { x: 123, y: 456 }
   * mergeWith(
   *   (oldVal, newVal) => oldVal + newVal,
   *   original,
   *   { y: 789, z: 'abc' }
   * ) // { x: 123, y: 1245, z: 'abc' }
   * console.log(original) // { x: 123, y: 456 }
   * ```
   */
export function mergeWith<C>(
    merger: (oldVal: any, newVal: any, key: any) => any,
    collection: C,
    ...collections: Array<Iterable<any> | Iterable<[any, any]> | {[key: string]: any}>
  ): C;


/**
   * Returns a copy of the collection with the remaining collections merged in
   * deeply (recursively).
   *
   * A functional alternative to `collection.mergeDeep()` which will also work
   * with plain Objects and Arrays.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { mergeDeep } = require('immutable')
   * const original = { x: { y: 123 }}
   * mergeDeep(original, { x: { z: 456 }}) // { x: { y: 123, z: 456 }}
   * console.log(original) // { x: { y: 123 }}
   * ```
   */
export function mergeDeep<C>(
    collection: C,
    ...collections: Array<Iterable<any> | Iterable<[any, any]> | {[key: string]: any}>
  ): C;


/**
   * Returns a copy of the collection with the remaining collections merged in
   * deeply (recursively), calling the `merger` function whenever an existing
   * value is encountered.
   *
   * A functional alternative to `collection.mergeDeepWith()` which will also
   * work with plain Objects and Arrays.
   *
   * <!-- runkit:activate -->
   * ```js
   * const { mergeDeepWith } = require('immutable')
   * const original = { x: { y: 123 }}
   * mergeDeepWith(
   *   (oldVal, newVal) => oldVal + newVal,
   *   original,
   *   { x: { y: 456 }}
   * ) // { x: { y: 579 }}
   * console.log(original) // { x: { y: 123 }}
   * ```
   */
export function mergeDeepWith<C>(
    merger: (oldVal: any, newVal: any, key: any) => any,
    collection: C,
    ...collections: Array<Iterable<any> | Iterable<[any, any]> | {[key: string]: any}>
  ): C;


export interface SortedMap<K, V> extends Map<K, V> {

    /**
    * The number of entries (key/value pairs) in this SortedMap.
    */
   readonly size: number;

    // Persistent changes

    /**
     * Returns a new `SortedMap` containing the entries of the provided
     * collection-like. The entries 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 `SortedMap` will be reorganized into an optimized tree structure.
     *
     * The pack procedure is actually called from the `SortedMap` constructor
     * as it is usually faster than a series of set operations. It is recommended
     * to explicitly call this method after a large batch of update or delete operations
     * to release a portion of the allocated memory and to speed up the consequent get
     * operations.
     */
    pack(collection?: Iterable<[K, V]>): this;

    // Deep persistent changes

    // Transient changes

    // Reading values

    /**
     * Returns a sequence representing a portion of this sorted map starting with a specific key
     * up to the last entry in the sorted  map.
     * If the optional parameter backwards is set to true, the returned sequence will
     * list the entries backwards, starting with key down to the first entry in the sorted map,

     * Example:
     * ```js
     * > const abc = SortedMap([["A", "a"], ["B", "b"], ["C", "c"], ["D", "d"], ["E", "e"], ["F", "f"], ["G", "g"], ["H", "h"], ["I", "i"], ["J", "j"], ["K", "k"], ["L", "l"], ["M", "m"], ["N", "n"], ["O", "o"], ["P", "p"], ["Q", "q"], ["R", "r"], ["S", "s"], ["T", "t"], ["U", "u"], ["V", "v"], ["W", "w"], ["X", "x"], ["Y", "y"], ["Z", "z"]]);
     *
     * > abc.from("R");
     * Seq { "R": "r", "S": "s", "T": "t", "U": "u", "V": "v", "W": "w", "X": "x", "Y": "y", "Z": "z" }
     *
     * > abc.from("R", true);
     * Seq { "R": "r", "Q": "q", "P": "p", "O": "o", "N": "n", "M": "m", "L": "l", "K": "k", "J": "j", "I": "i", "H": "h", "G": "g", "F": "f", "E": "e", "D": "d", "C": "c", "B": "b", "A": "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": "r", "S": "s", "T": "t", "U": "u", "V": "v" }
     *
     * > abc.from("R").takeWhile((v, k) => k < "W");
     * Seq { "R": "r", "S": "s", "T": "t", "U": "u", "V": "v" }
     *
     * > abc.from("R", true).take(5);
     * Seq { "R": "r", "Q": "q", "P": "p", "O": "o", "N": "n" }
     *
     * > abc.from("R", true).takeWhile((v, k) => k > "K");
     * Seq { "R": "r", "Q": "q", "P": "p", "O": "o", "N": "n", "M": "m", "L": "l" }
     * ```
     */
    from(key: K, backwards?: boolean): Seq<K, V>;

    /**
     * Returns a sequence representing a portion of this sorted map 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
     * > const abc = SortedMap([["A", "a"], ["B", "b"], ["C", "c"], ["D", "d"], ["E", "e"], ["F", "f"], ["G", "g"], ["H", "h"], ["I", "i"], ["J", "j"], ["K", "k"], ["L", "l"], ["M", "m"], ["N", "n"], ["O", "o"], ["P", "p"], ["Q", "q"], ["R", "r"], ["S", "s"], ["T", "t"], ["U", "u"], ["V", "v"], ["W", "w"], ["X", "x"], ["Y", "y"], ["Z", "z"]]);
     *
     * > abc.fromIndex(4).take(5);
     * Seq { "E": "e", "F": "f", "G": "g", "H": "h", "I": "i" }
     *
     * > abc.fromIndex(4, true).take(5);
     * Seq { "E": "e", "D": "d", "C": "c", "B": "b", "A": "a" }
     * ```
     */
    fromIndex(index: number, backwards?: boolean): Seq<K, V>;

    /**
     * Prints out the internal Btree structure of the SortedMap.
     * Keeps printing the nodes recursively until `maxDepth` level is reached.
     *
     * ```js
     * const { SortedMap } = require('immutable-sorted')
     * const aSortedMap = Range(0, 8).toSortedMap(undefined, {btreeOrder: 4});
     * sortedMap.print();
     *
     * + LEAF[0] (L0)
     *     - ENTRY[0]: 0
     *     - ENTRY[1]: 1
     * - ENTRY[0]: 2
     * + LEAF[1] (L0)
     *     - ENTRY[0]: 3
     *     - ENTRY[1]: 4
     * - ENTRY[1]: 5
     * + LEAF[2] (L0)
     *     - ENTRY[0]: 6
     *     - ENTRY[1]: 7
     *
     * ```
     *
     */
    print(maxDepth?: number): this;
  }


export interface OrderedMap<K, V> extends Map<K, V> {

    /**
     * The number of entries in this OrderedMap.
     */
    readonly size: number;

    /**
     * Returns a new OrderedMap also containing the new key, value pair. If an
     * equivalent key already exists in this OrderedMap, it will be replaced
     * while maintaining the existing order.
     *
     * <!-- runkit:activate -->
     * ```js
     * const { OrderedMap } = require('immutable')
     * const originalMap = OrderedMap({a:1, b:1, c:1})
     * const updatedMap = originalMap.set('b', 2)
     *
     * originalMap
     * // OrderedMap {a: 1, b: 1, c: 1}
     * updatedMap
     * // OrderedMap {a: 1, b: 2, c: 1}
     * ```
     *
     * Note: `set` can be used in `withMutations`.
     */
    set(key: K, value: V): this;

    /**
     * Returns a new OrderedMap resulting from merging the provided Collections
     * (or JS objects) into this OrderedMap. In other words, this takes each
     * entry of each collection and sets it on this OrderedMap.
     *
     * Note: Values provided to `merge` are shallowly converted before being
     * merged. No nested values are altered.
     *
     * <!-- runkit:activate -->
     * ```js
     * const { OrderedMap } = require('immutable')
     * const one = OrderedMap({ a: 10, b: 20, c: 30 })
     * const two = OrderedMap({ b: 40, a: 50, d: 60 })
     * one.merge(two) // OrderedMap { "a": 50, "b": 40, "c": 30, "d": 60 }
     * two.merge(one) // OrderedMap { "b": 20, "a": 10, "d": 60, "c": 30 }
     * ```
     *
     * Note: `merge` can be used in `withMutations`.
     *
     * @alias concat
     */
    merge<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): OrderedMap<K | KC, V | VC>;
    merge<C>(...collections: Array<{[key: string]: C}>): OrderedMap<K | string, V | C>;
    concat<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): OrderedMap<K | KC, V | VC>;
    concat<C>(...collections: Array<{[key: string]: C}>): OrderedMap<K | string, V | C>;

    // Sequence algorithms

    /**
     * Returns a new OrderedMap with values passed through a
     * `mapper` function.
     *
     *     OrderedMap({ a: 1, b: 2 }).map(x => 10 * x)
     *     // OrderedMap { "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
    ): OrderedMap<K, M>;

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

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

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

    /**
     * Returns a new OrderedMap 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
    ): OrderedMap<K, F>;
    filter(
      predicate: (value: V, key: K, iter: this) => any,
      context?: any
    ): this;

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


export interface Set<T> extends Collection.Set<T> {

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

    // Persistent changes

    /**
     * Returns a new Set which also includes this value.
     *
     * Note: `add` can be used in `withMutations`.
     */
    add(value: T): this;

    /**
     * Returns a new Set which excludes this value.
     *
     * Note: `delete` can be used in `withMutations`.
     *
     * Note: `delete` **cannot** be safely used in IE8, use `remove` if
     * supporting old browsers.
     *
     * @alias remove
     */
    delete(value: T): this;
    remove(value: T): this;

    /**
     * Returns a new Set containing no values.
     *
     * Note: `clear` can be used in `withMutations`.
     */
    clear(): this;

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

    /**
     * Returns a Set which has removed any values not also contained
     * within `collections`.
     *
     * Note: `intersect` can be used in `withMutations`.
     */
    intersect(...collections: Array<Iterable<T>>): this;

    /**
     * Returns a Set excluding any values contained within `collections`.
     *
     * <!-- runkit:activate -->
     * ```js
     * const { OrderedSet } = require('immutable')
     * OrderedSet([ 1, 2, 3 ]).subtract([1, 3])
     * // OrderedSet [2]
     * ```
     *
     * Note: `subtract` can be used in `withMutations`.
     */
    subtract(...collections: Array<Iterable<T>>): this;

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

    /**
     * Flat-maps the Set, returning a new Set.
     *
     * Similar to `set.map(...).flatten(true)`.
     */
    flatMap<M>(
      mapper: (value: T, key: T, iter: this) => Iterable<M>,
      context?: any
    ): Set<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, key: T, iter: this) => value is F,
      context?: any
    ): Set<F>;
    filter(
      predicate: (value: T, key: T, iter: this) => any,
      context?: any
    ): this;
  }