Full Code of devlucky/Kakapo.js for AI

master a578cc918d92 cached
69 files
305.8 KB
87.6k tokens
107 symbols
1 requests
Download .txt
Showing preview only (325K chars total). Download the full file or copy to clipboard to get everything.
Repository: devlucky/Kakapo.js
Branch: master
Commit: a578cc918d92
Files: 69
Total size: 305.8 KB

Directory structure:
gitextract_xt59y45s/

├── .editorconfig
├── .eslintrc
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── __tests__/
│   ├── data/
│   │   └── users.ts
│   ├── database_spec.ts
│   ├── request_spec.ts
│   ├── response_spec.ts
│   ├── router_spec.ts
│   └── server_spec.ts
├── create-readme.js
├── examples/
│   ├── dummy/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── bower.json
│   │   ├── index.html
│   │   └── package.json
│   ├── github-explorer/
│   │   ├── .firebaserc
│   │   ├── README.md
│   │   ├── database.rules.json
│   │   ├── firebase.json
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── styles.css
│   │   └── styles.scss
│   ├── react/
│   │   ├── .nvmrc
│   │   ├── example/
│   │   │   ├── app.tsx
│   │   │   ├── index.html
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── package.json
│   │   └── tsconfig.json
│   └── todo-app/
│       ├── .firebaserc
│       ├── README.md
│       ├── database.rules.json
│       ├── firebase.json
│       ├── index.html
│       └── package.json
├── flow-typed/
│   └── npm/
│       ├── jest_v22.x.x.js
│       └── lodash_v4.x.x.js
├── jest.config.js
├── jestFrameworkSetup.js
├── md/
│   ├── end.md
│   └── start.md
├── package.json
├── perf/
│   └── index.js
├── src/
│   ├── Database/
│   │   └── index.ts
│   ├── Request/
│   │   └── index.ts
│   ├── Response/
│   │   └── index.ts
│   ├── Router/
│   │   └── index.ts
│   ├── Server/
│   │   └── index.ts
│   ├── config/
│   │   └── environment.ts
│   ├── index.ts
│   ├── interceptors/
│   │   ├── fetchInterceptor.ts
│   │   ├── index.ts
│   │   ├── interceptorHelper.ts
│   │   └── xhrInterceptor.ts
│   ├── serializers/
│   │   ├── index.ts
│   │   └── json-api.ts
│   └── utils.ts
├── tsconfig.dist.json
├── tsconfig.json
├── typings/
│   ├── parse-url/
│   │   └── index.d.ts
│   ├── path-match/
│   │   └── index.d.ts
│   └── query-string/
│       └── index.d.ts
├── webpack.config.js
└── webpack.perf.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

[{*.js, *.json, *.yml}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false

[Makefile]
indent_style = tab


================================================
FILE: .eslintrc
================================================
{
  "parser":  "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 2018,
    "sourceType":  "module"
  },
  "rules": {
    "indent": ["error", 2],
    "typescript/no-explicit-any": "off",
    "typescript/explicit-function-return-type": "off"
  }
}

================================================
FILE: .gitignore
================================================
*~
.directory
.Trash-*
logs
*.log
pids
*.pid
*.seed
lib-cov
.lock-wscript
build/Release
node_modules
dist/
npm-debug.log
npm-debug.log*
.DS_Store
.AppleDouble
.LSOverride
Icon
._*
.Spotlight-V100
.Trashes
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
*.sublime-workspace
sftp-config.json
lib
package-lock.json
coverage
.vscode
/.idea
/examples/**/*.js


================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
  - '8'
cache: yarn
script:
  - yarn
  - yarn test:ci
notifications:
  email: false

================================================
FILE: CHANGELOG.md
================================================

n.n.n / 2016-06-16
==================

  * Merge pull request #121 from devlucky/feature/disconnect
  * v0.2.0

v0.2.0 / 2016-06-13
===================

  * v0.2.0
  * Implement disconnect feature
  * Merge pull request #120 from devlucky/chore/record_factory_side_effects
  * Ensure Interceptors response doesn't contain record-factory methods
  * Merge pull request #118 from devlucky/bugfix/update_demo
  * Adapt kakapo changes in demos
  * Merge pull request #117 from devlucky/bugfix/not_require_index_module
  * v0.1.4

v0.1.4 / 2016-06-12
===================

  * v0.1.4
  * Dont require index option
  * Merge pull request #115 from devlucky/docs_update

docs_update / 2016-06-12
========================

  * Update docs
  * Merge pull request #109 from devlucky/chore/integration_tests
  * Adapt specs to new response type
  * Remove shared state between tests
  * Improve jQuery coverage
  * Handling body for xhr request
  * Merge remote-tracking branch 'origin/master' into chore/integration_tests
  * Merge pull request #113 from devlucky/relase-0.1.3
  * basic jquery and superagent support
  * Integration specs structure

relase-0.1.3 / 2016-06-08
=========================

  * v0.1.3

v0.1.3 / 2016-06-08
===================

  * v0.1.3
  * Update Readme
  * Merge pull request #112 from devlucky/chore/keywords
  * Add keywords and fix table of contents
  * Merge pull request #110 from devlucky/example/dummy
  * Merge remote-tracking branch 'origin/master' into example/dummy
  * Update dummy readme
  * Ignore dist
  * Update Readme
  * Fix entry point for npm package
  * Bower dummy integration
  * Merge pull request #111 from devlucky/chore/bower
  * Add bower support
  * Dummy example draft
  * Merge pull request #106 from devlucky/add_demo_links_to_readmes

add_demo_links_to_readmes / 2016-06-04
======================================

  * Update README
  * Add Demos links to Readme

add / 2016-06-02
================

  * Merge pull request #105 from devlucky/chore/deploy_demo_apps
  * Deploy demo apps to Firebase
  * Merge pull request #91 from devlucky/feature/scenarios
  * fix tests
  * Check that scenarios works with xhr
  * Use helpers instead of 'this'
  * Introduce KakapoRequest
  * Merge remote-tracking branch 'origin/master' into feature/scenarios
  * Adapt specs to the new scenario api
  * Intercept requests in the right moment
  * Merge pull request #95 from devlucky/chore/readme-generation
  * Readme autogeneration
  * Merge pull request #94 from devlucky/baseInterceptor/separate-from-strategies
  * Refactor interceptors, so they are not THAT tighly coupled with helpers
  * Make xhrInterceptor a little cleaner, move utils to helpers
  * Remove not needed functions and move from other files
  * Add xhrInterceptor.spec to specs exports
  * Create spec for xhrInterceptor
  * Pass db to request handler
  * Merge pull request #90 from devlucky/chore/add_npm_version_badge
  * Remove disclaimer
  * Relaser setup
  * Merge pull request #88 from devlucky/chore/relaser_integration
  * 0.1.2

v0.1.2 / 2016-05-20
===================

  * 0.1.2
  * Fix current version
  * Merge remote-tracking branch 'origin/master' into chore/relaser_integration
  * Fix build_command
  * [Example] GitHub explorer (#83)
  * Merge pull request #89 from devlucky/oskarcieslik-patch-1
  * Update README.md
  * Merge branch 'master' into chore/relaser_integration
  * Merge pull request #87 from devlucky/patch-1
  * Relaser setup
  * Change entry point in package.json to lib/
  * Merge pull request #84 from devlucky/bugfix/apply_xhr_instance_attributes
  * Merge branch 'master' into bugfix/apply_xhr_instance_attributes
  * Merge pull request #86 from devlucky/oskarcieslik-patch-1-1
  * Update README.md
  * Merge pull request #79 from devlucky/example/todo-app
  * docs(Example/Todo-app): Example app
  * chore(package.json): new build script
  * chore(makefile): New build script
  * chore(project): no dist/ in project
  * feat(todo-app/kakapo-config): Add more generated data
  * feat(todo-app/kakapo-config): Add some faker generated data :zap:
  * Apply all xhr instance properties and methods
  * Merge remote-tracking branch 'origin/master' into example/todo-app
  * Render after destroy todos
  * Merge pull request #82 from devlucky/feature/delete_record
  * Implement record.delete()
  * Delete todo
  * Implement record.delete()
  * Toggle all
  * Update TODO's
  * Merge pull request #80 from devlucky/bugfix/fetch_interceptor_request_url
  * Handle record creation
  * Decorate record on push
  * Support Request url in fetch interceptor
  * Todo app first draft
  * Support Request url in fetch interceptor
  * Merge pull request #76 from devlucky/documentation/util
  * docs(helpers/util): Add documentation for helpers/util
  * Merge pull request #75 from devlucky/documentation/recordFactory
  * docs(database/recordFactory): Add documentation for recordFactory
  * Merge pull request #74 from devlucky/documentation/database
  * Merge branch 'master' into documentation/database
  * docs(database): Fix documentation a bit in style
  * Merge pull request #73 from devlucky/documentation/database
  * docs(database): Create documentation for Database
  * Merge pull request #72 from devlucky/database/refactor-stores
  * test(database): remove unused tests
  * refactor(database/uuidStore): create registration for uuidStore
  * fix(database/find): Fix serialize function call to have collectionName on it
  * style(styling):
  * style(database + recordFactory): styling]
  * test(database): Remove test for factoryFor
  * fix(database/hasMany): hasMany should be in range [1, len(all)]
  * refactor(database/factoryFor|serializerFor): Rename methods to better tell purpose
  * style(database/order): Order methods alphabetically
  * refactor(database/serializers): Separate concerns of serialize & other methods
  * refactor(database/serializers): Separate concerns of serialize & other methods
  * refactor(database/whole): More code removal, better practices implementation
  * refactor(database/uuidStore + database/whole): Move uuid to it's own store. Remove unnecessary metho
  * refactor(database/factoryStore|serializerStore): Move factories and serializers outside of Database
  * refactor(database/store): Move records' store outside of database, replace with weakmaps + maps
  * Merge pull request #71 from devlucky/test/runners--all-specs
  * chore(test/runners): By default let's have runners call ALL specs

v0.0.1 / 2016-05-10
===================

  * Merge pull request #70 from devlucky/project/style-fixes
  * style(serializers/json-api): fixes according to airbnb-javascript guide
  * style(serializers/index): fixes according to airbnb-javascript guide
  * style(router): fixes according to airbnb-javascript guide
  * style(interceptors/xhrInterceptor): fixes according to airbnb-javascript guide
  * style(interceptors/index): fixes according to airbnb-javascript guide
  * style(interceptors/fetchInterceptor): fixes according to airbnb-javascript guide
  * style(interceptors/baseInterceptor): fixes according to airbnb-javascript guide
  * style(helpers/util): fixes according to airbnb-javascript guide
  * style(database/recordFactory): fixes according to airbnb-javascript guide
  * fix(database): Fix missing return statement
  * fix(test/database): fix name change from previous style changes
  * style(database): fixes according to airbnb-javascript guide
  * style(database): fixes according to airbnb-javascript guide
  * Update README.md

v0.0.0 / 2016-05-08
===================

  * Merge pull request #67 from devlucky/database/first-last
  * test(Database/first+last): Add tests for Database.first and Database.last
  * refactor(database/first+last): Add check for presence of factory
  * fix(version): Update npm + github version of package
  * fix(semantic-release): Fix semrel
  * 0.0.0
  * feat(Makefile & semantic-release): Move semantic-release to Makefile & remove npm publish for now
  * feat(Database): Database now have (find + findOne) instead of (find + filter)
  * chore(commitizen): Add run-config for commitizen
  * fix(package.json): Add missing coma
  * chore(semantic-release): Replaced relaser with semantic-release
  * chore(codecov.io): Add codecov again, somehow disappeared?!
  * Merge pull request #65 from devlucky/database/find
  * fix(Fix tests typos):
  * fix(specs/serializers): Fix new database methods
  * refactor(database/find): Change filter method to find
  * refactor(database/findOne): Change find method to findOne
  * chore(package.json): Add script for karma-watch
  * style(specs): Improve specs according to Airbnb's styleguide
  * style(runners/travis): Stop using lodash just for iterating specs
  * style(runners/karma): Improve karma runner
  * style(test/index.html):
  * style(runners/browser): Improve browser runner
  * chore(Makefile): Extract some parts of commands to VARIABLEs
  * chore(Makefile): Replace scripts with Makefile
  * chore(scripts): Remove scripts dir
  * chore(gitignore): Fix coverage dir again
  * chore(test_bundle): Remove test_bundle.js from git
  * chore(gitignore): Fix path to test dir
  * chore(test-coverage): Update reports dir
  * chore(eslint): Update deprecated config. Install config modules
  * chore(editorconfig): Add editor config to project
  * docs(LICENSE): Nicer LICENSE file
  * chore(project): Remove playground
  * chore(project/dist): Remove dist directory
  * chore(webpack): Add loaders to webpack & actually install their npm packages
  * fix(package.json): move some dependencies to dev deps
  * refactor(test): mv tests => test
  * fix(.gitignore): Fix path to test_bundle
  * chore(Add test_bundle to .gitignore):
  * chore(Add npm logs to .gitignore):
  * Merge branch 'master' of github.com:devlucky/Kakapo.js
  * chore(.gitignore): Extend gitignore
  * Merge pull request #60 from devlucky/interceptor/nativeServices
  * refactor(interceptors): Take use of those nativeServices helper.
  * Merge branch 'master' of github.com:devlucky/Kakapo.js
  * Project/refactor structure (#59)
  * refactor(project): Improve project's structure to follow modern node apps
  * refactor(project): Improve project's structure to follow modern node apps
  * Merge branch 'master' of github.com:devlucky/Kakapo.js
  * refactor(interceptors): Improve interceptors structure (#58)
  * refactor(interceptors): Improve interceptors structure
  * Merge pull request #57 from devlucky/database/refactor
  * refactor(specs): Change request delay to 1s for quicker tests
  * fix(package.json): Fix packages versions causing errors in travis-ci
  * fix(database/hasMany): Quick fix for limit of hasMany, this was making our tests fail at random
  * refactor(database/hasMany):
  * style(database/all):
  * refactor(database/hasMany):
  * refactor(database/belongsTo):
  * test(database/nested-find database/nested-filter): Test find / filter with nested conditions.
  * Merge pull request #48 from devlucky/feature/db_relationships
  * Merge remote-tracking branch 'origin/master' into feature/db_relationships
  * Rename last by lastItem
  * Merge pull request #55 from devlucky/database/nested-factories
  * Add tests for nested properties
  * ...
  * Add recursive factory mapping
  * Merge pull request #46 from devlucky/router/requestDelay
  * Merge branch 'master' into router/requestDelay
  * Fix mutability bug
  * Implement Database relationships
  * Merge pull request #41 from devlucky/feature/serializers
  * Serializer improvements
  * Separate router configs, add requestDelay option
  * Return undefined in factoryFor
  * Merge remote-tracking branch 'origin/master' into feature/serializers
  * Fix serializer
  * Update router.js
  * Merge pull request #45 from devlucky/router/additional-options
  * Change undefined to null. Tests using some valid url
  * Add functionality to specify host
  * Add functionality to specify host
  * Don't mutate default config
  * Update README.md
  * New slack team
  * Change ES6 Object's static methods to lodash alternatives
  * Merge pull request #38 from devlucky/database/pass-records-as-copy
  * Serializers draft
  * Better order of parameters
  * Records are now passed as copies
  * Merge pull request #36 from devlucky/database/safer-tests
  * Merge pull request #37 from devlucky/scripts/refactor
  * Fix package.json
  * Move scripts into separate files
  * Run code coverage only on travis
  * Add checks for factory presence to more functions, also tests
  * Make database tests safer
  * Implement record factory for database (#33)
  * Add slack notifications
  * Add codecov coverage
  * Merge pull request #32 from devlucky/response/fix-coverage
  * Tests for response.error and response.ok
  * Refactor error()
  * Merge pull request #31 from devlucky/tests/code-coverage
  * Add code-coverage with automatic codecove.io report
  * Separate tests into modules, also provide workflow just for travis
  * Abstract fakeXMLHttpRequest & fakeFetch functionality (#28)
  * Merge pull request #29 from devlucky/router/refactor-router
  * Remove request, change with register
  * Refactor router just a little
  * Implement database's record population (#21)
  * :tada:
  * Align code with new structure
  * Merge remote-tracking branch 'origin/master' into feature/rich_response_support
  * Add slack to travis
  * typo in scripts
  * Change script names a little, add support for multiple runs karma
  * Change package.json due to new structure
  * Separate tape-dom with karma, remove index.js
  * move index.html & fixtures to browser folder, better structure
  * move index.html & fixtures to browser folder, better structure
  * Make specs more modular, better structure
  * this is my last typo in .travis.yml
  * another typo in .travis.yml
  * typo in .travis.yml
  * Merge branch 'master' of github.com:devlucky/Kakapo.js
  * EHH... Updating firefox on travis...
  * Update README.md
  * Change karma launcher to firefox, since travis doesnt have chrome
  * Fix travis' yaml file
  * Support for Travis-CI with karma test-runner
  * Merge branch 'master' of github.com:devlucky/Kakapo.js
  * Change tests for travis
  * Add comments for tape-dom
  * Add some docs...
  * Add some docs...
  * Clean up tests for further travis-ci integration
  * Run npm scripts with npm-run-all to kill all scripts on ctrl-c
  * Support Request headers
  * Implement response headers support
  * Merge remote-tracking branch 'origin/master' into feature/rich_response_support
  * Merge pull request #17 from devlucky/feature/return_response_instances_in_fakeFetch
  * Use const for fakeResponse function
  * Response headers wip
  * Introduce Response concept
  * Make tests support Fetch Api
  * Return Response instances for fakeFetch
  * Clean fetch.js, Parse query
  * Some more ES6 goodness, Support for query
  * Support request query handling
  * Return request params in request handler
  * Return request body in handler
  * Intercept XHMLHttpRequest
  * Implement Interceptors concept
  * Improving Router coverage
  * Working on interceptor...
  * Remove wip
  * Change scripts to run concurrently since serve is watching
  * Change python server to npm serve
  * Script to run tests in one tab
  * Add missing dev-dependency
  * Update README.md
  * Improve coverage for DB
  * DB first draft
  * remove ghooks
  * Fix environment
  * 0.1.1

v0.1.1 / 2016-04-06
===================

  * 0.1.1
  * Initial commit

================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2016 @oskarcieslik - @zzarcon (https://github.com/devlucky)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: README.md
================================================
# Kakapo.js <img src="https://sdl-stickershop.line.naver.jp/products/0/0/1/1087538/LINEStorePC/main.png?__=20150924" width="40" height="40" >
[![Build Status](https://travis-ci.org/devlucky/Kakapo.js.svg?branch=master)](https://travis-ci.org/devlucky/Kakapo.js)
[![codecov.io](https://codecov.io/github/devlucky/Kakapo.js/coverage.svg?branch=master)](https://codecov.io/github/devlucky/Kakapo.js?branch=master)
[![npm version](https://badge.fury.io/js/kakapo.svg)](https://npmjs.com/package/kakapo)
[![dependencies](https://david-dm.org/devlucky/Kakapo.js.svg)](https://david-dm.org/devlucky/Kakapo.js)
[![npm license](https://img.shields.io/npm/l/awesome-badges.svg)](https://tldrlegal.com/license/mit-license)
<img src="http://benschwarz.github.io/bower-badges/badge@2x.png" width="130" height="25">

> Next generation mocking framework in Javascript - [docs](http://devlucky.github.io/kakapo-js) 

## Contents
- [Getting started](#getting-started)
  - [Installation](#installation)
- [Examples](#examples)
  - [Basic](#basic)
  - [Using the DB](#using-the-db)
  - [Unchaining the Router](#unchaining-the-router)
  - [Fetch & XMLHttpRequest support](#fetch--xmlhttprequest-support)
  - [Database candyness](#database-candyness)
  - [Passthrough](#passthrough)
- [Demo Apps](#demo-apps)
  - [TODO App](#todo-app)
  - [Github explorer](#github-explorer)
- [Components](#components)
  - [Server](#server)
  - [Router](#router)
  - [Database](#database)
  - [Response](#response)
  - [Serializers](#serializers)
  - [Interceptors](#interceptors)
  - [Scenarios](#scenarios)
  - [Fake data](#fake-data)
- [Browser support](#browser-support)
- [Roadmap](#roadmap)

Kakapo its a full featured http mocking library, he allows you to entirely replicate your backend logic in simple and declaritive way directly in the browser. This way you can easily prototype and develop the whole Application without backend and just deactivate Kakapo when you go production. In order to achieve that Kakapo gives you a set of utilities like Routing, Database, Response, Request and so on...

## Installation

`$ npm i kakapo -D`

`$ bower i kakapo -D`


# Examples

Before going deep into the Kakapo docs, we want to show you some examples of how to use Kakapo in your apps, in order to demonstrate how easy to integrate it is

## Basic

Use the kakapo router to declare two custom routes and returning custom data.

```javascript
import {Router, Server} from 'Kakapo';
  
const router = new Router();

router.get('/users', _ => {
  return [{
    id: 1,
    name: 'Hector'
  }, {
    id: 2,
    name: 'Zarco'
  }]
});

router.get('/users/:user_id', request => {
  const userId = request.params.user_id;
  return [{
    id: userId,
    name: 'Hector'
  }];
});

const server = new Server();

server.use(router);

fetch('/users', users => {
  console.log(users[0].id === 1);
  console.log(users[1].id === 2);
});

fetch('/users/3', user => {
  console.log(user.id === 3);
  console.log(user.name === 'Hector');
});
```  

### Using the DB
  
Combine the usage of the Router and the Database to have a more consistent way of managing the mock data. In the following example we are defining the user factory and later using some access methods provided by the db.

```javascript
import {Database, Router, Server} from 'Kakapo';

const db = new Database();

db.register('user', () => ({
  firstName: 'Hector',
  lastName: 'Zarco'
}));
db.create('user', 10);

const router = new Router();

router.get('/users', (request, db) => {
  return db.all('user');
});

router.get('/users/:user_id', (request, db) => {
  const userId = request.params.user_id;
  return db.findOne('user', userId);
});

const server = new Server();

server.use(db);
server.use(router);

fetch('/users', users => {
  console.log(users[0].id === 1);
  console.log(users[1].id === 2);
  console.log(users[2].id === 3);
});

fetch('/users/7', user => {
  console.log(user.id === 7);
  console.log(user.name === 'Hector');
});
```  

As you can see, the database automatically handles the **id** generation, so you don't have to worry about assigning incremental id's of any kind.

### Unchaining the Router

Next you will see how to use other features of the router and figure out the things you can build with it. In this example we show you how easy is to create a fake pagination handling, which is based in the actual requested page. 

```javascript
import {Router, Server} from 'Kakapo';
  
const router = new Router();

router.get('/users', (request) => {
  const currentPage = request.query.page;
  let count = request.query.count;
  let users = []

  while (--count) {
    users.push({name: 'hector', age: 24});
  }

  return {
    data: users,
    metadata: {
      previous_page: currentPage - 1,
      current_page: currentPage,
      next_page: currentPage + 1
    }
  }
});

router.post('/users/:user_id/friends/:friend_id', (request) => {
  const token = request.headers.get('X-auth-token');
  const userId = request.params.friend_id;
  const friendId = request.params.friend_id;
  let message;

  if (token === 'foo-bar') {
    message = `successs friend: ${friendId} created for userId: ${userId}`;
  } else {
    message = 'Unauthorized';
  }

  return {
    message
  }
});
const server = new Server();

server.use(router);

fetch('/users?page=1&count=3', response => {
  console.log(response.data.length === 3);
  console.log(response.metadata.previous_page === 1);
  console.log(response.metadata.next_page === 2);
});

const headers = new Headers();
headers.append('X-auth-token', 'foo-bar');
const request = new Request('/users/10/friends/55');

fetch(request, {method: 'POST', headers}).then(response => {
  console.log(response.message);
});
```

### Fetch & XMLHttpRequest support

Kakapo have Fetch and XMLHttpRequest support by default, but you can always change that if you want, see the [interceptors docs](#interceptors).

```javascript
import {Router, Server} from 'Kakapo';
  
const router = new Router();

router.get('/users/', () => {
  return 'meh';
});

const server = new Server();

server.use(router);

fetch('/users', users => {
  console.log(users[0].id === 1);
  console.log(users[1].id === 2);
});

const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
  if (xhr.readyState !== 4) return;

  const response = JSON.parse(xhr.responseText);
  console.log(response[0].id === 1);
  console.log(response[1].id === 2);
};
xhr.open('GET', '/users', true);
xhr.send();

```

### Database candyness

Check how easy to build a consistent CRUD Api with the kakapo db.

```javascript
import {Database, Router, Server, Response as KakapoResponse} from 'Kakapo';
  
const sever = new Server();
const router = new Router();
const databse = new Database();

database.register('user', faker => {
  return {
    firstName: faker.name.firstName,
    lastName: faker.name.lastName,
    age: 24
  };
});

database.create('user', 5);

router.get('/users', (request, db) => {
  return db.all('user');
});
router.post('/users', (request, db) => {
  const user = JSON.parse(request.body);

  db.push('user', user);

  return user;
});
router.put('/users/:user_id', (request, db) => {
  const newLastName = JSON.parse(request.body).lastName;
  const user = db.findOne('user', request.params.user_id);

  user.lastName = newLastName;
  user.save();

  return user;
});
router.delete('/users/:user_id', (request, db) => {
  const user = db.findOne('user', request.params.user_id);
  const code = user ? 200 : 400;
  const body = {code};
  
  user && user.delete();

  return new KakapoResponse(code, body);
});

const server = new Server();

server.use(database);
server.use(router);

const getUsers = () => {
  return fetch('/users').then(r => r.json());
}

const createUser = (user) => {
  return $.post('/users', user);
};

const updateLast = () => {
  return $.ajax({
    url: '/users/6',
    method: 'PUT',
    data: {lastName: 'Zarco'}
  });
};

const deleteFirst = () => {
  return $.ajax({
    url: '/users/1',
    method: 'DELETE'
  });
};

getUsers() // users[0].id === 1, users.length === 5
  .then(createUser.bind(null, {firstName: 'Hector'})) // response.id === 6, response.firstName === 'Hector'
  .then(deleteFirst) // response.code === 200
  .then(getUsers) // users[0].id == 2, users[4].id == 6, users.length == 5
  .then(updateLast) // user.id == 6, user.lastName == 'Zarco'
  .then(getUsers) // users.length == 5

```

### Passthrough

You don't need to do anything in order to keep your existing request working as they were before. Kakapo will just passthrough all the request that doesn't match any of the defined routes and fire the associated callback.

```javascript
import {Router, Server} from 'Kakapo';
  
const server = new Server();
const router = new Router();

router.get('/users', (request) => {
  return 'Kakapo';
});

const server = new Server();

server.use(router);

fetch('/users', users => {
  users == 'Kakapo';
});

fetch('https://api.github.com/users', users => {
  //Real Github users data
});

```


# Demo Apps

## TODO App

Every project needs a TODO App, so here is the Kakapo one. Straightforward vanilla js app, uses the **fetch api** for the networking part.

[Check the demo](https://kakapo-todo-app.firebaseapp.com/) or [look at the code](https://github.com/devlucky/Kakapo.js/tree/master/examples/todo-app)

![](http://cl.ly/1K1z1G102X1P/Screen%20Recording%202016-05-16%20at%2010.06%20PM.gif)

## Github explorer

Basic github users search example, based 100% on the (Github Api)[https://developer.github.com/v3]. It shows you how easy is to replicate the logic of a backend with Kakapo and iterate faster when building the UI. This example also uses jQuery just to demostrate the compatibility with Kakapo.

[Check the demo](https://kakapo-github-explorer.firebaseapp.com) or [look at the code](https://github.com/devlucky/Kakapo.js/tree/master/examples/github-explorer)

![](https://raw.github.com/devlucky/Kakapo.js/master/examples/github-explorer/demo.gif)

# Components

## Server
  The Kakapo Server is the main component of the framework, he is charge of activate things and link components like the router or the database.

  **Linking components**
  
  So, in order to make your router to start intercepting requests, you must connect him with your server using the *use* method. Also is a good practice to connect your *current database* with your server, that way you will receive her as a parameter in your request handlers. This practice is very useful when you have multiple databases and routers, since you can easily swicth them without rewriting anything, see [Scenarios](#scenarios) section

```javascript
const myDB = new Database();
const router = new Router();
const server = new Server();

router.get('/posts', (request, db) => {
  console.log(db === myDB);
});

server.use(myDB);
server.use(router);

fetch('/posts');

```

## Router
The Router class gives you the functionality to 
it has a very intuitive interface, so if you ever had to build any kind of rest api in any server-side language, you are already familiar with the Kakapo router. that allows you to define complex routes (like in a real server)

**Method handling**

Those are the supported http methods

```javascript
import {Router} from 'kakapo';

const router = new Router();

router.get('/users/:user_id')
router.post('/users/:user_id')
router.put('/users/:user_id')
router.delete('/users/:user_id')
```

**Request object**

You can access to all the request properties through the request object passed in the request handler

```javascript
router.get('/posts/:post_id/comments/:comment_id', request => {
  console.log(request.params.post_id);
  console.log(request.params.comment_id);
  console.log(request.query.page);
  console.log(request.query.count);
  console.log(request.body);
  console.log(request.headers);
});

$.ajax({
  url: '/posts/1/comments/5?page=1&count=10',
  data: {text: 'Foo comment'},
  headers: {'X-Access-token': '12345'}
})
```

**Options**

Other useful router options are the **host** and the **requestDelay**, you just need to pass them at the initialization moment

```javascript
import {Router} from 'kakapo';

const router = new Router({
  host: 'https://api.github.com',
  requestDelay: 2000
});
```
  
## Database

Database along with the Router is also one of the most important components, if you learn how to use it properly you can reuse tons of code and become really productive, that's why Kakapo promotes the use of the Database but you can still don't use it and return whatever you want from the request handlers.

**Factories**

They come with [Faker](https://github.com/Marak/faker.js) a cool library to generate fake data
Just a brief example of what you can achieve with the db:

```javascript
import {Server, Router, Database} from 'kakapo';

const router = new Router();
const database = new Database();
const server = new Server();

db.register('user', faker => {
  const name = faker.internet.userName();

  return {
    name,
    avatar_url: faker.internet.avatar,
    url: `https://api.github.com/users/${name}`,
    type: "User",
    company: faker.company.companyName, 
    blog: faker.internet.url, 
    location: faker.address.city,
    email: faker.internet.email,
    bio: faker.hacker.phrase,
    created_at: faker.date.past, 
    updated_at: faker.date.recent
  }
});
db.create('user', 10);

router.get('/users', (request, db) => {
  return db.all('user');
});

router.get('/users/:user_id', (request, db) => {
  return db.findOne('user', request.params.user_id);
});

router.post('/users', (request, db) => {
  return db.push('user', request.params.body);
});

server.use(database);
server.use(router);
```


**Relationships**

Sometimes while mocking, you miss some sort of consistency in your responses. Let's say you have a blog and when you ask for comments of a post you return a **post_id** that doesn't match any of the post ids...

You can solve that using relationships, they are designed to help you create this consistent state across all your requests. The methods are **belongsTo** and **hasMany**

```javascript
import {Server, Database, Router} from 'kakapo';

const server = new Server();
const db = new Database();
const router = new Router();

const blogFactory = () => ({
  posts: db.hasMany('post'),
  authors: db.hasMany('user', 2) //Notice how we expecify the author id, to force to return that record always
});
const postFactory = () => ({
  title: 'Js for the lulz',
  body: 'html body',
  blog: db.belongsTo('blog')
});
const userFactory = () => ({
  name: 'devlucky',
  followers: 1000,
});

db.register('blog', blogFactory);
db.register('post', postFactory);
db.register('user', userFactory);

db.create('post', 10);
db.create('user', 5);
db.create('blog', 1);
```

## Response

The Response object is a helper class mostly used inside the request handlers to provide rich responses to your real handlers
  
```javascript
import { Server, Response, Router } from 'kakapo';

const server = new Server();
const router = new Router();

router.get('/user/:user_id', request => {
  const code = request.params.user_id < 10 ? 200 : 400;
  const headers = {'X-request-date': new Date().getTime()};

  return new Response(code, {status: code}, headers);
});

server.use(router);
```

## Serializers

This is another component very familiar in backend laguages, Serializers offers you a way to abstract the **render** part of your entities. 
In this example we cover a common case in which you have different versions of your Api and you want to represent that in Kakapo in the same way

```javascript
const ApiV2Serializer = (record, type) => {
  const id = record.id;
  const metadata = {created_at: new Date()};
  const attributes = Object.assign({}, record, metadata);

  return {
    id,
    type,
    attributes
  };
};

const db = new Database();

db.register('user', () => ({
  firstName: 'Hector',
  lastName: 'Zarco',
  age: 24,
}), ApiV2Serializer);

db.register('comment', () => ({
  text: 'msg'
}), ApiV2Serializer);

```

## Interceptors

This component is the one that actually handles the original request, is a private one but you can configure it in the Router. Just pass **strategies** in the constructor, by default both **fetch** and **XMLHttpRequest** are used.

```javascript
import {Server, Router} from 'kakapo';

const server = new Server();
const fetchRouter = new Router({
  strategies: ['fetch']
});
const xhrRouter = new Router({
  strategies: ['XMLHttpRequest']
});

server.use(fetchRouter);

//LATER

server.use(xhrRouter);
  
```

## Scenarios

The **scenario** concept is nothing else than the ability of having different presets of Kakapo, like router, database, etc... and later, allow the user to decide when he wants to use one of other.  

Let's say you want to check how the spinners looks in your app, in that case you probably will put a higher value as a **requestDelay**, to make sure that the requests are intercepted late and you can check the UI... other good use case might be one in which you want to test the performance of a view when you have thousands of elements, in order to achieve that you will just need to pass a high number to the **create** method of the **Database**: 

```javascript
import {Server, Router, Database} from 'kakapo';

const userFactory = (faker) => {
  return {
    name: faker.name.findName,
    age: 24,
    city: 'Valencia'
  }
};
const usersHandler = (request, db) => db.all('user');
const wifiServer = new Server({requestDelay: 150});
const threeGServer = new Server({requestDelay: 1000});
const router = new Router();
const chillDB = new Database();
const stressfulDB = new Database();

chillDB.register('user', userFactory);
chillDB.create('user', 5);

stressfulDB.register('user', userFactory);
stressfulDB.create('user', 1000);

wifiServer.get('/users', usersHandler);
threeGServer.get('/users', usersHandler);

//Pick the server with more latency if you want to check how the spinner looks like
//server.use(wifiServer);
server.use(threeGServer);

//Here you just have to switch between different databases in order to test the UI with tons of users
//server.use(chillDB);
server.use(stressfulDB);

```  

## Fake data

As mention above, you can use [Faker](https://github.com/Marak/faker.js) for generate fake data, take a look at the full demo [here](http://marak.com/faker.js/). Also note that you can define nested properties and use Faker on them:

```javascript
db.register('user', faker => {
  return {
    user: {
      name: faker.name.findName,
      nick: 'nick'
    },
    company: faker.company.companyName, 
    location: 'Valencia, Spain'
  }
});
```

# ROADMAP

**Full support for JSONApiSerializer**

**Node.js compatibility**

**Node.js interceptors**

# Authors 

[@rpunkfu](https://github.com/rpunkfu) - [@zzarcon](https://github.com/zzarcon)


================================================
FILE: __tests__/data/users.ts
================================================
import * as Faker from 'faker';

export type UserId = string;

export type User = {
  id: UserId,
  firstName: string,
  lastName: string,
  age: number
};

export const userFactory = ({
  id = Faker.random.uuid(),
  firstName = Faker.name.firstName(),
  lastName = Faker.name.lastName(),
  age = Faker.random.number()
}: Partial<User> = {} as User) => ({
  id,
  firstName,
  lastName,
  age
});

export const someUser = userFactory();


================================================
FILE: __tests__/database_spec.ts
================================================
import * as Faker from 'faker';

import { Database, DataFactory } from '../src/Database';
import { User, UserId, userFactory, someUser } from './data/users';

describe('Database', () => {
  type Book = {
    userId: UserId;
    name: string;
  };

  type Schema = {
    user: User;
    book: Book;
  };

  type SetupOptions = {
    factory?: DataFactory<User>;
  };

  const firstName = Faker.name.firstName();
  const lastName = Faker.name.lastName();

  const setup = ({ factory = jest.fn(userFactory) }: SetupOptions = {}) => {
    const database: Database<Schema> = new Database();

    database.register('user', factory);

    return {
      database,
      factory
    };
  };

  describe('create', () => {
    it('should create a record given no size specified', () => {
      const { database } = setup({ factory: () => someUser });
      const records = database.create('user');

      expect(records).toHaveLength(1);

      const [record] = records;
      expect(record.id).toEqual(0);
      expect(record.data).toEqual(someUser);
    });

    it('should create multiple records given size is over 1', () => {
      const { database } = setup();
      const records = database.create('user', 10);

      expect(records).toHaveLength(10);
    });

    it('should throw error given collection has not been registered', () => {
      const database: Database<{
        user: User;
      }> = new Database();

      expect(() => database.create('user')).toThrow();
    });
  });

  describe('all', () => {
    it('should return all records given collection name', () => {
      const { database } = setup();

      database.create('user', 10);
      expect(database.all('user')).toHaveLength(10);

      database.create('user', 5);
      expect(database.all('user')).toHaveLength(15);
    });
  });

  describe('delete', () => {
    it('should return a record given id of existing record', () => {
      const { database } = setup();
      const user = userFactory({ firstName, lastName });

      database.create('user', 10);
      const record = database.push('user', user);

      expect(database.all('user')).toHaveLength(11);
      expect(database.delete('user', record.id)).toEqual(record);
      expect(database.all('user')).toHaveLength(10);
    });

    it('should return null given id of non-existing record', () => {
      const { database } = setup();
      const user = userFactory({ firstName, lastName });

      database.create('user', 10);

      expect(database.all('user')).toHaveLength(10);
      expect(database.delete('user', 123)).toBeNull();
      expect(database.all('user')).toHaveLength(10);
    });
  });

  describe('find', () => {
    it('should return matching records given predicate', () => {
      const { database } = setup();

      database.create('user', 10);
      database.create('user', 5, () => userFactory({ firstName }));

      expect(database.all('user')).toHaveLength(15);
      expect(database.find('user', { firstName })).toHaveLength(5);
    });
  });

  describe('findOne', () => {
    it('should return first matching record given predicate', () => {
      const { database } = setup();
      const user = userFactory({ firstName, lastName });

      database.create('user', 10);
      database.push('user', user);
      database.create('user', 5, () => userFactory({ firstName }));
      database.create('user', 10);

      expect(database.findOne('user', { firstName })!.data).toEqual(user);
    });
  });

  describe('first', () => {
    it('should return the first record given collection name', () => {
      const { database } = setup();

      database.push('user', someUser);
      database.create('user', 10);

      expect(database.first('user')!.data).toEqual(someUser);
    });
  });

  describe('last', () => {
    it('should return the last record given collection name', () => {
      const { database } = setup();

      database.create('user', 10);
      database.push('user', someUser);

      expect(database.last('user')!.data).toEqual(someUser);
    });
  });

  describe('push', () => {
    it('should return a record given some data', () => {
      const { database } = setup();

      const record = database.push('user', someUser);

      expect(record.data).toEqual(someUser);
    });
  });

  describe('register', () => {
    it('should allow database to create records of given collection name', () => {
      const { database } = setup();

      database.register('book', () => ({
        id: Faker.random.uuid(),
        name: Faker.hacker.phrase(),
        userId: someUser.id
      }));

      const records = database.create('book', 10);

      expect(records).toHaveLength(10);
    });

    it('should now allow database to create records of given collection has not been registered', () => {
      const { database } = setup();

      expect(() => database.create('book')).toThrow();
    });
  });

  describe('reset', () => {
    it('should remove all collections', () => {
      const { database } = setup();

      expect(database.exists('user')).toBeTruthy();
      expect(database.exists('book')).toBeFalsy();

      database.register('book', () => ({
        id: Faker.random.uuid(),
        name: Faker.hacker.phrase(),
        userId: someUser.id
      }));

      expect(database.exists('user')).toBeTruthy();
      expect(database.exists('book')).toBeTruthy();

      database.reset();

      expect(database.exists('user')).toBeFalsy();
      expect(database.exists('book')).toBeFalsy();
    });
  });

  describe('update', () => {
    it('should return an updated record given id of existing record', () => {
      const { database } = setup();
      const [record] = database.create('user');

      const updatedRecord = database.update('user', record.id, {
        firstName: 'Jimmy'
      });

      expect(updatedRecord.id).toEqual(record.id);
      expect(updatedRecord.data).toEqual({
        ...record.data,
        firstName: 'Jimmy'
      });
    });

    it('should throw an error given id of non-existing record', () => {
      const { database } = setup();

      database.create('user', 10);

      expect(() =>
        database.update('user', 123, { firstName: 'Jimmy' })
      ).toThrow();
    });
  });
});


================================================
FILE: __tests__/request_spec.ts
================================================
import { Server, Router } from '../src';

test.skip('Request # headers', () => {
  expect.assertions(2);

  const server = new Server();
  const router = new Router();

  router.post('/users', (request) => {
    expect(request.headers.get('custom-request-header-1')).toEqual('one');
    expect(request.headers.get('custom-request-header-2')).toEqual('two');
  });

  server.use(router);

  // TODO: Headers is undefined in jsdom
  const headers = new Headers({
    'custom-request-header-1': 'one',
    'custom-request-header-2': 'two',
  });

  const options = {
    method: 'POST',
    headers,
  };

  fetch('/users', options);
});

// @TODO: Test explicitly the contents of request.params
// @TODO: Test explicitly the contents of request.query

================================================
FILE: __tests__/response_spec.ts
================================================
import { Server, KakapoResponse, Router } from '../src';

// TODO: stub native Response
describe.skip('Response', () => {
  test('Response # body', () => {
    expect.assertions(2);

    const server = new Server();
    const router = new Router();

    router.get(
      '/users/:id',
      request =>
        new KakapoResponse(200, { id: request.params.id, type: 'user' })
    );

    server.use(router);

    fetch('/users/1')
      .then(r => r.json())
      .then(result => {
        expect(result.id).toEqual('1');
        expect(result.type).toEqual('user');
      });
  });

  test('Response # headers', assert => {
    expect.assertions(4);

    const server = new Server();
    const router = new Router();

    router.get(
      '/users/:id',
      () =>
        new KakapoResponse(
          200,
          {},
          { 'x-header-1': 'one', 'x-header-2': 'two' }
        )
    );

    server.use(router);

    fetch('/users/1').then(result => {
      expect(result.headers.get('x-header-1')).toEqual('one');
      expect(result.headers.get('x-header-2')).toEqual('two');
    });

    const xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        expect(this.getResponseHeader('x-header-1')).toEqual('one');
        expect(this.getResponseHeader('x-header-2')).toEqual('two');
      }
    };

    xhr.open('GET', '/users/1', true);
    xhr.send();
  });

  test('Response # error', assert => {
    const response = new KakapoResponse(404, {}, { 'x-header-1': 'one' });

    expect(response.error).toBeTruthy();
  });

  test('Response # ok', assert => {
    const response = new KakapoResponse(204, {}, { 'x-header-1': 'one' });

    expect(response.ok).toBeTruthy();
  });

  test('Response # code', assert => {
    expect.assertions(2);

    const server = new Server();
    const router = new Router();
    const responsePayload = { status: 'error' };

    router.get('/users', request => new KakapoResponse(400, responsePayload));

    server.use(router);

    const xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        expect(xhr.status).toEqual(400);
        expect(xhr.responseText).toEqual(JSON.stringify(responsePayload));
      }
    };
    xhr.open('GET', '/users', true);
    xhr.send();
  });
});


================================================
FILE: __tests__/router_spec.ts
================================================
import { Server, Router, KakapoResponse } from '../src';
import { isFakeFetch } from '../src/interceptors/fetchInterceptor';

describe('Router', () => {

  let server: Server<any>;
  let router: Router<any>;

  beforeEach(() => {
    server = new Server();
    router = new Router();
  });

  afterEach(() => {
    router.reset();
  });

  it('should use fake fetch', () => {
    router = new Router({
      host: 'https://api.github.com'
    });
    router.get('/comments', request => {
      expect(typeof request).toEqual('object');
    });
    server.use(router);

    expect(isFakeFetch(fetch)).toBe(true);
  });

  test('Router # config # host', async () => {
    // TODO: Create multiple servers at the same time with different
    // 'host' and check that works properly
    router = new Router({
      host: 'https://api.github.com'
    });

    router.get('/comments', request => {
      expect(typeof request).toEqual('object');
    });

    server.use(router);

    const response = await fetch('https://api.github.com/comments');

    expect(response).toBeInstanceOf(Response);
    expect(response.ok).toBeTruthy();

    const response2 = await fetch('/comments');
    expect(response).toBeInstanceOf(Response);
  });

  test('Router # config # requestDelay', async () => {
    router = new Router({
      requestDelay: 1000
    });

    router.get('/comments', request => {
      expect(typeof request).toEqual('object');
    });

    server.use(router);

    const response = await fetch('/comments');

    expect(response instanceof Response).toBeTruthy();
    expect(response.ok).toBeTruthy();
  });

  test('Router # config # strategies', async () => {
    const server = new Server();
    const router = new Router({}, {strategies: ['fetch']});

    server.use(router);

    expect(router.routerConfig).toEqual({
      strategies: ['fetch']
    })
  });

  test('Router#get', async () => {
    router.get('/comments', request => {
      expect(typeof request).toEqual('object');
    });

    router.get('/users/:user_id', request => {
      expect(typeof request).toEqual('object');
      expect(typeof request.params).toEqual('object');

      return {
        users: [{ firstName: 'hector' }]
      };
    });

    server.use(router);

    expect(await fetch('/doesnt_exist')).toBeInstanceOf(Response);
    expect(await fetch('/comments')).toBeInstanceOf(Response);

    return fetch('/users/1')
      .then(response => {
        expect(response).toBeInstanceOf(Response);
        return response.json();
      })
      .then(response => {
        const firstName = response.users[0].firstName;
        expect(firstName).toEqual('hector');
      });
  });

  test('Router#post', async () => {
    const body = JSON.stringify({ firstName: 'Joan', lastName: 'Romano' });

    router.post('/users', request => {
      const parsedBody = JSON.parse(request.body);
      const firstName = parsedBody.firstName;

      expect(request.body).toEqual(body);
      expect(firstName).toEqual('Joan');

      return {
        status: 'success',
        record: parsedBody
      };
    });

    server.use(router);

    const response = await (await fetch('/users', {
      method: 'POST',
      body
    })).json();
    const status = response.status;
    const firstName = response.record.firstName;

    expect(status).toEqual('success');
    expect(firstName).toEqual('Joan');
  });

  test('Router # post # XMLHttpRequest', () => {
    const body = JSON.stringify({ firstName: 'Joan', lastName: 'Romano' });

    router.post('/hector', request => {
      const body = JSON.parse(request.body);

      expect(body.firstName).toEqual('Joan');
    });

    server.use(router);

    const xhr = new XMLHttpRequest();

    xhr.onreadystatechange = () => {};
    xhr.open('POST', '/hector', true);
    xhr.send(body);
  });

  test('Router#put', async () => {
    router.put('/users', request => {
      const query = request.query;
      const page = query.page;

      expect(page).toEqual('1');

      return {
        status: 'success',
        query
      };
    });

    server.use(router);

    const response = await (await fetch('/users?page=1', {
      method: 'PUT'
    })).json();
    const status = response.status;
    const page = response.query.page;

    expect(status).toEqual('success');
    expect(page).toEqual('1');
  });

  test('Router#delete', async () => {
    router.delete('/users/:user_id/comments/:comment_id', request => {
      const params = request.params;
      const commentId = request.params.comment_id;

      expect(commentId).toEqual('2');

      return {
        status: 'success',
        params
      };
    });

    server.use(router);

    const response = await (await fetch('/users/1/comments/2', {
      method: 'DELETE'
    })).json();
    const status = response.status;
    const userId = response.params.user_id;

    expect(status).toEqual('success');
    expect(userId).toEqual('1');
  });

  test('Router#XMLHttpRequest # config # requestDelay', () => {
    router = new Router({
      requestDelay: 10
    });

    router.get('/comments', request => {
      expect(typeof request).toEqual('object');
    });

    server.use(router);

    const xhr = new XMLHttpRequest();

    xhr.onreadystatechange = () => {};
    xhr.open('GET', '/comments', true);
    xhr.send();
  });

  test.skip('Router#XMLHttpRequest', () => {
    router.get('/comments', request => {
      const params = request.params;

      expect(typeof request).toEqual('object');
      expect(typeof params).toEqual('object');

      return [{ text: 'First comment' }, { text: 'Second comment' }];
    });

    server.use(router);

    const xhr = new XMLHttpRequest();
    const xhr2 = new XMLHttpRequest();

    xhr.onreadystatechange = () => {
      if (xhr.readyState !== 4) {
        return;
      }

      const response = xhr.responseText;

      expect(typeof response).toEqual('string');
    };
    xhr.open('GET', '/doesnt_exist', true);
    xhr.send();

    xhr2.onreadystatechange = function() {
      if (xhr2.readyState !== 4 || xhr2.status !== 200) {
        return;
      }

      const response = xhr2.responseText;
      const texts = response;
      const responseObject = JSON.parse(response);

      expect(this.readyState).toEqual(xhr2.readyState);
      expect(this.responseText).toEqual(xhr2.responseText);
      expect(typeof response).toEqual('string');
      expect(typeof responseObject).toEqual('object');
      expect(responseObject.length).toEqual(2);
    };
    xhr2.open('GET', '/comments', true);
    xhr2.send();
    expect.assertions(8);
  });

  test('Router # Async support', async () => {
    router.get('/async_endpoint', request => {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve({
            body: 'async response'
          });
        }, 1000);
      });
    });

    server.use(router);

    const response = await (await fetch('/async_endpoint')).json();

    expect(response.body).toEqual('async response');
  });

  test('Router # Fetch # Content-Type image/svg+xml', async () => {
    const svgData = 'svgData';

    router.get('/svg_content', request => {
      return new KakapoResponse(200, svgData, {
        'content-type': 'image/svg+xml'
      });
    });

    server.use(router);

    const response = await fetch('/svg_content');

    expect(response.body).toEqual(svgData);
  });

  test('Router # Fetch # No Content Type', async () => {
    const expectedResponse = { foo: 'bar' };

    router.get('/json_content', request => {
      return new KakapoResponse(200, expectedResponse);
    });

    server.use(router);

    const response = await fetch('/json_content');

    expect(response.json()).resolves.toEqual(expectedResponse);
  });

  test('Router # Fetch # Content Type application/json', async () => {
    const expectedResponse = { foo: 'bar' };

    router.get('/json_content', request => {
      return new KakapoResponse(200, expectedResponse, {
        'content-type': 'application/json'
      });
    });

    server.use(router);

    const response = await fetch('/json_content');

    expect(response.body).toEqual(JSON.stringify(expectedResponse));
  });
  // @TODO Test strategies in router.
});


================================================
FILE: __tests__/server_spec.ts
================================================
// @TODO Test Server's config
import { Database, Router, Server } from '../src';

const xhrRequest = (url: string) => {
    const xhr = new XMLHttpRequest();

    xhr.onreadystatechange = () => {};
    xhr.open('GET', url, true);
    xhr.send();
};

describe.skip('Server', () => {
    test('Server # use database', () => {
        expect.assertions(2);

        const myDB = new Database();
        const router = new Router();
        const server = new Server();

        router.get('/fetch', (request, db) => {
            expect(db == myDB).toBeTruthy();
        });
        router.get('/xhr', (request, db) => {
            expect(db == myDB).toBeTruthy();
        });

        server.use(myDB);
        server.use(router);

        fetch('/fetch');
        xhrRequest('/xhr');
    });

    test('Server # use router', () => {
        const router = new Router();
        const server = new Server();

        router.get('/comments', _ => {
            //Should not reach this handler since the request is fired before "server.use"
        });

        router.get('/users', _ => {
            //It must only enter in this handler since the request has been triggered after the registration
            expect(true).toBeTruthy();
        });

        fetch('/comments');
        server.use(router);
        fetch('/users');
    });

    test('Server # remove database', () => {
        expect.assertions(2);

        const myDB = new Database();
        const router = new Router();
        const server = new Server();

        router.get('/fetch_db', (_request, db) => {
            expect(db == myDB).toBeTruthy();
        });
        router.get('/fetch_nodb', (_request, db) => {
            expect(db == null).toBeTruthy();
        });

        server.use(myDB);
        server.use(router);
        fetch('/fetch_db');

        server.remove(myDB);
        fetch('/fetch_nodb');
    });

    test('Server # remove router', () => {
        expect.assertions(2);

        const router = new Router();
        const server = new Server();

        router.get('/fetch', _ => {
            //Server is active before being removed
            expect(true).toBeTruthy();
        });
        router.get('/fetch_fail', _ => {
            //Request is being intercepted when router is removed
        });

        server.use(router);
        fetch('/fetch');

        server.remove(router);
        fetch('/fetch_fail').then(response => {
            //Server is inactive after removal
            expect(response.status).toEqual(404);
        });
    });
});


================================================
FILE: create-readme.js
================================================
'use strict';
const fs = require('fs');
const request = require('superagent');
const readmeUrl = 'https://cdn.rawgit.com/devlucky/devlucky.github.io/master/kakapo-js.md';

request
  .get(readmeUrl)
  .end(function(err, res) {
    if (err) {
      return console.log(err);
    }

    const text = res.text;
    const content = text.split('# Getting started')[1].replace(/\<\/div>/g, '');
    const start = getFile('start');
    const end = getFile('end');
    const readme = [start, content, end].join('');
    
    fs.writeFileSync('./README.md', readme);
  });

const getFile = uri => fs.readFileSync(`./md/${uri}.md`).toString();

================================================
FILE: examples/dummy/.gitignore
================================================
bower_components
dist

================================================
FILE: examples/dummy/README.md
================================================
#Kakapo Dummy App example
> Just shows how to integrate Kakapo.js in you app in multiple flavours

This Example shows different ways of requiring Kakapo.js in your app:

##ES6 Module

`$ npm i kakapo -D`

`$ npm run browserify` 

```javascript
import {Server, Router} from 'kakapo';

const server = new Server();
const router = new Router();
```

##AMD

`$ npm i kakapo -D`

`$ npm run browserify_require`

```javascript
const kakapo = require('kakapo');

const server = new kakapo.Server();
const router = new kakapo.Router();
```

##Bower

`$ bower i kakapo -D`

Include **bower_components/kakapo/lib/kakapo.js** 

```javascript
const server = new Kakapo.Server();
const router = new Kakapo.Router();
```


================================================
FILE: examples/dummy/bower.json
================================================
{
  "name": "kakapo-dummy-app",
  "description": "Dummy app that shows how to integrate Kakapo.js",
  "main": "index.js",
  "authors": [
    "kakapo-team"
  ],
  "license": "MIT",
  "homepage": "https://github.com/devlucky/Kakapo.js",
  "private": true,
  "dependencies": {
    "kakapo": "https://github.com/devlucky/Kakapo.js.git#master"
  }
}


================================================
FILE: examples/dummy/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Kakapo dummy app</title>
  <!---->
  <!-- Uncomment the option you wanna try -->
  <!---->
  <!-- <script src="dist/browserify_bundle.js"></script> -->
  <!-- <script src="dist/browserify_require_bundle.js"></script> -->
  <!-- <script src="../../lib/kakapo.js"></script>
  <script src="bower_test.js"></script> -->
  <script src="https://rawgit.com/devlucky/Kakapo.js/master/lib/kakapo.js"></script>
  <!-- <script src="bower_components/kakapo/lib/kakapo.js"></script> -->
  <!-- <script src="bower_test.js"></script> -->
</head>
<body>
  
</body>
</html>

================================================
FILE: examples/dummy/package.json
================================================
{
  "name": "kakapo-dummy-app",
  "version": "0.1.0",
  "description": "Dummy app that shows how to integrate Kakapo.js",
  "main": "index.js",
  "scripts": {
    "browserify": "browserify browserify_test.js -o dist/browserify_bundle.js -t [ babelify --presets [ es2015 ] ]",
    "browserify_require": "browserify browserify_require_test.js -o dist/browserify_require_bundle.js -t [ babelify --presets [ es2015 ] ]"
  },
  "author": "kakapo-team",
  "license": "MIT",
  "dependencies": {
    "kakapo": "0.1.3"
  },
  "devDependencies": {
    "babel-cli": "^6.10.1",
    "babel-preset-es2015": "^6.9.0",
    "babelify": "^7.3.0",
    "browserify": "^13.0.1"
  }
}


================================================
FILE: examples/github-explorer/.firebaserc
================================================
{
  "projects": {
    "default": "kakapo-github-explorer"
  }
}


================================================
FILE: examples/github-explorer/README.md
================================================
# Example - Github explorer
> Example of a github user explorer powered by Kakapo.js - [DEMO](https://kakapo-github-explorer.firebaseapp.com/)

![](https://raw.github.com/devlucky/Kakapo.js/master/examples/github-explorer/demo.gif)

# Installation

`$ npm i`

`$ python -m SimpleHTTPServer 8000`

================================================
FILE: examples/github-explorer/database.rules.json
================================================
{
  ".read": true,
  ".write": true
}


================================================
FILE: examples/github-explorer/firebase.json
================================================
{
  "database": {
    "rules": "database.rules.json"
  },
  "hosting": {
    "public": ".",
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}


================================================
FILE: examples/github-explorer/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link type="text/css" rel="stylesheet" href="node_modules/materialize-css/bin/materialize.css"  media="screen,projection"/>
    <link type="text/css" rel="stylesheet" href="styles.css"/>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Kakapo - Github explorer</title>
  </head>
  <body>
    <nav>
      <div class="nav-wrapper">
        <a href="#" class="brand-logo">Github explorer</a>
        <ul id="nav-mobile" class="right hide-on-med-and-down">
          <div class="row">
            <div class="input-field col s6">
              <i class="material-icons prefix">search</i>
              <input id="search" type="text" class="validate">
              <label for="search">Search...</label>
            </div>
          </div>
        </ul>
      </div>
    </nav>
    
    <div id="userModal" class="modal">
      <div class="modal-content">
        
      </div>
    </div>
    <div id="users-loader" class="progress">
      <div class="indeterminate"></div>
    </div>
    <ul id="user-list" class="collection">
      
    </ul>
    <!-- For development -->
    <!-- <script src="../../lib/kakapo.js"></script> -->
    <script src="https://rawgit.com/devlucky/Kakapo.js/master/lib/kakapo.js"></script>
    <script src="node_modules/jquery/dist/jquery.js"></script>
    <script src="kakapo-config.js"></script>
    <script src="app.js"></script>
    <script src="node_modules/materialize-css/bin/materialize.js"></script>
  </body>
</html>

================================================
FILE: examples/github-explorer/package.json
================================================
{
  "name": "kakapo-github-explorer",
  "version": "0.1.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "styles": "node-sass styles.scss styles.css -w"
  },
  "author": "kakapo-team",
  "license": "MIT",
  "dependencies": {
    "jquery": "^2.2.3",
    "materialize-css": "^0.97.6"
  },
  "devDependencies": {
    "node-sass": "^3.7.0"
  }
}


================================================
FILE: examples/github-explorer/styles.css
================================================
nav {
  padding: 0 10px;
  margin-bottom: 20px; }
  nav #nav-mobile label {
    color: #ccc; }
    nav #nav-mobile label.active {
      display: none; }

#search {
  padding: 0;
  margin-left: 35px; }

.collection-item {
  transition: background-color 0.2s ease;
  cursor: pointer; }
  .collection-item:hover {
    background-color: #2bbbad; }

#users-loader {
  height: 0;
  transition: height .3s; }
  #users-loader.active {
    height: 4px; }

.media {
  display: flex;
  align-items: flex-start;
  margin-bottom: 10px; }
  .media .media-img {
    margin-right: 10px;
    width: 70px; }
  .media .media-body {
    flex: 1; }
  .media .media-title {
    margin-bottom: 5px; }
  .media ul li {
    display: flex;
    align-items: center;
    margin-bottom: 10px; }
    .media ul li i {
      margin-right: 10px; }
  .media p {
    border-top: 1px solid #eee;
    margin-top: 10px;
    padding-top: 10px; }


================================================
FILE: examples/github-explorer/styles.scss
================================================
nav {
  padding: 0 10px;
  margin-bottom: 20px;

  #nav-mobile label {
    color: #ccc;

    &.active {
      display: none;
    }
  }
}
#search {
  padding: 0;
  margin-left: 35px;
}
.collection-item {
  transition: background-color 0.2s ease;
  cursor: pointer;

  &:hover {
    background-color: #2bbbad;
  }
}
#users-loader {
  height: 0;
  transition: height .3s;

  &.active {
    height: 4px;
  }
}
.media{
  display: flex;
  align-items: flex-start;
  margin-bottom: 10px;

  .media-img{
    margin-right: 10px;
    width: 70px;
  }
  .media-body{
    flex: 1;
  }
  .media-title{
    margin-bottom: 5px;
  }
  ul{
    li{
      display: flex;
      align-items: center;
      margin-bottom: 10px;

      i{
        margin-right: 10px;
      }
    }
  }
  p{
    border-top: 1px solid #eee;
    margin-top: 10px;
    padding-top: 10px;
  }
}

================================================
FILE: examples/react/.nvmrc
================================================
8.5.0

================================================
FILE: examples/react/example/app.tsx
================================================
import * as React from 'react';
import {Component} from 'react';
import {Server, Router} from '../../../dist';
import {AppWrapper} from './styled';

const server = new Server();
const router = new Router();

router.get('/files', () => {
  return {
    files: [1,2]
  };
});

router.get('/promise/files', () => {
  return Promise.resolve({
    files: [1,2]
  });
});

router.post('/promise/file', async () => {
  await new Promise(resolve => setTimeout(resolve, 100));

  return new Promise(resolve => {
    resolve({
      status: 'success'
    });
  });
});

server.use(router);

export interface AppState {
  
}

export default class App extends Component <{}, AppState> {
  state: AppState = {
    
  }
  
  componentDidMount() {
    this.getFilesXHR();
    this.getFilesPromiseXHR();
    this.postFilePromiseXHR();
  }

  async getFilesFetch() {
    const files = await (await fetch('/files')).json();

    console.log(files)
  }

  async getFilesXHR() {
    const xhr = new XMLHttpRequest();

    xhr.open('GET', '/files');
    xhr.onload = () => {
      console.log('response', xhr.response);
    };
    xhr.send();
  }

  getFilesPromiseXHR() {
    const xhr = new XMLHttpRequest();

    xhr.open('GET', '/promise/files');
    xhr.onload = () => {
      console.log('promise response', xhr.response);
    };
    xhr.send();
  }

  postFilePromiseXHR() {
    const xhr = new XMLHttpRequest();

    xhr.open('POST', '/promise/file');
    xhr.onload = () => {
      console.log('promise post response', xhr.response);
    };
    xhr.send();
  }

  render() {
    return (
      <AppWrapper>
        Example!
      </AppWrapper>
    )
  }
}

================================================
FILE: examples/react/example/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example</title>
</head>
<body>
  <div id="app"></div>
  <script src="../example-bundle.js"></script>
</body>
</html>

================================================
FILE: examples/react/example/index.tsx
================================================
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './app';

ReactDOM.render(<App />, document.getElementById('app'));


================================================
FILE: examples/react/example/styled.ts
================================================
import styled from 'styled-components';

export const AppWrapper = styled.div`

`;

================================================
FILE: examples/react/package.json
================================================
{
  "name": "kakapo-react-example",
  "version": "1.0.0",
  "private": true,
  "license": "MIT",
  "devDependencies": {
    "ts-react-toolbox": "^0.1.1"
  },
  "engines": {
    "node": ">=8.5.0"
  },
  "scripts": {
    "bootstrap": "ts-react-toolbox init",
    "dev": "ts-react-toolbox dev",
    "build": "ts-react-toolbox build",
    "lint": "ts-react-toolbox lint"
  },
  "peerDependencies": {
    "react": "^16.2.0"
  }
}

================================================
FILE: examples/react/tsconfig.json
================================================
{
  "compilerOptions": {
    "strict": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitAny": false,
    "removeComments": true,
    "target": "es5",
    "lib": [
      "dom",
      "es5",
      "scripthost",
      "es2015.collection",
      "es2015.symbol",
      "es2015.iterable",
      "es2015.promise"
    ],
    "jsx": "react"
  }
}

================================================
FILE: examples/todo-app/.firebaserc
================================================
{
  "projects": {
    "default": "kakapo-todo-app"
  }
}


================================================
FILE: examples/todo-app/README.md
================================================
# Example - TODO App
> Example of a todo app powered by Kakapo.js - [DEMO](https://kakapo-todo-app.firebaseapp.com/)

![](http://cl.ly/1K1z1G102X1P/Screen%20Recording%202016-05-16%20at%2010.06%20PM.gif)

# Installation

`$ npm i`

`$ python -m SimpleHTTPServer 8000`


================================================
FILE: examples/todo-app/database.rules.json
================================================
{
  ".read": true,
  ".write": true
}


================================================
FILE: examples/todo-app/firebase.json
================================================
{
  "database": {
    "rules": "database.rules.json"
  },
  "hosting": {
    "public": ".",
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}


================================================
FILE: examples/todo-app/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Kakapo.js - TODO App</title>
    <link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">
  </head>
  <body>
    <body>
      <section class="todoapp">
        <header class="header">
          <h1>todos</h1>
          <input class="new-todo" placeholder="What needs to be done?" autofocus>
        </header>
        <section class="main">
          <input class="toggle-all" type="checkbox">
          <label for="toggle-all">Mark all as complete</label>
          <ul class="todo-list"></ul>
        </section>
        <footer class="footer" hidden>
          <span class="todo-count"><strong>0</strong> item left</span>
          <button class="clear-completed">Clear completed</button>
        </footer>
      </section>
      <footer class="info">
        <p>Double-click to edit a todo</p>
      </footer>
      
      <!-- For development -->
      <!-- <script src="../../lib/kakapo.js"></script> -->
      <script src="https://rawgit.com/devlucky/Kakapo.js/master/lib/kakapo.js"></script>
      <script src="kakapo-config.js"></script>
      <script src="app.js"></script>
    </body>
  </body>
</html>


================================================
FILE: examples/todo-app/package.json
================================================
{
  "name": "kakapo-todo-app",
  "version": "0.1.0",
  "description": "Todo app built with Kakapo.js",
  "main": "index.js",
  "scripts": {},
  "author": "devlucky",
  "license": "MIT",
  "dependencies": {
    "kakapo": "0.0.1",
    "todomvc-app-css": "^2.0.5"
  }
}


================================================
FILE: flow-typed/npm/jest_v22.x.x.js
================================================
// flow-typed signature: 069387a9f0aaed26ad0eb69da26f3e03
// flow-typed version: 2c21d4538f/jest_v22.x.x/flow_>=v0.39.x

type JestMockFn<TArguments: $ReadOnlyArray<*>, TReturn> = {
  (...args: TArguments): TReturn,
  /**
   * An object for introspecting mock calls
   */
  mock: {
    /**
     * An array that represents all calls that have been made into this mock
     * function. Each call is represented by an array of arguments that were
     * passed during the call.
     */
    calls: Array<TArguments>,
    /**
     * An array that contains all the object instances that have been
     * instantiated from this mock function.
     */
    instances: Array<TReturn>
  },
  /**
   * Resets all information stored in the mockFn.mock.calls and
   * mockFn.mock.instances arrays. Often this is useful when you want to clean
   * up a mock's usage data between two assertions.
   */
  mockClear(): void,
  /**
   * Resets all information stored in the mock. This is useful when you want to
   * completely restore a mock back to its initial state.
   */
  mockReset(): void,
  /**
   * Removes the mock and restores the initial implementation. This is useful
   * when you want to mock functions in certain test cases and restore the
   * original implementation in others. Beware that mockFn.mockRestore only
   * works when mock was created with jest.spyOn. Thus you have to take care of
   * restoration yourself when manually assigning jest.fn().
   */
  mockRestore(): void,
  /**
   * Accepts a function that should be used as the implementation of the mock.
   * The mock itself will still record all calls that go into and instances
   * that come from itself -- the only difference is that the implementation
   * will also be executed when the mock is called.
   */
  mockImplementation(
    fn: (...args: TArguments) => TReturn
  ): JestMockFn<TArguments, TReturn>,
  /**
   * Accepts a function that will be used as an implementation of the mock for
   * one call to the mocked function. Can be chained so that multiple function
   * calls produce different results.
   */
  mockImplementationOnce(
    fn: (...args: TArguments) => TReturn
  ): JestMockFn<TArguments, TReturn>,
  /**
   * Accepts a string to use in test result output in place of "jest.fn()" to
   * indicate which mock function is being referenced.
   */
  mockName(name: string): JestMockFn<TArguments, TReturn>,
  /**
   * Just a simple sugar function for returning `this`
   */
  mockReturnThis(): void,
  /**
   * Deprecated: use jest.fn(() => value) instead
   */
  mockReturnValue(value: TReturn): JestMockFn<TArguments, TReturn>,
  /**
   * Sugar for only returning a value once inside your mock
   */
  mockReturnValueOnce(value: TReturn): JestMockFn<TArguments, TReturn>
};

type JestAsymmetricEqualityType = {
  /**
   * A custom Jasmine equality tester
   */
  asymmetricMatch(value: mixed): boolean
};

type JestCallsType = {
  allArgs(): mixed,
  all(): mixed,
  any(): boolean,
  count(): number,
  first(): mixed,
  mostRecent(): mixed,
  reset(): void
};

type JestClockType = {
  install(): void,
  mockDate(date: Date): void,
  tick(milliseconds?: number): void,
  uninstall(): void
};

type JestMatcherResult = {
  message?: string | (() => string),
  pass: boolean
};

type JestMatcher = (actual: any, expected: any) => JestMatcherResult;

type JestPromiseType = {
  /**
   * Use rejects to unwrap the reason of a rejected promise so any other
   * matcher can be chained. If the promise is fulfilled the assertion fails.
   */
  rejects: JestExpectType,
  /**
   * Use resolves to unwrap the value of a fulfilled promise so any other
   * matcher can be chained. If the promise is rejected the assertion fails.
   */
  resolves: JestExpectType
};

/**
 * Jest allows functions and classes to be used as test names in test() and
 * describe()
 */
type JestTestName = string | Function;

/**
 *  Plugin: jest-enzyme
 */
type EnzymeMatchersType = {
  toBeChecked(): void,
  toBeDisabled(): void,
  toBeEmpty(): void,
  toBeEmptyRender(): void,
  toBePresent(): void,
  toContainReact(element: React$Element<any>): void,
  toExist(): void,
  toHaveClassName(className: string): void,
  toHaveHTML(html: string): void,
  toHaveProp: ((propKey: string, propValue?: any) => void) & ((props: Object) => void),
  toHaveRef(refName: string): void,
  toHaveState: ((stateKey: string, stateValue?: any) => void) & ((state: Object) => void),
  toHaveStyle: ((styleKey: string, styleValue?: any) => void) & ((style: Object) => void),
  toHaveTagName(tagName: string): void,
  toHaveText(text: string): void,
  toIncludeText(text: string): void,
  toHaveValue(value: any): void,
  toMatchElement(element: React$Element<any>): void,
  toMatchSelector(selector: string): void
};

// DOM testing library extensions https://github.com/kentcdodds/dom-testing-library#custom-jest-matchers
type DomTestingLibraryType = {
  toBeInTheDOM(): void,
  toHaveTextContent(content: string): void,
  toHaveAttribute(name: string, expectedValue?: string): void
};

type JestExpectType = {
  not: JestExpectType & EnzymeMatchersType & DomTestingLibraryType,
  /**
   * If you have a mock function, you can use .lastCalledWith to test what
   * arguments it was last called with.
   */
  lastCalledWith(...args: Array<any>): void,
  /**
   * toBe just checks that a value is what you expect. It uses === to check
   * strict equality.
   */
  toBe(value: any): void,
  /**
   * Use .toHaveBeenCalled to ensure that a mock function got called.
   */
  toBeCalled(): void,
  /**
   * Use .toBeCalledWith to ensure that a mock function was called with
   * specific arguments.
   */
  toBeCalledWith(...args: Array<any>): void,
  /**
   * Using exact equality with floating point numbers is a bad idea. Rounding
   * means that intuitive things fail.
   */
  toBeCloseTo(num: number, delta: any): void,
  /**
   * Use .toBeDefined to check that a variable is not undefined.
   */
  toBeDefined(): void,
  /**
   * Use .toBeFalsy when you don't care what a value is, you just want to
   * ensure a value is false in a boolean context.
   */
  toBeFalsy(): void,
  /**
   * To compare floating point numbers, you can use toBeGreaterThan.
   */
  toBeGreaterThan(number: number): void,
  /**
   * To compare floating point numbers, you can use toBeGreaterThanOrEqual.
   */
  toBeGreaterThanOrEqual(number: number): void,
  /**
   * To compare floating point numbers, you can use toBeLessThan.
   */
  toBeLessThan(number: number): void,
  /**
   * To compare floating point numbers, you can use toBeLessThanOrEqual.
   */
  toBeLessThanOrEqual(number: number): void,
  /**
   * Use .toBeInstanceOf(Class) to check that an object is an instance of a
   * class.
   */
  toBeInstanceOf(cls: Class<*>): void,
  /**
   * .toBeNull() is the same as .toBe(null) but the error messages are a bit
   * nicer.
   */
  toBeNull(): void,
  /**
   * Use .toBeTruthy when you don't care what a value is, you just want to
   * ensure a value is true in a boolean context.
   */
  toBeTruthy(): void,
  /**
   * Use .toBeUndefined to check that a variable is undefined.
   */
  toBeUndefined(): void,
  /**
   * Use .toContain when you want to check that an item is in a list. For
   * testing the items in the list, this uses ===, a strict equality check.
   */
  toContain(item: any): void,
  /**
   * Use .toContainEqual when you want to check that an item is in a list. For
   * testing the items in the list, this matcher recursively checks the
   * equality of all fields, rather than checking for object identity.
   */
  toContainEqual(item: any): void,
  /**
   * Use .toEqual when you want to check that two objects have the same value.
   * This matcher recursively checks the equality of all fields, rather than
   * checking for object identity.
   */
  toEqual(value: any): void,
  /**
   * Use .toHaveBeenCalled to ensure that a mock function got called.
   */
  toHaveBeenCalled(): void,
  /**
   * Use .toHaveBeenCalledTimes to ensure that a mock function got called exact
   * number of times.
   */
  toHaveBeenCalledTimes(number: number): void,
  /**
   * Use .toHaveBeenCalledWith to ensure that a mock function was called with
   * specific arguments.
   */
  toHaveBeenCalledWith(...args: Array<any>): void,
  /**
   * Use .toHaveBeenLastCalledWith to ensure that a mock function was last called
   * with specific arguments.
   */
  toHaveBeenLastCalledWith(...args: Array<any>): void,
  /**
   * Check that an object has a .length property and it is set to a certain
   * numeric value.
   */
  toHaveLength(number: number): void,
  /**
   *
   */
  toHaveProperty(propPath: string, value?: any): void,
  /**
   * Use .toMatch to check that a string matches a regular expression or string.
   */
  toMatch(regexpOrString: RegExp | string): void,
  /**
   * Use .toMatchObject to check that a javascript object matches a subset of the properties of an object.
   */
  toMatchObject(object: Object | Array<Object>): void,
  /**
   * This ensures that a React component matches the most recent snapshot.
   */
  toMatchSnapshot(name?: string): void,
  /**
   * Use .toThrow to test that a function throws when it is called.
   * If you want to test that a specific error gets thrown, you can provide an
   * argument to toThrow. The argument can be a string for the error message,
   * a class for the error, or a regex that should match the error.
   *
   * Alias: .toThrowError
   */
  toThrow(message?: string | Error | Class<Error> | RegExp): void,
  toThrowError(message?: string | Error | Class<Error> | RegExp): void,
  /**
   * Use .toThrowErrorMatchingSnapshot to test that a function throws a error
   * matching the most recent snapshot when it is called.
   */
  toThrowErrorMatchingSnapshot(): void
};

type JestObjectType = {
  /**
   *  Disables automatic mocking in the module loader.
   *
   *  After this method is called, all `require()`s will return the real
   *  versions of each module (rather than a mocked version).
   */
  disableAutomock(): JestObjectType,
  /**
   * An un-hoisted version of disableAutomock
   */
  autoMockOff(): JestObjectType,
  /**
   * Enables automatic mocking in the module loader.
   */
  enableAutomock(): JestObjectType,
  /**
   * An un-hoisted version of enableAutomock
   */
  autoMockOn(): JestObjectType,
  /**
   * Clears the mock.calls and mock.instances properties of all mocks.
   * Equivalent to calling .mockClear() on every mocked function.
   */
  clearAllMocks(): JestObjectType,
  /**
   * Resets the state of all mocks. Equivalent to calling .mockReset() on every
   * mocked function.
   */
  resetAllMocks(): JestObjectType,
  /**
   * Restores all mocks back to their original value.
   */
  restoreAllMocks(): JestObjectType,
  /**
   * Removes any pending timers from the timer system.
   */
  clearAllTimers(): void,
  /**
   * The same as `mock` but not moved to the top of the expectation by
   * babel-jest.
   */
  doMock(moduleName: string, moduleFactory?: any): JestObjectType,
  /**
   * The same as `unmock` but not moved to the top of the expectation by
   * babel-jest.
   */
  dontMock(moduleName: string): JestObjectType,
  /**
   * Returns a new, unused mock function. Optionally takes a mock
   * implementation.
   */
  fn<TArguments: $ReadOnlyArray<*>, TReturn>(
    implementation?: (...args: TArguments) => TReturn
  ): JestMockFn<TArguments, TReturn>,
  /**
   * Determines if the given function is a mocked function.
   */
  isMockFunction(fn: Function): boolean,
  /**
   * Given the name of a module, use the automatic mocking system to generate a
   * mocked version of the module for you.
   */
  genMockFromModule(moduleName: string): any,
  /**
   * Mocks a module with an auto-mocked version when it is being required.
   *
   * The second argument can be used to specify an explicit module factory that
   * is being run instead of using Jest's automocking feature.
   *
   * The third argument can be used to create virtual mocks -- mocks of modules
   * that don't exist anywhere in the system.
   */
  mock(
    moduleName: string,
    moduleFactory?: any,
    options?: Object
  ): JestObjectType,
  /**
   * Returns the actual module instead of a mock, bypassing all checks on
   * whether the module should receive a mock implementation or not.
   */
  requireActual(moduleName: string): any,
  /**
   * Returns a mock module instead of the actual module, bypassing all checks
   * on whether the module should be required normally or not.
   */
  requireMock(moduleName: string): any,
  /**
   * Resets the module registry - the cache of all required modules. This is
   * useful to isolate modules where local state might conflict between tests.
   */
  resetModules(): JestObjectType,
  /**
   * Exhausts the micro-task queue (usually interfaced in node via
   * process.nextTick).
   */
  runAllTicks(): void,
  /**
   * Exhausts the macro-task queue (i.e., all tasks queued by setTimeout(),
   * setInterval(), and setImmediate()).
   */
  runAllTimers(): void,
  /**
   * Exhausts all tasks queued by setImmediate().
   */
  runAllImmediates(): void,
  /**
   * Executes only the macro task queue (i.e. all tasks queued by setTimeout()
   * or setInterval() and setImmediate()).
   */
  advanceTimersByTime(msToRun: number): void,
  /**
   * Executes only the macro task queue (i.e. all tasks queued by setTimeout()
   * or setInterval() and setImmediate()).
   *
   * Renamed to `advanceTimersByTime`.
   */
  runTimersToTime(msToRun: number): void,
  /**
   * Executes only the macro-tasks that are currently pending (i.e., only the
   * tasks that have been queued by setTimeout() or setInterval() up to this
   * point)
   */
  runOnlyPendingTimers(): void,
  /**
   * Explicitly supplies the mock object that the module system should return
   * for the specified module. Note: It is recommended to use jest.mock()
   * instead.
   */
  setMock(moduleName: string, moduleExports: any): JestObjectType,
  /**
   * Indicates that the module system should never return a mocked version of
   * the specified module from require() (e.g. that it should always return the
   * real module).
   */
  unmock(moduleName: string): JestObjectType,
  /**
   * Instructs Jest to use fake versions of the standard timer functions
   * (setTimeout, setInterval, clearTimeout, clearInterval, nextTick,
   * setImmediate and clearImmediate).
   */
  useFakeTimers(): JestObjectType,
  /**
   * Instructs Jest to use the real versions of the standard timer functions.
   */
  useRealTimers(): JestObjectType,
  /**
   * Creates a mock function similar to jest.fn but also tracks calls to
   * object[methodName].
   */
  spyOn(object: Object, methodName: string, accessType?: "get" | "set"): JestMockFn<any, any>,
  /**
   * Set the default timeout interval for tests and before/after hooks in milliseconds.
   * Note: The default timeout interval is 5 seconds if this method is not called.
   */
  setTimeout(timeout: number): JestObjectType
};

type JestSpyType = {
  calls: JestCallsType
};

/** Runs this function after every test inside this context */
declare function afterEach(
  fn: (done: () => void) => ?Promise<mixed>,
  timeout?: number
): void;
/** Runs this function before every test inside this context */
declare function beforeEach(
  fn: (done: () => void) => ?Promise<mixed>,
  timeout?: number
): void;
/** Runs this function after all tests have finished inside this context */
declare function afterAll(
  fn: (done: () => void) => ?Promise<mixed>,
  timeout?: number
): void;
/** Runs this function before any tests have started inside this context */
declare function beforeAll(
  fn: (done: () => void) => ?Promise<mixed>,
  timeout?: number
): void;

/** A context for grouping tests together */
declare var describe: {
  /**
   * Creates a block that groups together several related tests in one "test suite"
   */
  (name: JestTestName, fn: () => void): void,

  /**
   * Only run this describe block
   */
  only(name: JestTestName, fn: () => void): void,

  /**
   * Skip running this describe block
   */
  skip(name: JestTestName, fn: () => void): void
};

/** An individual test unit */
declare var it: {
  /**
   * An individual test unit
   *
   * @param {JestTestName} Name of Test
   * @param {Function} Test
   * @param {number} Timeout for the test, in milliseconds.
   */
  (
    name: JestTestName,
    fn?: (done: () => void) => ?Promise<mixed>,
    timeout?: number
  ): void,
  /**
   * Only run this test
   *
   * @param {JestTestName} Name of Test
   * @param {Function} Test
   * @param {number} Timeout for the test, in milliseconds.
   */
  only(
    name: JestTestName,
    fn?: (done: () => void) => ?Promise<mixed>,
    timeout?: number
  ): void,
  /**
   * Skip running this test
   *
   * @param {JestTestName} Name of Test
   * @param {Function} Test
   * @param {number} Timeout for the test, in milliseconds.
   */
  skip(
    name: JestTestName,
    fn?: (done: () => void) => ?Promise<mixed>,
    timeout?: number
  ): void,
  /**
   * Run the test concurrently
   *
   * @param {JestTestName} Name of Test
   * @param {Function} Test
   * @param {number} Timeout for the test, in milliseconds.
   */
  concurrent(
    name: JestTestName,
    fn?: (done: () => void) => ?Promise<mixed>,
    timeout?: number
  ): void
};
declare function fit(
  name: JestTestName,
  fn: (done: () => void) => ?Promise<mixed>,
  timeout?: number
): void;
/** An individual test unit */
declare var test: typeof it;
/** A disabled group of tests */
declare var xdescribe: typeof describe;
/** A focused group of tests */
declare var fdescribe: typeof describe;
/** A disabled individual test */
declare var xit: typeof it;
/** A disabled individual test */
declare var xtest: typeof it;

type JestPrettyFormatColors = {
  comment: { close: string, open: string },
  content: { close: string, open: string },
  prop: { close: string, open: string },
  tag: { close: string, open: string },
  value: { close: string, open: string },
};

type JestPrettyFormatIndent = string => string;
type JestPrettyFormatRefs = Array<any>;
type JestPrettyFormatPrint = any => string;
type JestPrettyFormatStringOrNull = string | null;

type JestPrettyFormatOptions = {|
  callToJSON: boolean,
  edgeSpacing: string,
  escapeRegex: boolean,
  highlight: boolean,
  indent: number,
  maxDepth: number,
  min: boolean,
  plugins: JestPrettyFormatPlugins,
  printFunctionName: boolean,
  spacing: string,
  theme: {|
    comment: string,
    content: string,
    prop: string,
    tag: string,
    value: string,
  |},
|};

type JestPrettyFormatPlugin = {
  print: (
    val: any,
    serialize: JestPrettyFormatPrint,
    indent: JestPrettyFormatIndent,
    opts: JestPrettyFormatOptions,
    colors: JestPrettyFormatColors,
  ) => string,
  test: any => boolean,
};

type JestPrettyFormatPlugins = Array<JestPrettyFormatPlugin>;

/** The expect function is used every time you want to test a value */
declare var expect: {
  /** The object that you want to make assertions against */
  (value: any): JestExpectType & JestPromiseType & EnzymeMatchersType & DomTestingLibraryType,
  /** Add additional Jasmine matchers to Jest's roster */
  extend(matchers: { [name: string]: JestMatcher }): void,
  /** Add a module that formats application-specific data structures. */
  addSnapshotSerializer(pluginModule: JestPrettyFormatPlugin): void,
  assertions(expectedAssertions: number): void,
  hasAssertions(): void,
  any(value: mixed): JestAsymmetricEqualityType,
  anything(): any,
  arrayContaining(value: Array<mixed>): Array<mixed>,
  objectContaining(value: Object): Object,
  /** Matches any received string that contains the exact expected string. */
  stringContaining(value: string): string,
  stringMatching(value: string | RegExp): string
};

// TODO handle return type
// http://jasmine.github.io/2.4/introduction.html#section-Spies
declare function spyOn(value: mixed, method: string): Object;

/** Holds all functions related to manipulating test runner */
declare var jest: JestObjectType;

/**
 * The global Jasmine object, this is generally not exposed as the public API,
 * using features inside here could break in later versions of Jest.
 */
declare var jasmine: {
  DEFAULT_TIMEOUT_INTERVAL: number,
  any(value: mixed): JestAsymmetricEqualityType,
  anything(): any,
  arrayContaining(value: Array<mixed>): Array<mixed>,
  clock(): JestClockType,
  createSpy(name: string): JestSpyType,
  createSpyObj(
    baseName: string,
    methodNames: Array<string>
  ): { [methodName: string]: JestSpyType },
  objectContaining(value: Object): Object,
  stringMatching(value: string): string
};


================================================
FILE: flow-typed/npm/lodash_v4.x.x.js
================================================
// flow-typed signature: 213ae107c05372e2489e50a054136496
// flow-typed version: 08e518e6e8/lodash_v4.x.x/flow_>=v0.63.x

declare module "lodash" {
  declare type __CurriedFunction1<A, R, AA: A> = (...r: [AA]) => R;
  declare type CurriedFunction1<A, R> = __CurriedFunction1<A, R, *>;

  declare type __CurriedFunction2<A, B, R, AA: A, BB: B> = ((
    ...r: [AA]
  ) => CurriedFunction1<BB, R>) &
    ((...r: [AA, BB]) => R);
  declare type CurriedFunction2<A, B, R> = __CurriedFunction2<A, B, R, *, *>;

  declare type __CurriedFunction3<A, B, C, R, AA: A, BB: B, CC: C> = ((
    ...r: [AA]
  ) => CurriedFunction2<BB, CC, R>) &
    ((...r: [AA, BB]) => CurriedFunction1<CC, R>) &
    ((...r: [AA, BB, CC]) => R);
  declare type CurriedFunction3<A, B, C, R> = __CurriedFunction3<
    A,
    B,
    C,
    R,
    *,
    *,
    *
  >;

  declare type __CurriedFunction4<
    A,
    B,
    C,
    D,
    R,
    AA: A,
    BB: B,
    CC: C,
    DD: D
  > = ((...r: [AA]) => CurriedFunction3<BB, CC, DD, R>) &
    ((...r: [AA, BB]) => CurriedFunction2<CC, DD, R>) &
    ((...r: [AA, BB, CC]) => CurriedFunction1<DD, R>) &
    ((...r: [AA, BB, CC, DD]) => R);
  declare type CurriedFunction4<A, B, C, D, R> = __CurriedFunction4<
    A,
    B,
    C,
    D,
    R,
    *,
    *,
    *,
    *
  >;

  declare type __CurriedFunction5<
    A,
    B,
    C,
    D,
    E,
    R,
    AA: A,
    BB: B,
    CC: C,
    DD: D,
    EE: E
  > = ((...r: [AA]) => CurriedFunction4<BB, CC, DD, EE, R>) &
    ((...r: [AA, BB]) => CurriedFunction3<CC, DD, EE, R>) &
    ((...r: [AA, BB, CC]) => CurriedFunction2<DD, EE, R>) &
    ((...r: [AA, BB, CC, DD]) => CurriedFunction1<EE, R>) &
    ((...r: [AA, BB, CC, DD, EE]) => R);
  declare type CurriedFunction5<A, B, C, D, E, R> = __CurriedFunction5<
    A,
    B,
    C,
    D,
    E,
    R,
    *,
    *,
    *,
    *,
    *
  >;

  declare type __CurriedFunction6<
    A,
    B,
    C,
    D,
    E,
    F,
    R,
    AA: A,
    BB: B,
    CC: C,
    DD: D,
    EE: E,
    FF: F
  > = ((...r: [AA]) => CurriedFunction5<BB, CC, DD, EE, FF, R>) &
    ((...r: [AA, BB]) => CurriedFunction4<CC, DD, EE, FF, R>) &
    ((...r: [AA, BB, CC]) => CurriedFunction3<DD, EE, FF, R>) &
    ((...r: [AA, BB, CC, DD]) => CurriedFunction2<EE, FF, R>) &
    ((...r: [AA, BB, CC, DD, EE]) => CurriedFunction1<FF, R>) &
    ((...r: [AA, BB, CC, DD, EE, FF]) => R);
  declare type CurriedFunction6<A, B, C, D, E, F, R> = __CurriedFunction6<
    A,
    B,
    C,
    D,
    E,
    F,
    R,
    *,
    *,
    *,
    *,
    *,
    *
  >;

  declare type Curry = (<A, R>((...r: [A]) => R) => CurriedFunction1<A, R>) &
    (<A, B, R>((...r: [A, B]) => R) => CurriedFunction2<A, B, R>) &
    (<A, B, C, R>((...r: [A, B, C]) => R) => CurriedFunction3<A, B, C, R>) &
    (<A, B, C, D, R>(
      (...r: [A, B, C, D]) => R
    ) => CurriedFunction4<A, B, C, D, R>) &
    (<A, B, C, D, E, R>(
      (...r: [A, B, C, D, E]) => R
    ) => CurriedFunction5<A, B, C, D, E, R>) &
    (<A, B, C, D, E, F, R>(
      (...r: [A, B, C, D, E, F]) => R
    ) => CurriedFunction6<A, B, C, D, E, F, R>);

  declare type UnaryFn<A, R> = (a: A) => R;

  declare type TemplateSettings = {
    escape?: RegExp,
    evaluate?: RegExp,
    imports?: Object,
    interpolate?: RegExp,
    variable?: string
  };

  declare type TruncateOptions = {
    length?: number,
    omission?: string,
    separator?: RegExp | string
  };

  declare type DebounceOptions = {
    leading?: boolean,
    maxWait?: number,
    trailing?: boolean
  };

  declare type ThrottleOptions = {
    leading?: boolean,
    trailing?: boolean
  };

  declare type NestedArray<T> = Array<Array<T>>;

  declare type matchesIterateeShorthand = Object;
  declare type matchesPropertyIterateeShorthand = [string, any];
  declare type propertyIterateeShorthand = string;

  declare type OPredicate<A, O> =
    | ((value: A, key: string, object: O) => any)
    | matchesIterateeShorthand
    | matchesPropertyIterateeShorthand
    | propertyIterateeShorthand;

  declare type OIterateeWithResult<V, O, R> =
    | Object
    | string
    | ((value: V, key: string, object: O) => R);
  declare type OIteratee<O> = OIterateeWithResult<any, O, any>;
  declare type OFlatMapIteratee<T, U> = OIterateeWithResult<any, T, Array<U>>;

  declare type Predicate<T> =
    | ((value: T, index: number, array: Array<T>) => any)
    | matchesIterateeShorthand
    | matchesPropertyIterateeShorthand
    | propertyIterateeShorthand;

  declare type _ValueOnlyIteratee<T> = (value: T) => mixed;
  declare type ValueOnlyIteratee<T> = _ValueOnlyIteratee<T> | string;
  declare type _Iteratee<T> = (
    item: T,
    index: number,
    array: ?Array<T>
  ) => mixed;
  declare type Iteratee<T> = _Iteratee<T> | Object | string;
  declare type FlatMapIteratee<T, U> =
    | ((item: T, index: number, array: ?$ReadOnlyArray<T>) => Array<U>)
    | Object
    | string;
  declare type Comparator<T> = (item: T, item2: T) => boolean;

  declare type MapIterator<T, U> =
    | ((item: T, index: number, array: Array<T>) => U)
    | propertyIterateeShorthand;

  declare type ReadOnlyMapIterator<T, U> =
    | ((item: T, index: number, array: $ReadOnlyArray<T>) => U)
    | propertyIterateeShorthand;

  declare type OMapIterator<T, O, U> =
    | ((item: T, key: string, object: O) => U)
    | propertyIterateeShorthand;

  declare class Lodash {
    // Array
    chunk<T>(array?: ?Array<T>, size?: ?number): Array<Array<T>>;
    compact<T, N: ?T>(array?: ?Array<N>): Array<T>;
    concat<T>(base?: ?Array<T>, ...elements: Array<any>): Array<T | any>;
    difference<T>(array?: ?$ReadOnlyArray<T>, values?: ?$ReadOnlyArray<T>): Array<T>;
    differenceBy<T>(
      array?: ?$ReadOnlyArray<T>,
      values?: ?$ReadOnlyArray<T>,
      iteratee?: ?ValueOnlyIteratee<T>
    ): T[];
    differenceWith<T>(array?: ?$ReadOnlyArray<T>, values?: ?$ReadOnlyArray<T>, comparator?: ?Comparator<T>): T[];
    drop<T>(array?: ?Array<T>, n?: ?number): Array<T>;
    dropRight<T>(array?: ?Array<T>, n?: ?number): Array<T>;
    dropRightWhile<T>(array?: ?Array<T>, predicate?: ?Predicate<T>): Array<T>;
    dropWhile<T>(array?: ?Array<T>, predicate?: ?Predicate<T>): Array<T>;
    fill<T, U>(
      array?: ?Array<T>,
      value?: ?U,
      start?: ?number,
      end?: ?number
    ): Array<T | U>;
    findIndex<T>(
      array: $ReadOnlyArray<T>,
      predicate?: ?Predicate<T>,
      fromIndex?: ?number
    ): number;
    findIndex<T>(
      array: void | null,
      predicate?: ?Predicate<T>,
      fromIndex?: ?number
    ): -1;
    findLastIndex<T>(
      array: $ReadOnlyArray<T>,
      predicate?: ?Predicate<T>,
      fromIndex?: ?number
    ): number;
    findLastIndex<T>(
      array: void | null,
      predicate?: ?Predicate<T>,
      fromIndex?: ?number
    ): -1;
    // alias of _.head
    first<T>(array: ?Array<T>): T;
    flatten<T, X>(array?: ?Array<Array<T> | X>): Array<T | X>;
    flattenDeep<T>(array?: ?any[]): Array<T>;
    flattenDepth(array?: ?any[], depth?: ?number): any[];
    fromPairs<A, B>(pairs?: ?Array<[A, B]>): { [key: A]: B };
    head<T>(array: ?Array<T>): T;
    indexOf<T>(array: Array<T>, value: T, fromIndex?: number): number;
    indexOf<T>(array: void | null, value?: ?T, fromIndex?: ?number): -1;
    initial<T>(array: ?Array<T>): Array<T>;
    intersection<T>(...arrays?: Array<Array<T>>): Array<T>;
    //Workaround until (...parameter: T, parameter2: U) works
    intersectionBy<T>(a1?: ?Array<T>, iteratee?: ?ValueOnlyIteratee<T>): Array<T>;
    intersectionBy<T>(
      a1?: ?Array<T>,
      a2?: ?Array<T>,
      iteratee?: ?ValueOnlyIteratee<T>
    ): Array<T>;
    intersectionBy<T>(
      a1?: ?Array<T>,
      a2?: ?Array<T>,
      a3?: ?Array<T>,
      iteratee?: ?ValueOnlyIteratee<T>
    ): Array<T>;
    intersectionBy<T>(
      a1?: ?Array<T>,
      a2?: ?Array<T>,
      a3?: ?Array<T>,
      a4?: ?Array<T>,
      iteratee?: ?ValueOnlyIteratee<T>
    ): Array<T>;
    //Workaround until (...parameter: T, parameter2: U) works
    intersectionWith<T>(a1?: ?Array<T>, comparator?: ?Comparator<T>): Array<T>;
    intersectionWith<T>(
      a1?: ?Array<T>,
      a2?: ?Array<T>,
      comparator?: ?Comparator<T>
    ): Array<T>;
    intersectionWith<T>(
      a1?: ?Array<T>,
      a2?: ?Array<T>,
      a3?: ?Array<T>,
      comparator?: ?Comparator<T>
    ): Array<T>;
    intersectionWith<T>(
      a1?: ?Array<T>,
      a2?: ?Array<T>,
      a3?: ?Array<T>,
      a4?: ?Array<T>,
      comparator?: ?Comparator<T>
    ): Array<T>;
    join<T>(array: Array<T>, separator?: ?string): string;
    join<T>(array: void | null, separator?: ?string): '';
    last<T>(array: ?Array<T>): T;
    lastIndexOf<T>(array: Array<T>, value?: ?T, fromIndex?: ?number): number;
    lastIndexOf<T>(array: void | null, value?: ?T, fromIndex?: ?number): -1;
    nth<T>(array: T[], n?: ?number): T;
    nth(array: void | null, n?: ?number): void;
    pull<T>(array: Array<T>, ...values?: Array<?T>): Array<T>;
    pull<T: void | null>(array: T, ...values?: Array<?any>): T;
    pullAll<T>(array: Array<T>, values?: ?Array<T>): Array<T>;
    pullAll<T: void | null>(array: T, values?: ?Array<any>): T;
    pullAllBy<T>(
      array: Array<T>,
      values?: ?Array<T>,
      iteratee?: ?ValueOnlyIteratee<T>
    ): Array<T>;
    pullAllBy<T: void | null>(
      array: T,
      values?: ?Array<any>,
      iteratee?: ?ValueOnlyIteratee<any>
    ): T;
    pullAllWith<T>(array: T[], values?: ?T[], comparator?: ?Function): T[];
    pullAllWith<T: void | null>(array: T, values?: ?Array<any>, comparator?: ?Function): T;
    pullAt<T>(array?: ?Array<T>, ...indexed?: Array<?number>): Array<T>;
    pullAt<T>(array?: ?Array<T>, indexed?: ?Array<number>): Array<T>;
    remove<T>(array?: ?Array<T>, predicate?: ?Predicate<T>): Array<T>;
    reverse<T>(array: Array<T>): Array<T>;
    reverse<T: void | null>(array: T): T;
    slice<T>(array?: ?Array<T>, start?: ?number, end?: ?number): Array<T>;
    sortedIndex<T>(array: Array<T>, value: T): number;
    sortedIndex<T>(array: void | null, value: ?T): 0;
    sortedIndexBy<T>(
      array: Array<T>,
      value?: ?T,
      iteratee?: ?ValueOnlyIteratee<T>
    ): number;
    sortedIndexBy<T>(
      array: void | null,
      value?: ?T,
      iteratee?: ?ValueOnlyIteratee<T>
    ): 0;
    sortedIndexOf<T>(array: Array<T>, value: T): number;
    sortedIndexOf<T>(array: void | null, value?: ?T): -1;
    sortedLastIndex<T>(array: Array<T>, value: T): number;
    sortedLastIndex<T>(array: void | null, value?: ?T): 0;
    sortedLastIndexBy<T>(
      array: Array<T>,
      value: T,
      iteratee?: ValueOnlyIteratee<T>
    ): number;
    sortedLastIndexBy<T>(
      array: void | null,
      value?: ?T,
      iteratee?: ?ValueOnlyIteratee<T>
    ): 0;
    sortedLastIndexOf<T>(array: Array<T>, value: T): number;
    sortedLastIndexOf<T>(array: void | null, value?: ?T): -1;
    sortedUniq<T>(array?: ?Array<T>): Array<T>;
    sortedUniqBy<T>(array?: ?Array<T>, iteratee?: ?(value: T) => mixed): Array<T>;
    tail<T>(array?: ?Array<T>): Array<T>;
    take<T>(array?: ?Array<T>, n?: ?number): Array<T>;
    takeRight<T>(array?: ?Array<T>, n?: ?number): Array<T>;
    takeRightWhile<T>(array?: ?Array<T>, predicate?: ?Predicate<T>): Array<T>;
    takeWhile<T>(array?: ?Array<T>, predicate?: ?Predicate<T>): Array<T>;
    union<T>(...arrays?: Array<Array<T>>): Array<T>;
    //Workaround until (...parameter: T, parameter2: U) works
    unionBy<T>(a1?: ?Array<T>, iteratee?: ?ValueOnlyIteratee<T>): Array<T>;
    unionBy<T>(
      a1?: ?Array<T>,
      a2: Array<T>,
      iteratee?: ValueOnlyIteratee<T>
    ): Array<T>;
    unionBy<T>(
      a1: Array<T>,
      a2: Array<T>,
      a3: Array<T>,
      iteratee?: ValueOnlyIteratee<T>
    ): Array<T>;
    unionBy<T>(
      a1: Array<T>,
      a2: Array<T>,
      a3: Array<T>,
      a4: Array<T>,
      iteratee?: ValueOnlyIteratee<T>
    ): Array<T>;
    //Workaround until (...parameter: T, parameter2: U) works
    unionWith<T>(a1?: ?Array<T>, comparator?: ?Comparator<T>): Array<T>;
    unionWith<T>(
      a1: Array<T>,
      a2: Array<T>,
      comparator?: Comparator<T>
    ): Array<T>;
    unionWith<T>(
      a1: Array<T>,
      a2: Array<T>,
      a3: Array<T>,
      comparator?: Comparator<T>
    ): Array<T>;
    unionWith<T>(
      a1: Array<T>,
      a2: Array<T>,
      a3: Array<T>,
      a4: Array<T>,
      comparator?: Comparator<T>
    ): Array<T>;
    uniq<T>(array?: ?Array<T>): Array<T>;
    uniqBy<T>(array?: ?Array<T>, iteratee?: ?ValueOnlyIteratee<T>): Array<T>;
    uniqWith<T>(array?: ?Array<T>, comparator?: ?Comparator<T>): Array<T>;
    unzip<T>(array?: ?Array<T>): Array<T>;
    unzipWith<T>(array: ?Array<T>, iteratee?: ?Iteratee<T>): Array<T>;
    without<T>(array?: ?Array<T>, ...values?: Array<?T>): Array<T>;
    xor<T>(...array: Array<Array<T>>): Array<T>;
    //Workaround until (...parameter: T, parameter2: U) works
    xorBy<T>(a1?: ?Array<T>, iteratee?: ?ValueOnlyIteratee<T>): Array<T>;
    xorBy<T>(
      a1: Array<T>,
      a2: Array<T>,
      iteratee?: ValueOnlyIteratee<T>
    ): Array<T>;
    xorBy<T>(
      a1: Array<T>,
      a2: Array<T>,
      a3: Array<T>,
      iteratee?: ValueOnlyIteratee<T>
    ): Array<T>;
    xorBy<T>(
      a1: Array<T>,
      a2: Array<T>,
      a3: Array<T>,
      a4: Array<T>,
      iteratee?: ValueOnlyIteratee<T>
    ): Array<T>;
    //Workaround until (...parameter: T, parameter2: U) works
    xorWith<T>(a1?: ?Array<T>, comparator?: ?Comparator<T>): Array<T>;
    xorWith<T>(
      a1: Array<T>,
      a2: Array<T>,
      comparator?: Comparator<T>
    ): Array<T>;
    xorWith<T>(
      a1: Array<T>,
      a2: Array<T>,
      a3: Array<T>,
      comparator?: Comparator<T>
    ): Array<T>;
    xorWith<T>(
      a1: Array<T>,
      a2: Array<T>,
      a3: Array<T>,
      a4: Array<T>,
      comparator?: Comparator<T>
    ): Array<T>;
    zip<A, B>(a1?: ?A[], a2?: ?B[]): Array<[A, B]>;
    zip<A, B, C>(a1: A[], a2: B[], a3: C[]): Array<[A, B, C]>;
    zip<A, B, C, D>(a1: A[], a2: B[], a3: C[], a4: D[]): Array<[A, B, C, D]>;
    zip<A, B, C, D, E>(
      a1: A[],
      a2: B[],
      a3: C[],
      a4: D[],
      a5: E[]
    ): Array<[A, B, C, D, E]>;

    zipObject<K, V>(props: Array<K>, values?: ?Array<V>): { [key: K]: V };
    zipObject<K, V>(props: void | null, values?: ?Array<V>): {};
    zipObjectDeep(props: any[], values?: ?any): Object;
    zipObjectDeep(props: void | null, values?: ?any): {};

    zipWith<A>(a1?: ?Array<A>): Array<[A]>;
    zipWith<T, A>(a1: Array<A>, iteratee: (A) => T): Array<T>;

    zipWith<A, B>(a1: Array<A>, a2: Array<B>): Array<[A, B]>;
    zipWith<T, A, B>(
      a1: Array<A>,
      a2: Array<B>,
      iteratee: (A, B) => T
    ): Array<T>;

    zipWith<A, B, C>(
      a1: Array<A>,
      a2: Array<B>,
      a3: Array<C>
    ): Array<[A, B, C]>;
    zipWith<T, A, B, C>(
      a1: Array<A>,
      a2: Array<B>,
      a3: Array<C>,
      iteratee: (A, B, C) => T
    ): Array<T>;

    zipWith<A, B, C, D>(
      a1: Array<A>,
      a2: Array<B>,
      a3: Array<C>,
      a4: Array<D>
    ): Array<[A, B, C, D]>;
    zipWith<T, A, B, C, D>(
      a1: Array<A>,
      a2: Array<B>,
      a3: Array<C>,
      a4: Array<D>,
      iteratee: (A, B, C, D) => T
    ): Array<T>;

    // Collection
    countBy<T>(array: Array<T>, iteratee?: ?ValueOnlyIteratee<T>): Object;
    countBy<T>(array: void | null, iteratee?: ?ValueOnlyIteratee<T>): {};
    countBy<T: Object>(object: T, iteratee?: ?ValueOnlyIteratee<T>): Object;
    // alias of _.forEach
    each<T>(array: Array<T>, iteratee?: ?Iteratee<T>): Array<T>;
    each<T: void | null>(array: T, iteratee?: ?Iteratee<any>): T;
    each<T: Object>(object: T, iteratee?: ?OIteratee<T>): T;
    // alias of _.forEachRight
    eachRight<T>(array: Array<T>, iteratee?: ?Iteratee<T>): Array<T>;
    eachRight<T: void | null>(array: T, iteratee?: ?Iteratee<any>): T;
    eachRight<T: Object>(object: T, iteratee?: OIteratee<T>): T;
    every<T>(array?: ?Array<T>, iteratee?: ?Iteratee<T>): boolean;
    every<T: Object>(object: T, iteratee?: OIteratee<T>): boolean;
    filter<T>(array?: ?Array<T>, predicate?: ?Predicate<T>): Array<T>;
    filter<A, T: { [id: string]: A }>(
      object: T,
      predicate?: OPredicate<A, T>
    ): Array<A>;
    find<T>(
      array: $ReadOnlyArray<T>,
      predicate?: ?Predicate<T>,
      fromIndex?: ?number
    ): T | void;
    find<T>(
      array: void | null,
      predicate?: ?Predicate<T>,
      fromIndex?: ?number
    ): void;
    find<V, A, T: { [id: string]: A }>(
      object: T,
      predicate?: OPredicate<A, T>,
      fromIndex?: number
    ): V;
    findLast<T>(
      array: ?$ReadOnlyArray<T>,
      predicate?: ?Predicate<T>,
      fromIndex?: ?number
    ): T | void;
    findLast<V, A, T: { [id: string]: A }>(
      object: T,
      predicate?: ?OPredicate<A, T>
    ): V;
    flatMap<T, U>(
      array?: ?$ReadOnlyArray<T>,
      iteratee?: ?FlatMapIteratee<T, U>
    ): Array<U>;
    flatMap<T: Object, U>(
      object: T,
      iteratee?: OFlatMapIteratee<T, U>
    ): Array<U>;
    flatMapDeep<T, U>(
      array?: ?$ReadOnlyArray<T>,
      iteratee?: ?FlatMapIteratee<T, U>
    ): Array<U>;
    flatMapDeep<T: Object, U>(
      object: T,
      iteratee?: ?OFlatMapIteratee<T, U>
    ): Array<U>;
    flatMapDepth<T, U>(
      array?: ?Array<T>,
      iteratee?: ?FlatMapIteratee<T, U>,
      depth?: ?number
    ): Array<U>;
    flatMapDepth<T: Object, U>(
      object: T,
      iteratee?: OFlatMapIteratee<T, U>,
      depth?: number
    ): Array<U>;
    forEach<T>(array: Array<T>, iteratee?: ?Iteratee<T>): Array<T>;
    forEach<T: void | null>(array: T, iteratee?: ?Iteratee<any>): T;
    forEach<T: Object>(object: T, iteratee?: ?OIteratee<T>): T;
    forEachRight<T>(array: Array<T>, iteratee?: ?Iteratee<T>): Array<T>;
    forEachRight<T: void | null>(array: T, iteratee?: ?Iteratee<any>): T;
    forEachRight<T: Object>(object: T, iteratee?: ?OIteratee<T>): T;
    groupBy<V, T>(
      array: $ReadOnlyArray<T>,
      iteratee?: ?ValueOnlyIteratee<T>
    ): { [key: V]: Array<T> };
    groupBy(
      array: void | null,
      iteratee?: ?ValueOnlyIteratee<any>
    ): {};
    groupBy<V, A, T: { [id: string]: A }>(
      object: T,
      iteratee?: ValueOnlyIteratee<A>
    ): { [key: V]: Array<A> };
    includes<T>(array: Array<T>, value: T, fromIndex?: ?number): boolean;
    includes<T>(array: void | null, value?: ?T, fromIndex?: ?number): false;
    includes<T: Object>(object: T, value: any, fromIndex?: number): boolean;
    includes(str: string, value: string, fromIndex?: number): boolean;
    invokeMap<T>(
      array?: ?Array<T>,
      path?: ?((value: T) => Array<string> | string) | Array<string> | string,
      ...args?: Array<any>
    ): Array<any>;
    invokeMap<T: Object>(
      object: T,
      path: ((value: any) => Array<string> | string) | Array<string> | string,
      ...args?: Array<any>
    ): Array<any>;
    keyBy<T, V>(
      array: $ReadOnlyArray<T>,
      iteratee?: ?ValueOnlyIteratee<T>
    ): { [key: V]: ?T };
    keyBy(
      array: void | null,
      iteratee?: ?ValueOnlyIteratee<*>
    ): {};
    keyBy<V, A, I, T: { [id: I]: A }>(
      object: T,
      iteratee?: ?ValueOnlyIteratee<A>
    ): { [key: V]: ?A };
    map<T, U>(array?: ?Array<T>, iteratee?: ?MapIterator<T, U>): Array<U>;
    map<T, U>(
      array: ?$ReadOnlyArray<T>,
      iteratee?: ReadOnlyMapIterator<T, U>
    ): Array<U>,
    map<V, T: Object, U>(
      object: ?T,
      iteratee?: OMapIterator<V, T, U>
    ): Array<U>;
    map(
      str: ?string,
      iteratee?: (char: string, index: number, str: string) => any
    ): string;
    orderBy<T>(
      array: $ReadOnlyArray<T>,
      iteratees?: ?$ReadOnlyArray<Iteratee<T>> | ?string,
      orders?: ?$ReadOnlyArray<"asc" | "desc"> | ?string
    ): Array<T>;
    orderBy<T>(
      array: null | void,
      iteratees?: ?$ReadOnlyArray<Iteratee<T>> | ?string,
      orders?: ?$ReadOnlyArray<"asc" | "desc"> | ?string
    ): Array<T>;
    orderBy<V, T: Object>(
      object: T,
      iteratees?: $ReadOnlyArray<OIteratee<*>> | string,
      orders?: $ReadOnlyArray<"asc" | "desc"> | string
    ): Array<V>;
    partition<T>(
      array?: ?Array<T>,
      predicate?: ?Predicate<T>
    ): [Array<T>, Array<T>];
    partition<V, A, T: { [id: string]: A }>(
      object: T,
      predicate?: OPredicate<A, T>
    ): [Array<V>, Array<V>];
    reduce<T, U>(
      array: Array<T>,
      iteratee?: (
        accumulator: U,
        value: T,
        index: number,
        array: ?Array<T>
      ) => U,
      accumulator?: U
    ): U;
    reduce<T, U>(
      array: void | null,
      iteratee?: ?(
        accumulator: U,
        value: T,
        index: number,
        array: ?Array<T>
      ) => U,
      accumulator?: ?U
    ): void | null;
    reduce<T: Object, U>(
      object: T,
      iteratee?: (accumulator: U, value: any, key: string, object: T) => U,
      accumulator?: U
    ): U;
    reduceRight<T, U>(
      array: void | null,
      iteratee?: ?(
        accumulator: U,
        value: T,
        index: number,
        array: ?Array<T>
      ) => U,
      accumulator?: ?U
    ): void | null;
    reduceRight<T, U>(
      array: Array<T>,
      iteratee?: ?(
        accumulator: U,
        value: T,
        index: number,
        array: ?Array<T>
      ) => U,
      accumulator?: ?U
    ): U;
    reduceRight<T: Object, U>(
      object: T,
      iteratee?: ?(accumulator: U, value: any, key: string, object: T) => U,
      accumulator?: ?U
    ): U;
    reject<T>(array: ?Array<T>, predicate?: Predicate<T>): Array<T>;
    reject<V: Object, A, T: { [id: string]: A }>(
      object?: ?T,
      predicate?: ?OPredicate<A, T>
    ): Array<V>;
    sample<T>(array: ?Array<T>): T;
    sample<V, T: Object>(object: T): V;
    sampleSize<T>(array?: ?Array<T>, n?: ?number): Array<T>;
    sampleSize<V, T: Object>(object: T, n?: number): Array<V>;
    shuffle<T>(array: ?Array<T>): Array<T>;
    shuffle<V, T: Object>(object: T): Array<V>;
    size(collection: Array<any> | Object | string): number;
    some<T>(array: ?Array<T>, predicate?: Predicate<T>): boolean;
    some<T>(array: void | null, predicate?: ?Predicate<T>): false;
    some<A, T: { [id: string]: A }>(
      object?: ?T,
      predicate?: OPredicate<A, T>
    ): boolean;
    sortBy<T>(
      array: ?$ReadOnlyArray<T>,
      ...iteratees?: $ReadOnlyArray<Iteratee<T>>
    ): Array<T>;
    sortBy<T>(
      array: ?$ReadOnlyArray<T>,
      iteratees?: $ReadOnlyArray<Iteratee<T>>
    ): Array<T>;
    sortBy<V, T: Object>(
      object: T,
      ...iteratees?: Array<OIteratee<T>>
    ): Array<V>;
    sortBy<V, T: Object>(
      object: T,
      iteratees?: $ReadOnlyArray<OIteratee<T>>
    ): Array<V>;

    // Date
    now(): number;

    // Function
    after(n: number, fn: Function): Function;
    ary(func: Function, n?: number): Function;
    before(n: number, fn: Function): Function;
    bind(func: Function, thisArg: any, ...partials: Array<any>): Function;
    bindKey(obj?: ?Object, key?: ?string, ...partials?: Array<?any>): Function;
    curry: Curry;
    curry(func: Function, arity?: number): Function;
    curryRight(func: Function, arity?: number): Function;
    debounce<F: Function>(func: F, wait?: number, options?: DebounceOptions): F;
    defer(func: Function, ...args?: Array<any>): TimeoutID;
    delay(func: Function, wait: number, ...args?: Array<any>): TimeoutID;
    flip(func: Function): Function;
    memoize<F: Function>(func: F, resolver?: Function): F;
    negate(predicate: Function): Function;
    once(func: Function): Function;
    overArgs(func?: ?Function, ...transforms?: Array<Function>): Function;
    overArgs(func?: ?Function, transforms?: ?Array<Function>): Function;
    partial(func: Function, ...partials: any[]): Function;
    partialRight(func: Function, ...partials: Array<any>): Function;
    partialRight(func: Function, partials: Array<any>): Function;
    rearg(func: Function, ...indexes: Array<number>): Function;
    rearg(func: Function, indexes: Array<number>): Function;
    rest(func: Function, start?: number): Function;
    spread(func: Function): Function;
    throttle(
      func: Function,
      wait?: number,
      options?: ThrottleOptions
    ): Function;
    unary(func: Function): Function;
    wrap(value?: any, wrapper?: ?Function): Function;

    // Lang
    castArray(value: *): any[];
    clone<T>(value: T): T;
    cloneDeep<T>(value: T): T;
    cloneDeepWith<T, U>(
      value: T,
      customizer?: ?(value: T, key: number | string, object: T, stack: any) => U
    ): U;
    cloneWith<T, U>(
      value: T,
      customizer?: ?(value: T, key: number | string, object: T, stack: any) => U
    ): U;
    conformsTo<T: { [key: string]: mixed }>(
      source: T,
      predicates: T & { [key: string]: (x: any) => boolean }
    ): boolean;
    eq(value: any, other: any): boolean;
    gt(value: any, other: any): boolean;
    gte(value: any, other: any): boolean;
    isArguments(value: void | null): false;
    isArguments(value: any): boolean;
    isArray(value: Array<any>): true;
    isArray(value: any): false;
    isArrayBuffer(value: ArrayBuffer): true;
    isArrayBuffer(value: any): false;
    isArrayLike(value: Array<any> | string | {length: number}): true;
    isArrayLike(value: any): false;
    isArrayLikeObject(value: {length: number} | Array<any>): true;
    isArrayLikeObject(value: any): false;
    isBoolean(value: boolean): true;
    isBoolean(value: any): false;
    isBuffer(value: void | null): false;
    isBuffer(value: any): boolean;
    isDate(value: Date): true;
    isDate(value: any): false;
    isElement(value: Element): true;
    isElement(value: any): false;
    isEmpty(value: void | null | '' | {} | [] | number | boolean): true;
    isEmpty(value: any): boolean;
    isEqual(value: any, other: any): boolean;
    isEqualWith<T, U>(
      value?: ?T,
      other?: ?U,
      customizer?: ?(
        objValue: any,
        otherValue: any,
        key: number | string,
        object: T,
        other: U,
        stack: any
      ) => boolean | void
    ): boolean;
    isError(value: Error): true;
    isError(value: any): false;
    isFinite(value: number): boolean;
    isFinite(value: any): false;
    isFunction(value: Function): true;
    isFunction(value: any): false;
    isInteger(value: number): boolean;
    isInteger(value: any): false;
    isLength(value: void | null): false;
    isLength(value: any): boolean;
    isMap(value: Map<any, any>): true;
    isMap(value: any): false;
    isMatch(object?: ?Object, source?: ?Object): boolean;
    isMatchWith<T: Object, U: Object>(
      object?: ?T,
      source?: ?U,
      customizer?: ?(
        objValue: any,
        srcValue: any,
        key: number | string,
        object: T,
        source: U
      ) => boolean | void
    ): boolean;
    isNaN(value: Function | string | void | null | Object): false;
    isNaN(value: number): boolean;
    isNative(value: number | string | void | null | Object): false;
    isNative(value: any): boolean;
    isNil(value: void | null): true;
    isNil(value: any): false;
    isNull(value: null): true;
    isNull(value: any): false;
    isNumber(value: number): true;
    isNumber(value: any): false;
    isObject(value: Object): true;
    isObject(value: any): false;
    isObjectLike(value: void | null): false;
    isObjectLike(value: any): boolean;
    isPlainObject(value: Object): true;
    isPlainObject(value: any): false;
    isRegExp(value: RegExp): true;
    isRegExp(value: any): false;
    isSafeInteger(value: number): boolean;
    isSafeInteger(value: any): false;
    isSet(value: Set<any>): true;
    isSet(value: any): false;
    isString(value: string): true;
    isString(
      value: number | boolean | Function | void | null | Object | Array<any>
    ): false;
    isSymbol(value: Symbol): true;
    isSymbol(value: any): false;
    isTypedArray(value: $TypedArray): true;
    isTypedArray(value: any): false;
    isUndefined(value: void): true;
    isUndefined(value: any): false;
    isWeakMap(value: WeakMap<any, any>): true;
    isWeakMap(value: any): false;
    isWeakSet(value: WeakSet<any>): true;
    isWeakSet(value: any): false;
    lt(value: any, other: any): boolean;
    lte(value: any, other: any): boolean;
    toArray(value: any): Array<any>;
    toFinite(value: void | null): 0;
    toFinite(value: any): number;
    toInteger(value: void | null): 0;
    toInteger(value: any): number;
    toLength(value: void | null): 0;
    toLength(value: any): number;
    toNumber(value: void | null): 0;
    toNumber(value: any): number;
    toPlainObject(value: any): Object;
    toSafeInteger(value: void | null): 0;
    toSafeInteger(value: any): number;
    toString(value: void | null): '';
    toString(value: any): string;

    // Math
    add(augend: number, addend: number): number;
    ceil(number: number, precision?: number): number;
    divide(dividend: number, divisor: number): number;
    floor(number: number, precision?: number): number;
    max<T>(array: ?Array<T>): T;
    maxBy<T>(array: ?Array<T>, iteratee?: Iteratee<T>): T;
    mean(array: Array<*>): number;
    meanBy<T>(array: Array<T>, iteratee?: Iteratee<T>): number;
    min<T>(array: ?Array<T>): T;
    minBy<T>(array: ?Array<T>, iteratee?: Iteratee<T>): T;
    multiply(multiplier: number, multiplicand: number): number;
    round(number: number, precision?: number): number;
    subtract(minuend: number, subtrahend: number): number;
    sum(array: Array<*>): number;
    sumBy<T>(array: Array<T>, iteratee?: Iteratee<T>): number;

    // number
    clamp(number?: number, lower?: ?number, upper?: ?number): number;
    clamp(number: ?number, lower?: ?number, upper?: ?number): 0;
    inRange(number: number, start?: number, end: number): boolean;
    random(lower?: number, upper?: number, floating?: boolean): number;

    // Object
    assign(object?: ?Object, ...sources?: Array<Object>): Object;
    assignIn(): {};
    assignIn<A, B>(a: A, b: B): A & B;
    assignIn<A, B, C>(a: A, b: B, c: C): A & B & C;
    assignIn<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D;
    assignIn<A, B, C, D, E>(a: A, b: B, c: C, d: D, e: E): A & B & C & D & E;
    assignInWith(): {};
    assignInWith<T: Object, A: Object>(
      object: T,
      s1: A,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void
    ): Object;
    assignInWith<T: Object, A: Object, B: Object>(
      object: T,
      s1: A,
      s2: B,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B
      ) => any | void
    ): Object;
    assignInWith<T: Object, A: Object, B: Object, C: Object>(
      object: T,
      s1: A,
      s2: B,
      s3: C,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B | C
      ) => any | void
    ): Object;
    assignInWith<T: Object, A: Object, B: Object, C: Object, D: Object>(
      object: T,
      s1: A,
      s2: B,
      s3: C,
      s4: D,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B | C | D
      ) => any | void
    ): Object;
    assignWith(): {};
    assignWith<T: Object, A: Object>(
      object: T,
      s1: A,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void
    ): Object;
    assignWith<T: Object, A: Object, B: Object>(
      object: T,
      s1: A,
      s2: B,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B
      ) => any | void
    ): Object;
    assignWith<T: Object, A: Object, B: Object, C: Object>(
      object: T,
      s1: A,
      s2: B,
      s3: C,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B | C
      ) => any | void
    ): Object;
    assignWith<T: Object, A: Object, B: Object, C: Object, D: Object>(
      object: T,
      s1: A,
      s2: B,
      s3: C,
      s4: D,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B | C | D
      ) => any | void
    ): Object;
    at(object?: ?Object, ...paths: Array<string>): Array<any>;
    at(object?: ?Object, paths: Array<string>): Array<any>;
    create<T>(prototype: T, properties: Object): $Supertype<T>;
    create(prototype: any, properties: void | null): {};
    defaults(object?: ?Object, ...sources?: Array<Object>): Object;
    defaultsDeep(object?: ?Object, ...sources?: Array<Object>): Object;
    // alias for _.toPairs
    entries(object?: ?Object): Array<[string, any]>;
    // alias for _.toPairsIn
    entriesIn(object?: ?Object): Array<[string, any]>;
    // alias for _.assignIn
    extend<A, B>(a?: ?A, b?: ?B): A & B;
    extend<A, B, C>(a: A, b: B, c: C): A & B & C;
    extend<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D;
    extend<A, B, C, D, E>(a: A, b: B, c: C, d: D, e: E): A & B & C & D & E;
    // alias for _.assignInWith
    extendWith<T: Object, A: Object>(
      object?: ?T,
      s1?: ?A,
      customizer?: ?(
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void
    ): Object;
    extendWith<T: Object, A: Object, B: Object>(
      object: T,
      s1: A,
      s2: B,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B
      ) => any | void
    ): Object;
    extendWith<T: Object, A: Object, B: Object, C: Object>(
      object: T,
      s1: A,
      s2: B,
      s3: C,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B | C
      ) => any | void
    ): Object;
    extendWith<T: Object, A: Object, B: Object, C: Object, D: Object>(
      object: T,
      s1: A,
      s2: B,
      s3: C,
      s4: D,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B | C | D
      ) => any | void
    ): Object;
    findKey<A, T: { [id: string]: A }>(
      object: T,
      predicate?: ?OPredicate<A, T>
    ): string | void;
    findKey<A, T: { [id: string]: A }>(
      object: void | null,
      predicate?: ?OPredicate<A, T>
    ): void;
    findLastKey<A, T: { [id: string]: A }>(
      object: T,
      predicate?: ?OPredicate<A, T>
    ): string | void;
    findLastKey<A, T: { [id: string]: A }>(
      object: void | null,
      predicate?: ?OPredicate<A, T>
    ): void;
    forIn(object: Object, iteratee?: ?OIteratee<*>): Object;
    forIn(object: void | null, iteratee?: ?OIteratee<*>): null;
    forInRight(object: Object, iteratee?: ?OIteratee<*>): Object;
    forInRight(object: void | null, iteratee?: ?OIteratee<*>): null;
    forOwn(object: Object, iteratee?: ?OIteratee<*>): Object;
    forOwn(object: void | null, iteratee?: ?OIteratee<*>): null;
    forOwnRight(object: Object, iteratee?: ?OIteratee<*>): Object;
    forOwnRight(object: void | null, iteratee?: ?OIteratee<*>): null;
    functions(object?: ?Object): Array<string>;
    functionsIn(object?: ?Object): Array<string>;
    get(
      object?: ?Object | ?Array<any>,
      path?: ?Array<string> | string,
      defaultValue?: any
    ): any;
    has(object: Object, path: Array<string> | string): boolean;
    has(object: Object, path: void | null): false;
    has(object: void | null, path?: ?Array<string> | ?string): false;
    hasIn(object: Object, path: Array<string> | string): boolean;
    hasIn(object: Object, path: void | null): false;
    hasIn(object: void | null, path?: ?Array<string> | ?string): false;
    invert(object: Object, multiVal?: ?boolean): Object;
    invert(object: void | null, multiVal?: ?boolean): {};
    invertBy(object: Object, iteratee?: ?Function): Object;
    invertBy(object: void | null, iteratee?: ?Function): {};
    invoke(
      object?: ?Object,
      path?: ?Array<string> | string,
      ...args?: Array<any>
    ): any;
    keys<K>(object?: ?{ [key: K]: any }): Array<K>;
    keys(object?: ?Object): Array<string>;
    keysIn(object?: ?Object): Array<string>;
    mapKeys(object: Object, iteratee?: ?OIteratee<*>): Object;
    mapKeys(object: void | null, iteratee?: ?OIteratee<*>): {};
    mapValues(object: Object, iteratee?: ?OIteratee<*>): Object;
    mapValues(object: void | null, iteratee?: ?OIteratee<*>): {};
    merge(object?: ?Object, ...sources?: Array<?Object>): Object;
    mergeWith(): {};
    mergeWith<T: Object, A: Object>(
      object: T,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void
    ): Object;
    mergeWith<T: Object, A: Object, B: Object>(
      object: T,
      s1: A,
      s2: B,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B
      ) => any | void
    ): Object;
    mergeWith<T: Object, A: Object, B: Object, C: Object>(
      object: T,
      s1: A,
      s2: B,
      s3: C,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B | C
      ) => any | void
    ): Object;
    mergeWith<T: Object, A: Object, B: Object, C: Object, D: Object>(
      object: T,
      s1: A,
      s2: B,
      s3: C,
      s4: D,
      customizer?: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B | C | D
      ) => any | void
    ): Object;
    omit(object?: ?Object, ...props: Array<string>): Object;
    omit(object?: ?Object, props: Array<string>): Object;
    omitBy<A, T: { [id: string]: A }>(
      object: T,
      predicate?: ?OPredicate<A, T>
    ): Object;
    omitBy<A, T: void | null>(
      object: T,
      predicate?: ?OPredicate<A, T>
    ): {};
    pick(object?: ?Object, ...props: Array<string>): Object;
    pick(object?: ?Object, props: Array<string>): Object;
    pickBy<A, T: { [id: string]: A }>(
      object: T,
      predicate?: ?OPredicate<A, T>
    ): Object;
    pickBy<A, T: void | null>(
      object: T,
      predicate?: ?OPredicate<A, T>
    ): {};
    result(
      object?: ?Object,
      path?: ?Array<string> | string,
      defaultValue?: any
    ): any;
    set(object: Object, path?: ?Array<string> | string, value: any): Object;
    set<T: void | null>(
      object: T,
      path?: ?Array<string> | string,
      value?: ?any): T;
    setWith<T>(
      object: T,
      path?: ?Array<string> | string,
      value: any,
      customizer?: (nsValue: any, key: string, nsObject: T) => any
    ): Object;
    setWith<T: void | null>(
      object: T,
      path?: ?Array<string> | string,
      value?: ?any,
      customizer?: ?(nsValue: any, key: string, nsObject: T) => any
    ): T;
    toPairs(object?: ?Object | Array<*>): Array<[string, any]>;
    toPairsIn(object?: ?Object): Array<[string, any]>;
    transform(
      collection: Object | $ReadOnlyArray<any>,
      iteratee?: ?OIteratee<*>,
      accumulator?: any
    ): any;
    transform(
      collection: void | null,
      iteratee?: ?OIteratee<*>,
      accumulator?: ?any
    ): {};
    unset(object: Object, path?: ?Array<string> | ?string): boolean;
    unset(object: void | null, path?: ?Array<string> | ?string): true;
    update(object: Object, path: string[] | string, updater: Function): Object;
    update<T: void | null>(
      object: T,
      path?: ?string[] | ?string,
      updater?: ?Function): T;
    updateWith(
      object: Object,
      path?: ?string[] | ?string,
      updater?: ?Function,
      customizer?: ?Function
    ): Object;
    updateWith<T: void | null>(
      object: T,
      path?: ?string[] | ?string,
      updater?: ?Function,
      customizer?: ?Function
    ): T;
    values(object?: ?Object): Array<any>;
    valuesIn(object?: ?Object): Array<any>;

    // Seq
    // harder to read, but this is _()
    (value: any): any;
    chain<T>(value: T): any;
    tap<T>(value: T, interceptor: (value: T) => any): T;
    thru<T1, T2>(value: T1, interceptor: (value: T1) => T2): T2;
    // TODO: _.prototype.*

    // String
    camelCase(string: string): string;
    camelCase(string: void | null): '';
    capitalize(string: string): string;
    capitalize(string: void | null): '';
    deburr(string: string): string;
    deburr(string: void | null): '';
    endsWith(string: string, target?: string, position?: ?number): boolean;
    endsWith(string: void | null, target?: ?string, position?: ?number): false;
    escape(string: string): string;
    escape(string: void | null): '';
    escapeRegExp(string: string): string;
    escapeRegExp(string: void | null): '';
    kebabCase(string: string): string;
    kebabCase(string: void | null): '';
    lowerCase(string: string): string;
    lowerCase(string: void | null): '';
    lowerFirst(string: string): string;
    lowerFirst(string: void | null): '';
    pad(string?: ?string, length?: ?number, chars?: ?string): string;
    padEnd(string?: ?string, length?: ?number, chars?: ?string): string;
    padStart(string?: ?string, length?: ?number, chars?: ?string): string;
    parseInt(string: string, radix?: ?number): number;
    repeat(string: string, n?: ?number): string;
    repeat(string: void | null, n?: ?number): '';
    replace(
      string: string,
      pattern: RegExp | string,
      replacement: ((string: string) => string) | string
    ): string;
    replace(
      string: void | null,
      pattern?: ?RegExp | ?string,
      replacement: ?((string: string) => string) | ?string
    ): '';
    snakeCase(string: string): string;
    snakeCase(string: void | null): '';
    split(
      string?: ?string,
      separator?: ?RegExp | ?string,
      limit?: ?number
    ): Array<string>;
    startCase(string: string): string;
    startCase(string: void | null): '';
    startsWith(string: string, target?: string, position?: number): boolean;
    startsWith(string: void | null, target?: ?string, position?: ?number): false;
    template(string?: ?string, options?: ?TemplateSettings): Function;
    toLower(string: string): string;
    toLower(string: void | null): '';
    toUpper(string: string): string;
    toUpper(string: void | null): '';
    trim(string: string, chars?: string): string;
    trim(string: void | null, chars?: ?string): '';
    trimEnd(string: string, chars?: ?string): string;
    trimEnd(string: void | null, chars?: ?string): '';
    trimStart(string: string, chars?: ?string): string;
    trimStart(string: void | null, chars?: ?string): '';
    truncate(string: string, options?: TruncateOptions): string;
    truncate(string: void | null, options?: ?TruncateOptions): '';
    unescape(string: string): string;
    unescape(string: void | null): '';
    upperCase(string: string): string;
    upperCase(string: void | null): '';
    upperFirst(string: string): string;
    upperFirst(string: void | null): '';
    words(string?: ?string, pattern?: ?RegExp | ?string): Array<string>;

    // Util
    attempt(func: Function, ...args: Array<any>): any;
    bindAll(object: Object, methodNames?: ?Array<string>): Object;
    bindAll<T: void | null>(object: T, methodNames?: ?Array<string>): T;
    bindAll(object: Object, ...methodNames: Array<string>): Object;
    cond(pairs?: ?NestedArray<Function>): Function;
    conforms(source?: ?Object): Function;
    constant<T>(value: T): () => T;
    defaultTo<T1: string | boolean | Object, T2>(
      value: T1,
      defaultValue: T2
    ): T1;
    // NaN is a number instead of its own type, otherwise it would behave like null/void
    defaultTo<T1: number, T2>(value: T1, defaultValue: T2): T1 | T2;
    defaultTo<T1: void | null, T2>(value: T1, defaultValue: T2): T2;
    flow: ($ComposeReverse & (funcs: Array<Function>) => Function);
    flowRight: ($Compose & (funcs: Array<Function>) => Function);
    identity<T>(value: T): T;
    iteratee(func?: any): Function;
    matches(source?: ?Object): Function;
    matchesProperty(path?: ?Array<string> | string, srcValue: any): Function;
    method(path?: ?Array<string> | string, ...args?: Array<any>): Function;
    methodOf(object?: ?Object, ...args?: Array<any>): Function;
    mixin<T: Function | Object>(
      object?: T,
      source: Object,
      options?: { chain: boolean }
    ): T;
    noConflict(): Lodash;
    noop(...args: Array<mixed>): void;
    nthArg(n?: ?number): Function;
    over(...iteratees: Array<Function>): Function;
    over(iteratees: Array<Function>): Function;
    overEvery(...predicates: Array<Function>): Function;
    overEvery(predicates: Array<Function>): Function;
    overSome(...predicates: Array<Function>): Function;
    overSome(predicates: Array<Function>): Function;
    property(path?: ?Array<string> | string): Function;
    propertyOf(object?: ?Object): Function;
    range(start: number, end: number, step?: number): Array<number>;
    range(end: number, step?: number): Array<number>;
    rangeRight(start?: ?number, end?: ?number, step?: ?number): Array<number>;
    rangeRight(end?: ?number, step?: ?number): Array<number>;
    runInContext(context?: ?Object): Function;

    stubArray(): Array<*>;
    stubFalse(): false;
    stubObject(): {};
    stubString(): "";
    stubTrue(): true;
    times(n?: ?number, ...rest?: Array<void | null>): Array<number>;
    times<T>(n: number, iteratee: (i: number) => T): Array<T>;
    toPath(value: any): Array<string>;
    uniqueId(prefix?: ?string): string;

    // Properties
    VERSION: string;
    templateSettings: TemplateSettings;
  }

  declare module.exports: Lodash;
}

declare module "lodash/fp" {
  declare type __CurriedFunction1<A, R, AA: A> = (...r: [AA]) => R;
  declare type CurriedFunction1<A, R> = __CurriedFunction1<A, R, *>;

  declare type __CurriedFunction2<A, B, R, AA: A, BB: B> = ((
    ...r: [AA]
  ) => CurriedFunction1<BB, R>) &
    ((...r: [AA, BB]) => R);
  declare type CurriedFunction2<A, B, R> = __CurriedFunction2<A, B, R, *, *>;

  declare type __CurriedFunction3<A, B, C, R, AA: A, BB: B, CC: C> = ((
    ...r: [AA]
  ) => CurriedFunction2<BB, CC, R>) &
    ((...r: [AA, BB]) => CurriedFunction1<CC, R>) &
    ((...r: [AA, BB, CC]) => R);
  declare type CurriedFunction3<A, B, C, R> = __CurriedFunction3<
    A,
    B,
    C,
    R,
    *,
    *,
    *
  >;

  declare type __CurriedFunction4<
    A,
    B,
    C,
    D,
    R,
    AA: A,
    BB: B,
    CC: C,
    DD: D
  > = ((...r: [AA]) => CurriedFunction3<BB, CC, DD, R>) &
    ((...r: [AA, BB]) => CurriedFunction2<CC, DD, R>) &
    ((...r: [AA, BB, CC]) => CurriedFunction1<DD, R>) &
    ((...r: [AA, BB, CC, DD]) => R);
  declare type CurriedFunction4<A, B, C, D, R> = __CurriedFunction4<
    A,
    B,
    C,
    D,
    R,
    *,
    *,
    *,
    *
  >;

  declare type __CurriedFunction5<
    A,
    B,
    C,
    D,
    E,
    R,
    AA: A,
    BB: B,
    CC: C,
    DD: D,
    EE: E
  > = ((...r: [AA]) => CurriedFunction4<BB, CC, DD, EE, R>) &
    ((...r: [AA, BB]) => CurriedFunction3<CC, DD, EE, R>) &
    ((...r: [AA, BB, CC]) => CurriedFunction2<DD, EE, R>) &
    ((...r: [AA, BB, CC, DD]) => CurriedFunction1<EE, R>) &
    ((...r: [AA, BB, CC, DD, EE]) => R);
  declare type CurriedFunction5<A, B, C, D, E, R> = __CurriedFunction5<
    A,
    B,
    C,
    D,
    E,
    R,
    *,
    *,
    *,
    *,
    *
  >;

  declare type __CurriedFunction6<
    A,
    B,
    C,
    D,
    E,
    F,
    R,
    AA: A,
    BB: B,
    CC: C,
    DD: D,
    EE: E,
    FF: F
  > = ((...r: [AA]) => CurriedFunction5<BB, CC, DD, EE, FF, R>) &
    ((...r: [AA, BB]) => CurriedFunction4<CC, DD, EE, FF, R>) &
    ((...r: [AA, BB, CC]) => CurriedFunction3<DD, EE, FF, R>) &
    ((...r: [AA, BB, CC, DD]) => CurriedFunction2<EE, FF, R>) &
    ((...r: [AA, BB, CC, DD, EE]) => CurriedFunction1<FF, R>) &
    ((...r: [AA, BB, CC, DD, EE, FF]) => R);
  declare type CurriedFunction6<A, B, C, D, E, F, R> = __CurriedFunction6<
    A,
    B,
    C,
    D,
    E,
    F,
    R,
    *,
    *,
    *,
    *,
    *,
    *
  >;

  declare type Curry = (<A, R>((...r: [A]) => R) => CurriedFunction1<A, R>) &
    (<A, B, R>((...r: [A, B]) => R) => CurriedFunction2<A, B, R>) &
    (<A, B, C, R>((...r: [A, B, C]) => R) => CurriedFunction3<A, B, C, R>) &
    (<A, B, C, D, R>(
      (...r: [A, B, C, D]) => R
    ) => CurriedFunction4<A, B, C, D, R>) &
    (<A, B, C, D, E, R>(
      (...r: [A, B, C, D, E]) => R
    ) => CurriedFunction5<A, B, C, D, E, R>) &
    (<A, B, C, D, E, F, R>(
      (...r: [A, B, C, D, E, F]) => R
    ) => CurriedFunction6<A, B, C, D, E, F, R>);

  declare type UnaryFn<A, R> = (a: A) => R;

  declare type TemplateSettings = {
    escape?: RegExp,
    evaluate?: RegExp,
    imports?: Object,
    interpolate?: RegExp,
    variable?: string
  };

  declare type TruncateOptions = {
    length?: number,
    omission?: string,
    separator?: RegExp | string
  };

  declare type DebounceOptions = {
    leading?: boolean,
    maxWait?: number,
    trailing?: boolean
  };

  declare type ThrottleOptions = {
    leading?: boolean,
    trailing?: boolean
  };

  declare type NestedArray<T> = Array<Array<T>>;

  declare type matchesIterateeShorthand = Object;
  declare type matchesPropertyIterateeShorthand = [string, any];
  declare type propertyIterateeShorthand = string;

  declare type OPredicate<A> =
    | ((value: A) => any)
    | matchesIterateeShorthand
    | matchesPropertyIterateeShorthand
    | propertyIterateeShorthand;

  declare type OIterateeWithResult<V, R> = Object | string | ((value: V) => R);
  declare type OIteratee<O> = OIterateeWithResult<any, any>;
  declare type OFlatMapIteratee<T, U> = OIterateeWithResult<any, Array<U>>;

  declare type Predicate<T> =
    | ((value: T) => any)
    | matchesIterateeShorthand
    | matchesPropertyIterateeShorthand
    | propertyIterateeShorthand;

  declare type _ValueOnlyIteratee<T> = (value: T) => mixed;
  declare type ValueOnlyIteratee<T> = _ValueOnlyIteratee<T> | string;
  declare type _Iteratee<T> = (item: T) => mixed;
  declare type Iteratee<T> = _Iteratee<T> | Object | string;
  declare type FlatMapIteratee<T, U> =
    | ((item: T) => Array<U>)
    | Object
    | string;
  declare type Comparator<T> = (item: T, item2: T) => boolean;

  declare type MapIterator<T, U> = ((item: T) => U) | propertyIterateeShorthand;

  declare type OMapIterator<T, U> =
    | ((item: T) => U)
    | propertyIterateeShorthand;

  declare class Lodash {
    // Array
    chunk<T>(size: number): (array: Array<T>) => Array<Array<T>>;
    chunk<T>(size: number, array: Array<T>): Array<Array<T>>;
    compact<T, N: ?T>(array?: ?$ReadOnlyArray<N>): Array<T>;
    concat<T, U, A: Array<T> | T, B: Array<U> | U>(
      base: A
    ): (elements: B) => Array<T | U>;
    concat<T, U, A: Array<T> | T, B: Array<U> | U>(
      base: A,
      elements: B
    ): Array<T | U>;
    difference<T>(values: $ReadOnlyArray<T>): (array: $ReadOnlyArray<T>) => T[];
    difference<T>(values: $ReadOnlyArray<T>, array: $ReadOnlyArray<T>): T[];
    differenceBy<T>(
      iteratee: ValueOnlyIteratee<T>
    ): ((values: $ReadOnlyArray<T>) => (array: $ReadOnlyArray<T>) => T[]) &
      ((values: $ReadOnlyArray<T>, array: $ReadOnlyArray<T>) => T[]);
    differenceBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      values: $ReadOnlyArray<T>
    ): (array: $ReadOnlyArray<T>) => T[];
    differenceBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      values: $ReadOnlyArray<T>,
      array: $ReadOnlyArray<T>
    ): T[];
    differenceWith<T>(
      values: $ReadOnlyArray<T>
    ): ((comparator: Comparator<T>) => (array: $ReadOnlyArray<T>) => T[]) &
      ((comparator: Comparator<T>, array: $ReadOnlyArray<T>) => T[]);
    differenceWith<T>(
      values: $ReadOnlyArray<T>,
      comparator: Comparator<T>
    ): (array: $ReadOnlyArray<T>) => T[];
    differenceWith<T>(values: $ReadOnlyArray<T>, comparator: Comparator<T>, array: $ReadOnlyArray<T>): T[];
    drop<T>(n: number): (array: Array<T>) => Array<T>;
    drop<T>(n: number, array: Array<T>): Array<T>;
    dropLast<T>(n: number): (array: Array<T>) => Array<T>;
    dropLast<T>(n: number, array: Array<T>): Array<T>;
    dropRight<T>(n: number): (array: Array<T>) => Array<T>;
    dropRight<T>(n: number, array: Array<T>): Array<T>;
    dropRightWhile<T>(predicate: Predicate<T>): (array: Array<T>) => Array<T>;
    dropRightWhile<T>(predicate: Predicate<T>, array: Array<T>): Array<T>;
    dropWhile<T>(predicate: Predicate<T>): (array: Array<T>) => Array<T>;
    dropWhile<T>(predicate: Predicate<T>, array: Array<T>): Array<T>;
    dropLastWhile<T>(predicate: Predicate<T>): (array: Array<T>) => Array<T>;
    dropLastWhile<T>(predicate: Predicate<T>, array: Array<T>): Array<T>;
    fill<T, U>(
      start: number
    ): ((
      end: number
    ) => ((value: U) => (array: Array<T>) => Array<T | U>) &
      ((value: U, array: Array<T>) => Array<T | U>)) &
      ((end: number, value: U) => (array: Array<T>) => Array<T | U>) &
      ((end: number, value: U, array: Array<T>) => Array<T | U>);
    fill<T, U>(
      start: number,
      end: number
    ): ((value: U) => (array: Array<T>) => Array<T | U>) &
      ((value: U, array: Array<T>) => Array<T | U>);
    fill<T, U>(
      start: number,
      end: number,
      value: U
    ): (array: Array<T>) => Array<T | U>;
    fill<T, U>(
      start: number,
      end: number,
      value: U,
      array: Array<T>
    ): Array<T | U>;
    findIndex<T>(predicate: Predicate<T>): (array: $ReadOnlyArray<T>) => number;
    findIndex<T>(predicate: Predicate<T>, array: $ReadOnlyArray<T>): number;
    findIndexFrom<T>(
      predicate: Predicate<T>
    ): ((fromIndex: number) => (array: $ReadOnlyArray<T>) => number) &
      ((fromIndex: number, array: $ReadOnlyArray<T>) => number);
    findIndexFrom<T>(
      predicate: Predicate<T>,
      fromIndex: number
    ): (array: $ReadOnlyArray<T>) => number;
    findIndexFrom<T>(
      predicate: Predicate<T>,
      fromIndex: number,
      array: $ReadOnlyArray<T>
    ): number;
    findLastIndex<T>(
      predicate: Predicate<T>
    ): (array: $ReadOnlyArray<T>) => number;
    findLastIndex<T>(predicate: Predicate<T>, array: $ReadOnlyArray<T>): number;
    findLastIndexFrom<T>(
      predicate: Predicate<T>
    ): ((fromIndex: number) => (array: $ReadOnlyArray<T>) => number) &
      ((fromIndex: number, array: $ReadOnlyArray<T>) => number);
    findLastIndexFrom<T>(
      predicate: Predicate<T>,
      fromIndex: number
    ): (array: $ReadOnlyArray<T>) => number;
    findLastIndexFrom<T>(
      predicate: Predicate<T>,
      fromIndex: number,
      array: $ReadOnlyArray<T>
    ): number;
    // alias of _.head
    first<T>(array: Array<T>): T;
    flatten<T, X>(array: Array<Array<T> | X>): Array<T | X>;
    unnest<T, X>(array: Array<Array<T> | X>): Array<T | X>;
    flattenDeep<T>(array: any[]): Array<T>;
    flattenDepth(depth: number): (array: any[]) => any[];
    flattenDepth(depth: number, array: any[]): any[];
    fromPairs<A, B>(pairs: Array<[A, B]>): { [key: A]: B };
    head<T>(array: Array<T>): T;
    indexOf<T>(value: T): (array: Array<T>) => number;
    indexOf<T>(value: T, array: Array<T>): number;
    indexOfFrom<T>(
      value: T
    ): ((fromIndex: number) => (array: Array<T>) => number) &
      ((fromIndex: number, array: Array<T>) => number);
    indexOfFrom<T>(value: T, fromIndex: number): (array: Array<T>) => number;
    indexOfFrom<T>(value: T, fromIndex: number, array: Array<T>): number;
    initial<T>(array: Array<T>): Array<T>;
    init<T>(array: Array<T>): Array<T>;
    intersection<T>(a1: Array<T>): (a2: Array<T>) => Array<T>;
    intersection<T>(a1: Array<T>, a2: Array<T>): Array<T>;
    intersectionBy<T>(
      iteratee: ValueOnlyIteratee<T>
    ): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
      ((a1: Array<T>, a2: Array<T>) => Array<T>);
    intersectionBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      a1: Array<T>
    ): (a2: Array<T>) => Array<T>;
    intersectionBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      a1: Array<T>,
      a2: Array<T>
    ): Array<T>;
    intersectionWith<T>(
      comparator: Comparator<T>
    ): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
      ((a1: Array<T>, a2: Array<T>) => Array<T>);
    intersectionWith<T>(
      comparator: Comparator<T>,
      a1: Array<T>
    ): (a2: Array<T>) => Array<T>;
    intersectionWith<T>(
      comparator: Comparator<T>,
      a1: Array<T>,
      a2: Array<T>
    ): Array<T>;
    join<T>(separator: string): (array: Array<T>) => string;
    join<T>(separator: string, array: Array<T>): string;
    last<T>(array: Array<T>): T;
    lastIndexOf<T>(value: T): (array: Array<T>) => number;
    lastIndexOf<T>(value: T, array: Array<T>): number;
    lastIndexOfFrom<T>(
      value: T
    ): ((fromIndex: number) => (array: Array<T>) => number) &
      ((fromIndex: number, array: Array<T>) => number);
    lastIndexOfFrom<T>(
      value: T,
      fromIndex: number
    ): (array: Array<T>) => number;
    lastIndexOfFrom<T>(value: T, fromIndex: number, array: Array<T>): number;
    nth<T>(n: number): (array: T[]) => T;
    nth<T>(n: number, array: T[]): T;
    pull<T>(value: T): (array: Array<T>) => Array<T>;
    pull<T>(value: T, array: Array<T>): Array<T>;
    pullAll<T>(values: Array<T>): (array: Array<T>) => Array<T>;
    pullAll<T>(values: Array<T>, array: Array<T>): Array<T>;
    pullAllBy<T>(
      iteratee: ValueOnlyIteratee<T>
    ): ((values: Array<T>) => (array: Array<T>) => Array<T>) &
      ((values: Array<T>, array: Array<T>) => Array<T>);
    pullAllBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      values: Array<T>
    ): (array: Array<T>) => Array<T>;
    pullAllBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      values: Array<T>,
      array: Array<T>
    ): Array<T>;
    pullAllWith<T>(
      comparator: Function
    ): ((values: T[]) => (array: T[]) => T[]) &
      ((values: T[], array: T[]) => T[]);
    pullAllWith<T>(comparator: Function, values: T[]): (array: T[]) => T[];
    pullAllWith<T>(comparator: Function, values: T[], array: T[]): T[];
    pullAt<T>(indexed: Array<number>): (array: Array<T>) => Array<T>;
    pullAt<T>(indexed: Array<number>, array: Array<T>): Array<T>;
    remove<T>(predicate: Predicate<T>): (array: Array<T>) => Array<T>;
    remove<T>(predicate: Predicate<T>, array: Array<T>): Array<T>;
    reverse<T>(array: Array<T>): Array<T>;
    slice<T>(
      start: number
    ): ((end: number) => (array: Array<T>) => Array<T>) &
      ((end: number, array: Array<T>) => Array<T>);
    slice<T>(start: number, end: number): (array: Array<T>) => Array<T>;
    slice<T>(start: number, end: number, array: Array<T>): Array<T>;
    sortedIndex<T>(value: T): (array: Array<T>) => number;
    sortedIndex<T>(value: T, array: Array<T>): number;
    sortedIndexBy<T>(
      iteratee: ValueOnlyIteratee<T>
    ): ((value: T) => (array: Array<T>) => number) &
      ((value: T, array: Array<T>) => number);
    sortedIndexBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      value: T
    ): (array: Array<T>) => number;
    sortedIndexBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      value: T,
      array: Array<T>
    ): number;
    sortedIndexOf<T>(value: T): (array: Array<T>) => number;
    sortedIndexOf<T>(value: T, array: Array<T>): number;
    sortedLastIndex<T>(value: T): (array: Array<T>) => number;
    sortedLastIndex<T>(value: T, array: Array<T>): number;
    sortedLastIndexBy<T>(
      iteratee: ValueOnlyIteratee<T>
    ): ((value: T) => (array: Array<T>) => number) &
      ((value: T, array: Array<T>) => number);
    sortedLastIndexBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      value: T
    ): (array: Array<T>) => number;
    sortedLastIndexBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      value: T,
      array: Array<T>
    ): number;
    sortedLastIndexOf<T>(value: T): (array: Array<T>) => number;
    sortedLastIndexOf<T>(value: T, array: Array<T>): number;
    sortedUniq<T>(array: Array<T>): Array<T>;
    sortedUniqBy<T>(
      iteratee: (value: T) => mixed
    ): (array: Array<T>) => Array<T>;
    sortedUniqBy<T>(iteratee: (value: T) => mixed, array: Array<T>): Array<T>;
    tail<T>(array: Array<T>): Array<T>;
    take<T>(n: number): (array: Array<T>) => Array<T>;
    take<T>(n: number, array: Array<T>): Array<T>;
    takeRight<T>(n: number): (array: Array<T>) => Array<T>;
    takeRight<T>(n: number, array: Array<T>): Array<T>;
    takeLast<T>(n: number): (array: Array<T>) => Array<T>;
    takeLast<T>(n: number, array: Array<T>): Array<T>;
    takeRightWhile<T>(predicate: Predicate<T>): (array: Array<T>) => Array<T>;
    takeRightWhile<T>(predicate: Predicate<T>, array: Array<T>): Array<T>;
    takeLastWhile<T>(predicate: Predicate<T>): (array: Array<T>) => Array<T>;
    takeLastWhile<T>(predicate: Predicate<T>, array: Array<T>): Array<T>;
    takeWhile<T>(predicate: Predicate<T>): (array: Array<T>) => Array<T>;
    takeWhile<T>(predicate: Predicate<T>, array: Array<T>): Array<T>;
    union<T>(a1: Array<T>): (a2: Array<T>) => Array<T>;
    union<T>(a1: Array<T>, a2: Array<T>): Array<T>;
    unionBy<T>(
      iteratee: ValueOnlyIteratee<T>
    ): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
      ((a1: Array<T>, a2: Array<T>) => Array<T>);
    unionBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      a1: Array<T>
    ): (a2: Array<T>) => Array<T>;
    unionBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      a1: Array<T>,
      a2: Array<T>
    ): Array<T>;
    unionWith<T>(
      comparator: Comparator<T>
    ): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
      ((a1: Array<T>, a2: Array<T>) => Array<T>);
    unionWith<T>(
      comparator: Comparator<T>,
      a1: Array<T>
    ): (a2: Array<T>) => Array<T>;
    unionWith<T>(
      comparator: Comparator<T>,
      a1: Array<T>,
      a2: Array<T>
    ): Array<T>;
    uniq<T>(array: Array<T>): Array<T>;
    uniqBy<T>(iteratee: ValueOnlyIteratee<T>): (array: Array<T>) => Array<T>;
    uniqBy<T>(iteratee: ValueOnlyIteratee<T>, array: Array<T>): Array<T>;
    uniqWith<T>(comparator: Comparator<T>): (array: Array<T>) => Array<T>;
    uniqWith<T>(comparator: Comparator<T>, array: Array<T>): Array<T>;
    unzip<T>(array: Array<T>): Array<T>;
    unzipWith<T>(iteratee: Iteratee<T>): (array: Array<T>) => Array<T>;
    unzipWith<T>(iteratee: Iteratee<T>, array: Array<T>): Array<T>;
    without<T>(values: Array<T>): (array: Array<T>) => Array<T>;
    without<T>(values: Array<T>, array: Array<T>): Array<T>;
    xor<T>(a1: Array<T>): (a2: Array<T>) => Array<T>;
    xor<T>(a1: Array<T>, a2: Array<T>): Array<T>;
    symmetricDifference<T>(a1: Array<T>): (a2: Array<T>) => Array<T>;
    symmetricDifference<T>(a1: Array<T>, a2: Array<T>): Array<T>;
    xorBy<T>(
      iteratee: ValueOnlyIteratee<T>
    ): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
      ((a1: Array<T>, a2: Array<T>) => Array<T>);
    xorBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      a1: Array<T>
    ): (a2: Array<T>) => Array<T>;
    xorBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      a1: Array<T>,
      a2: Array<T>
    ): Array<T>;
    symmetricDifferenceBy<T>(
      iteratee: ValueOnlyIteratee<T>
    ): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
      ((a1: Array<T>, a2: Array<T>) => Array<T>);
    symmetricDifferenceBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      a1: Array<T>
    ): (a2: Array<T>) => Array<T>;
    symmetricDifferenceBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      a1: Array<T>,
      a2: Array<T>
    ): Array<T>;
    xorWith<T>(
      comparator: Comparator<T>
    ): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
      ((a1: Array<T>, a2: Array<T>) => Array<T>);
    xorWith<T>(
      comparator: Comparator<T>,
      a1: Array<T>
    ): (a2: Array<T>) => Array<T>;
    xorWith<T>(comparator: Comparator<T>, a1: Array<T>, a2: Array<T>): Array<T>;
    symmetricDifferenceWith<T>(
      comparator: Comparator<T>
    ): ((a1: Array<T>) => (a2: Array<T>) => Array<T>) &
      ((a1: Array<T>, a2: Array<T>) => Array<T>);
    symmetricDifferenceWith<T>(
      comparator: Comparator<T>,
      a1: Array<T>
    ): (a2: Array<T>) => Array<T>;
    symmetricDifferenceWith<T>(
      comparator: Comparator<T>,
      a1: Array<T>,
      a2: Array<T>
    ): Array<T>;
    zip<A, B>(a1: A[]): (a2: B[]) => Array<[A, B]>;
    zip<A, B>(a1: A[], a2: B[]): Array<[A, B]>;
    zipAll(arrays: Array<Array<any>>): Array<any>;
    zipObject<K, V>(props?: Array<K>): (values?: Array<V>) => { [key: K]: V };
    zipObject<K, V>(props?: Array<K>, values?: Array<V>): { [key: K]: V };
    zipObj(props: Array<any>): (values: Array<any>) => Object;
    zipObj(props: Array<any>, values: Array<any>): Object;
    zipObjectDeep(props: any[]): (values: any) => Object;
    zipObjectDeep(props: any[], values: any): Object;
    zipWith<T>(
      iteratee: Iteratee<T>
    ): ((a1: NestedArray<T>) => (a2: NestedArray<T>) => Array<T>) &
      ((a1: NestedArray<T>, a2: NestedArray<T>) => Array<T>);
    zipWith<T>(
      iteratee: Iteratee<T>,
      a1: NestedArray<T>
    ): (a2: NestedArray<T>) => Array<T>;
    zipWith<T>(
      iteratee: Iteratee<T>,
      a1: NestedArray<T>,
      a2: NestedArray<T>
    ): Array<T>;
    // Collection
    countBy<T>(
      iteratee: ValueOnlyIteratee<T>
    ): (collection: Array<T> | { [id: any]: T }) => { [string]: number };
    countBy<T>(
      iteratee: ValueOnlyIteratee<T>,
      collection: Array<T> | { [id: any]: T }
    ): { [string]: number };
    // alias of _.forEach
    each<T>(
      iteratee: Iteratee<T> | OIteratee<T>
    ): (collection: Array<T> | { [id: any]: T }) => Array<T>;
    each<T>(
      iteratee: Iteratee<T> | OIteratee<T>,
      collection: Array<T> | { [id: any]: T }
    ): Array<T>;
    // alias of _.forEachRight
    eachRight<T>(
      iteratee: Iteratee<T> | OIteratee<T>
    ): (collection: Array<T> | { [id: any]: T }) => Array<T>;
    eachRight<T>(
      iteratee: Iteratee<T> | OIteratee<T>,
      collection: Array<T> | { [id: any]: T }
    ): Array<T>;
    every<T>(
      iteratee: Iteratee<T> | OIteratee<T>
    ): (collection: Array<T> | { [id: any]: T }) => boolean;
    every<T>(
      iteratee: Iteratee<T> | OIteratee<T>,
      collection: Array<T> | { [id: any]: T }
    ): boolean;
    all<T>(
      iteratee: Iteratee<T> | OIteratee<T>
    ): (collection: Array<T> | { [id: any]: T }) => boolean;
    all<T>(
      iteratee: Iteratee<T> | OIteratee<T>,
      collection: Array<T> | { [id: any]: T }
    ): boolean;
    filter<T>(
      predicate: Predicate<T> | OPredicate<T>
    ): (collection: Array<T> | { [id: any]: T }) => Array<T>;
    filter<T>(
      predicate: Predicate<T> | OPredicate<T>,
      collection: Array<T> | { [id: any]: T }
    ): Array<T>;
    find<T>(
      predicate: Predicate<T> | OPredicate<T>
    ): (collection: $ReadOnlyArray<T> | { [id: any]: T }) => T | void;
    find<T>(
      predicate: Predicate<T> | OPredicate<T>,
      collection: $ReadOnlyArray<T> | { [id: any]: T }
    ): T | void;
    findFrom<T>(
      predicate: Predicate<T> | OPredicate<T>
    ): ((
      fromIndex: number
    ) => (collection: $ReadOnlyArray<T> | { [id: any]: T }) => T | void) &
      ((
        fromIndex: number,
        collection: $ReadOnlyArray<T> | { [id: any]: T }
      ) => T | void);
    findFrom<T>(
      predicate: Predicate<T> | OPredicate<T>,
      fromIndex: number
    ): (collection: Array<T> | { [id: any]: T }) => T | void;
    findFrom<T>(
      predicate: Predicate<T> | OPredicate<T>,
      fromIndex: number,
      collection: $ReadOnlyArray<T> | { [id: any]: T }
    ): T | void;
    findLast<T>(
      predicate: Predicate<T> | OPredicate<T>
    ): (collection: $ReadOnlyArray<T> | { [id: any]: T }) => T | void;
    findLast<T>(
      predicate: Predicate<T> | OPredicate<T>,
      collection: $ReadOnlyArray<T> | { [id: any]: T }
    ): T | void;
    findLastFrom<T>(
      predicate: Predicate<T> | OPredicate<T>
    ): ((
      fromIndex: number
    ) => (collection: $ReadOnlyArray<T> | { [id: any]: T }) => T | void) &
      ((
        fromIndex: number,
        collection: $ReadOnlyArray<T> | { [id: any]: T }
      ) => T | void);
    findLastFrom<T>(
      predicate: Predicate<T> | OPredicate<T>,
      fromIndex: number
    ): (collection: $ReadOnlyArray<T> | { [id: any]: T }) => T | void;
    findLastFrom<T>(
      predicate: Predicate<T> | OPredicate<T>,
      fromIndex: number,
      collection: $ReadOnlyArray<T> | { [id: any]: T }
    ): T | void;
    flatMap<T, U>(
      iteratee: FlatMapIteratee<T, U> | OFlatMapIteratee<T, U>
    ): (collection: Array<T> | { [id: any]: T }) => Array<U>;
    flatMap<T, U>(
      iteratee: FlatMapIteratee<T, U> | OFlatMapIteratee<T, U>,
      collection: Array<T> | { [id: any]: T }
    ): Array<U>;
    flatMapDeep<T, U>(
      iteratee: FlatMapIteratee<T, U> | OFlatMapIteratee<T, U>
    ): (collection: Array<T> | { [id: any]: T }) => Array<U>;
    flatMapDeep<T, U>(
      iteratee: FlatMapIteratee<T, U> | OFlatMapIteratee<T, U>,
      collection: Array<T> | { [id: any]: T }
    ): Array<U>;
    flatMapDepth<T, U>(
      iteratee: FlatMapIteratee<T, U> | OFlatMapIteratee<T, U>
    ): ((
      depth: number
    ) => (collection: Array<T> | { [id: any]: T }) => Array<U>) &
      ((depth: number, collection: Array<T> | { [id: any]: T }) => Array<U>);
    flatMapDepth<T, U>(
      iteratee: FlatMapIteratee<T, U> | OFlatMapIteratee<T, U>,
      depth: number
    ): (collection: Array<T> | { [id: any]: T }) => Array<U>;
    flatMapDepth<T, U>(
      iteratee: FlatMapIteratee<T, U> | OFlatMapIteratee<T, U>,
      depth: number,
      collection: Array<T> | { [id: any]: T }
    ): Array<U>;
    forEach<T>(
      iteratee: Iteratee<T> | OIteratee<T>
    ): (collection: Array<T> | { [id: any]: T }) => Array<T>;
    forEach<T>(
      iteratee: Iteratee<T> | OIteratee<T>,
      collection: Array<T> | { [id: any]: T }
    ): Array<T>;
    forEachRight<T>(
      iteratee: Iteratee<T> | OIteratee<T>
    ): (collection: Array<T> | { [id: any]: T }) => Array<T>;
    forEachRight<T>(
      iteratee: Iteratee<T> | OIteratee<T>,
      collection: Array<T> | { [id: any]: T }
    ): Array<T>;
    groupBy<V, T>(
      iteratee: ValueOnlyIteratee<T>
    ): (
      collection: $ReadOnlyArray<T> | { [id: any]: T }
    ) => { [key: V]: Array<T> };
    groupBy<V, T>(
      iteratee: ValueOnlyIteratee<T>,
      collection: $ReadOnlyArray<T> | { [id: any]: T }
    ): { [key: V]: Array<T> };
    includes<T>(value: T): (collection: Array<T> | { [id: any]: T }) => boolean;
    includes<T>(value: T, collection: Array<T> | { [id: any]: T }): boolean;
    includes(value: string): (str: string) => boolean;
    includes(value: string, str: string): boolean;
    contains(value: string): (str: string) => boolean;
    contains(value: string, str: string): boolean;
    contains<T>(value: T): (collection: Array<T> | { [id: any]: T }) => boolean;
    contains<T>(value: T, collection: Array<T> | { [id: any]: T }): boolean;
    includesFrom(
      value: string
    ): ((fromIndex: number) => (str: string) => boolean) &
      ((fromIndex: number, str: string) => boolean);
    includesFrom(value: string, fromIndex: number): (str: string) => boolean;
    includesFrom(value: string, fromIndex: number, str: string): boolean;
    includesFrom<T>(
      value: T
    ): ((fromIndex: number) => (collection: Array<T>) => boolean) &
      ((fromIndex: number, collection: Array<T>) => boolean);
    includesFrom<T>(
      value: T,
      fromIndex: number
    ): (collection: Array<T>) => boolean;
    includesFrom<T>(value: T, fromIndex: number, collection: Array<T>): boolean;
    invokeMap<T>(
      path: ((value: T) => Array<string> | string) | Array<string> | string
    ): (collection: Array<T> | { [id: any]: T }) => Array<any>;
    invokeMap<T>(
      path: ((value: T) => Array<string> | string) | Array<string> | string,
      collection: Array<T> | { [id: any]: T }
    ): Array<any>;
    invokeArgsMap<T>(
      path: ((value: T) => Array<string> | string) | Array<string> | string
    ): ((
      collection: Array<T> | { [id: any]: T }
    ) => (args: Array<any>) => Array<any>) &
      ((
        collection: Array<T> | { [id: any]: T },
        args: Array<any>
      ) => Array<any>);
    invokeArgsMap<T>(
      path: ((value: T) => Array<string> | string) | Array<string> | string,
      collection: Array<T> | { [id: any]: T }
    ): (args: Array<any>) => Array<any>;
    invokeArgsMap<T>(
      path: ((value: T) => Array<string> | string) | Array<string> | string,
      collection: Array<T> | { [id: any]: T },
      args: Array<any>
    ): Array<any>;
    keyBy<T, V>(
      iteratee: ValueOnlyIteratee<T>
    ): (collection: $ReadOnlyArray<T> | { [id: any]: T }) => { [key: V]: T };
    keyBy<T, V>(
      iteratee: ValueOnlyIteratee<T>,
      collection: $ReadOnlyArray<T> | { [id: any]: T }
    ): { [key: V]: T };
    indexBy<T, V>(
      iteratee: ValueOnlyIteratee<T>
    ): (collection: $ReadOnlyArray<T> | { [id: any]: T }) => { [key: V]: T };
    indexBy<T, V>(
      iteratee: ValueOnlyIteratee<T>,
      collection: $ReadOnlyArray<T> | { [id: any]: T }
    ): { [key: V]: T };
    map<T, U>(
      iteratee: MapIterator<T, U> | OMapIterator<T, U>
    ): (collection: Array<T> | { [id: any]: T }) => Array<U>;
    map<T, U>(
      iteratee: MapIterator<T, U> | OMapIterator<T, U>,
      collection: Array<T> | { [id: any]: T }
    ): Array<U>;
    map(iteratee: (char: string) => any): (str: string) => string;
    map(iteratee: (char: string) => any, str: string): string;
    pluck<T, U>(
      iteratee: MapIterator<T, U> | OMapIterator<T, U>
    ): (collection: Array<T> | { [id: any]: T }) => Array<U>;
    pluck<T, U>(
      iteratee: MapIterator<T, U> | OMapIterator<T, U>,
      collection: Array<T> | { [id: any]: T }
    ): Array<U>;
    pluck(iteratee: (char: string) => any): (str: string) => string;
    pluck(iteratee: (char: string) => any, str: string): string;
    orderBy<T>(
      iteratees: $ReadOnlyArray<Iteratee<T> | OIteratee<*>> | string
    ): ((
      orders: $ReadOnlyArray<"asc" | "desc"> | string
    ) => (collection: $ReadOnlyArray<T> | { [id: any]: T }) => Array<T>) &
      ((
        orders: $ReadOnlyArray<"asc" | "desc"> | string,
        collection: $ReadOnlyArray<T> | { [id: any]: T }
      ) => Array<T>);
    orderBy<T>(
      iteratees: $ReadOnlyArray<Iteratee<T> | OIteratee<*>> | string,
      orders: $ReadOnlyArray<"asc" | "desc"> | string
    ): (collection: $ReadOnlyArray<T> | { [id: any]: T }) => Array<T>;
    orderBy<T>(
      iteratees: $ReadOnlyArray<Iteratee<T> | OIteratee<*>> | string,
      orders: $ReadOnlyArray<"asc" | "desc"> | string,
      collection: $ReadOnlyArray<T> | { [id: any]: T }
    ): Array<T>;
    partition<T>(
      predicate: Predicate<T> | OPredicate<T>
    ): (collection: Array<T> | { [id: any]: T }) => [Array<T>, Array<T>];
    partition<T>(
      predicate: Predicate<T> | OPredicate<T>,
      collection: Array<T> | { [id: any]: T }
    ): [Array<T>, Array<T>];
    reduce<T, U>(
      iteratee: (accumulator: U, value: T) => U
    ): ((accumulator: U) => (collection: Array<T> | { [id: any]: T }) => U) &
      ((accumulator: U, collection: Array<T> | { [id: any]: T }) => U);
    reduce<T, U>(
      iteratee: (accumulator: U, value: T) => U,
      accumulator: U
    ): (collection: Array<T> | { [id: any]: T }) => U;
    reduce<T, U>(
      iteratee: (accumulator: U, value: T) => U,
      accumulator: U,
      collection: Array<T> | { [id: any]: T }
    ): U;
    reduceRight<T, U>(
      iteratee: (value: T, accumulator: U) => U
    ): ((accumulator: U) => (collection: Array<T> | { [id: any]: T }) => U) &
      ((accumulator: U, collection: Array<T> | { [id: any]: T }) => U);
    reduceRight<T, U>(
      iteratee: (value: T, accumulator: U) => U,
      accumulator: U
    ): (collection: Array<T> | { [id: any]: T }) => U;
    reduceRight<T, U>(
      iteratee: (value: T, accumulator: U) => U,
      accumulator: U,
      collection: Array<T> | { [id: any]: T }
    ): U;
    reject<T>(
      predicate: Predicate<T> | OPredicate<T>
    ): (collection: Array<T> | { [id: any]: T }) => Array<T>;
    reject<T>(
      predicate: Predicate<T> | OPredicate<T>,
      collection: Array<T> | { [id: any]: T }
    ): Array<T>;
    sample<T>(collection: Array<T> | { [id: any]: T }): T;
    sampleSize<T>(
      n: number
    ): (collection: Array<T> | { [id: any]: T }) => Array<T>;
    sampleSize<T>(n: number, collection: Array<T> | { [id: any]: T }): Array<T>;
    shuffle<T>(collection: Array<T> | { [id: any]: T }): Array<T>;
    size(collection: Array<any> | Object | string): number;
    some<T>(
      predicate: Predicate<T> | OPredicate<T>
    ): (collection: Array<T> | { [id: any]: T }) => boolean;
    some<T>(
      predicate: Predicate<T> | OPredicate<T>,
      collection: Array<T> | { [id: any]: T }
    ): boolean;
    any<T>(
      predicate: Predicate<T> | OPredicate<T>
    ): (collection: Array<T> | { [id: any]: T }) => boolean;
    any<T>(
      predicate: Predicate<T> | OPredicate<T>,
      collection: Array<T> | { [id: any]: T }
    ): boolean;
    sortBy<T>(
      iteratees: | $ReadOnlyArray<Iteratee<T> | OIteratee<T>>
      | Iteratee<T>
      | OIteratee<T>
    ): (collection: $ReadOnlyArray<T> | { [id: any]: T }) => Array<T>;
    sortBy<T>(
      iteratees: | $ReadOnlyArray<Iteratee<T> | OIteratee<T>>
      | Iteratee<T>
      | OIteratee<T>,
      collection: $ReadOnlyArray<T> | { [id: any]: T },
    ): Array<T>;

    // Date
    now(): number;

    // Function
    after(fn: Function): (n: number) => Function;
    after(fn: Function, n: number): Function;
    ary(func: Function): Function;
    nAry(n: number): (func: Function) => Function;
    nAry(n: number, func: Function): Function;
    before(fn: Function): (n: number) => Function;
    before(fn: Function, n: number): Function;
    bind(func: Function): (thisArg: any) => Function;
    bind(func: Function, thisArg: any): Function;
    bindKey(obj: Object): (key: string) => Function;
    bindKey(obj: Object, key: string): Function;
    curry: Curry;
    curryN(arity: number): (func: Function) => Function;
    curryN(arity: number, func: Function): Function;
    curryRight(func: Function): Function;
    curryRightN(arity: number): (func: Function) => Function;
    curryRightN(arity: number, func: Function): Function;
    debounce(wait: number): <F: Function>(func: F) => F;
    debounce<F: Function>(wait: number, func: F): F;
    defer(func: Function): TimeoutID;
    delay(wait: number): (func: Function) => TimeoutID;
    delay(wait: number, func: Function): TimeoutID;
    flip(func: Function): Function;
    memoize<F: Function>(func: F): F;
    negate(predicate: Function): Function;
    complement(predicate: Function): Function;
    once(func: Function): Function;
    overArgs(func: Function): (transforms: Array<Function>) => Function;
    overArgs(func: Function, transforms: Array<Function>): Function;
    useWith(func: Function): (transforms: Array<Function>) => Function;
    useWith(func: Function, transforms: Array<Function>): Function;
    partial(func: Function): (partials: any[]) => Function;
    partial(func: Function, partials: any[]): Function;
    partialRight(func: Function): (partials: Array<any>) => Function;
    partialRight(func: Function, partials: Array<any>): Function;
    rearg(indexes: Array<number>): (func: Function) => Function;
    rearg(indexes: Array<number>, func: Function): Function;
    rest(func: Function): Function;
    unapply(func: Function): Function;
    restFrom(start: number): (func: Function) => Function;
    restFrom(start: number, func: Function): Function;
    spread(func: Function): Function;
    apply(func: Function): Function;
    spreadFrom(start: number): (func: Function) => Function;
    spreadFrom(start: number, func: Function): Function;
    throttle(wait: number): (func: Function) => Function;
    throttle(wait: number, func: Function): Function;
    unary(func: Function): Function;
    wrap(wrapper: Function): (value: any) => Function;
    wrap(wrapper: Function, value: any): Function;

    // Lang
    castArray(value: *): any[];
    clone<T>(value: T): T;
    cloneDeep<T>(value: T): T;
    cloneDeepWith<T, U>(
      customizer: (value: T, key: number | string, object: T, stack: any) => U
    ): (value: T) => U;
    cloneDeepWith<T, U>(
      customizer: (value: T, key: number | string, object: T, stack: any) => U,
      value: T
    ): U;
    cloneWith<T, U>(
      customizer: (value: T, key: number | string, object: T, stack: any) => U
    ): (value: T) => U;
    cloneWith<T, U>(
      customizer: (value: T, key: number | string, object: T, stack: any) => U,
      value: T
    ): U;
    conformsTo<T: { [key: string]: mixed }>(
      predicates: T & { [key: string]: (x: any) => boolean }
    ): (source: T) => boolean;
    conformsTo<T: { [key: string]: mixed }>(
      predicates: T & { [key: string]: (x: any) => boolean },
      source: T
    ): boolean;
    where<T: { [key: string]: mixed }>(
      predicates: T & { [key: string]: (x: any) => boolean }
    ): (source: T) => boolean;
    where<T: { [key: string]: mixed }>(
      predicates: T & { [key: string]: (x: any) => boolean },
      source: T
    ): boolean;
    conforms<T: { [key: string]: mixed }>(
      predicates: T & { [key: string]: (x: any) => boolean }
    ): (source: T) => boolean;
    conforms<T: { [key: string]: mixed }>(
      predicates: T & { [key: string]: (x: any) => boolean },
      source: T
    ): boolean;
    eq(value: any): (other: any) => boolean;
    eq(value: any, other: any): boolean;
    identical(value: any): (other: any) => boolean;
    identical(value: any, other: any): boolean;
    gt(value: any): (other: any) => boolean;
    gt(value: any, other: any): boolean;
    gte(value: any): (other: any) => boolean;
    gte(value: any, other: any): boolean;
    isArguments(value: any): boolean;
    isArray(value: any): boolean;
    isArrayBuffer(value: any): boolean;
    isArrayLike(value: any): boolean;
    isArrayLikeObject(value: any): boolean;
    isBoolean(value: any): boolean;
    isBuffer(value: any): boolean;
    isDate(value: any): boolean;
    isElement(value: any): boolean;
    isEmpty(value: any): boolean;
    isEqual(value: any): (other: any) => boolean;
    isEqual(value: any, other: any): boolean;
    equals(value: any): (other: any) => boolean;
    equals(value: any, other: any): boolean;
    isEqualWith<T, U>(
      customizer: (
        objValue: any,
        otherValue: any,
        key: number | string,
        object: T,
        other: U,
        stack: any
      ) => boolean | void
    ): ((value: T) => (other: U) => boolean) &
      ((value: T, other: U) => boolean);
    isEqualWith<T, U>(
      customizer: (
        objValue: any,
        otherValue: any,
        key: number | string,
        object: T,
        other: U,
        stack: any
      ) => boolean | void,
      value: T
    ): (other: U) => boolean;
    isEqualWith<T, U>(
      customizer: (
        objValue: any,
        otherValue: any,
        key: number | string,
        object: T,
        other: U,
        stack: any
      ) => boolean | void,
      value: T,
      other: U
    ): boolean;
    isError(value: any): boolean;
    isFinite(value: any): boolean;
    isFunction(value: Function): true;
    isFunction(value: number | string | void | null | Object): false;
    isInteger(value: any): boolean;
    isLength(value: any): boolean;
    isMap(value: any): boolean;
    isMatch(source: Object): (object: Object) => boolean;
    isMatch(source: Object, object: Object): boolean;
    whereEq(source: Object): (object: Object) => boolean;
    whereEq(source: Object, object: Object): boolean;
    isMatchWith<T: Object, U: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: number | string,
        object: T,
        source: U
      ) => boolean | void
    ): ((source: U) => (object: T) => boolean) &
      ((source: U, object: T) => boolean);
    isMatchWith<T: Object, U: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: number | string,
        object: T,
        source: U
      ) => boolean | void,
      source: U
    ): (object: T) => boolean;
    isMatchWith<T: Object, U: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: number | string,
        object: T,
        source: U
      ) => boolean | void,
      source: U,
      object: T
    ): boolean;
    isNaN(value: any): boolean;
    isNative(value: any): boolean;
    isNil(value: any): boolean;
    isNull(value: any): boolean;
    isNumber(value: any): boolean;
    isObject(value: any): boolean;
    isObjectLike(value: any): boolean;
    isPlainObject(value: any): boolean;
    isRegExp(value: any): boolean;
    isSafeInteger(value: any): boolean;
    isSet(value: any): boolean;
    isString(value: string): true;
    isString(
      value: number | boolean | Function | void | null | Object | Array<any>
    ): false;
    isSymbol(value: any): boolean;
    isTypedArray(value: any): boolean;
    isUndefined(value: any): boolean;
    isWeakMap(value: any): boolean;
    isWeakSet(value: any): boolean;
    lt(value: any): (other: any) => boolean;
    lt(value: any, other: any): boolean;
    lte(value: any): (other: any) => boolean;
    lte(value: any, other: any): boolean;
    toArray(value: any): Array<any>;
    toFinite(value: any): number;
    toInteger(value: any): number;
    toLength(value: any): number;
    toNumber(value: any): number;
    toPlainObject(value: any): Object;
    toSafeInteger(value: any): number;
    toString(value: any): string;

    // Math
    add(augend: number): (addend: number) => number;
    add(augend: number, addend: number): number;
    ceil(number: number): number;
    divide(dividend: number): (divisor: number) => number;
    divide(dividend: number, divisor: number): number;
    floor(number: number): number;
    max<T>(array: Array<T>): T;
    maxBy<T>(iteratee: Iteratee<T>): (array: Array<T>) => T;
    maxBy<T>(iteratee: Iteratee<T>, array: Array<T>): T;
    mean(array: Array<*>): number;
    meanBy<T>(iteratee: Iteratee<T>): (array: Array<T>) => number;
    meanBy<T>(iteratee: Iteratee<T>, array: Array<T>): number;
    min<T>(array: Array<T>): T;
    minBy<T>(iteratee: Iteratee<T>): (array: Array<T>) => T;
    minBy<T>(iteratee: Iteratee<T>, array: Array<T>): T;
    multiply(multiplier: number): (multiplicand: number) => number;
    multiply(multiplier: number, multiplicand: number): number;
    round(number: number): number;
    subtract(minuend: number): (subtrahend: number) => number;
    subtract(minuend: number, subtrahend: number): number;
    sum(array: Array<*>): number;
    sumBy<T>(iteratee: Iteratee<T>): (array: Array<T>) => number;
    sumBy<T>(iteratee: Iteratee<T>, array: Array<T>): number;

    // number
    clamp(
      lower: number
    ): ((upper: number) => (number: number) => number) &
      ((upper: number, number: number) => number);
    clamp(lower: number, upper: number): (number: number) => number;
    clamp(lower: number, upper: number, number: number): number;
    inRange(
      start: number
    ): ((end: number) => (number: number) => boolean) &
      ((end: number, number: number) => boolean);
    inRange(start: number, end: number): (number: number) => boolean;
    inRange(start: number, end: number, number: number): boolean;
    random(lower: number): (upper: number) => number;
    random(lower: number, upper: number): number;

    // Object
    assign(object: Object): (source: Object) => Object;
    assign(object: Object, source: Object): Object;
    assignAll(objects: Array<Object>): Object;
    assignInAll(objects: Array<Object>): Object;
    extendAll(objects: Array<Object>): Object;
    assignIn<A, B>(a: A): (b: B) => A & B;
    assignIn<A, B>(a: A, b: B): A & B;
    assignInWith<T: Object, A: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void
    ): ((object: T) => (s1: A) => Object) & ((object: T, s1: A) => Object);
    assignInWith<T: Object, A: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void,
      object: T
    ): (s1: A) => Object;
    assignInWith<T: Object, A: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void,
      object: T,
      s1: A
    ): Object;
    assignWith<T: Object, A: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void
    ): ((object: T) => (s1: A) => Object) & ((object: T, s1: A) => Object);
    assignWith<T: Object, A: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void,
      object: T
    ): (s1: A) => Object;
    assignWith<T: Object, A: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void,
      object: T,
      s1: A
    ): Object;
    assignInAllWith(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: Object,
        source: Object
      ) => any | void
    ): (objects: Array<Object>) => Object;
    assignInAllWith(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: Object,
        source: Object
      ) => any | void,
      objects: Array<Object>
    ): Object;
    extendAllWith(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: Object,
        source: Object
      ) => any | void
    ): (objects: Array<Object>) => Object;
    extendAllWith(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: Object,
        source: Object
      ) => any | void,
      objects: Array<Object>
    ): Object;
    assignAllWith(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: Object,
        source: Object
      ) => any | void
    ): (objects: Array<Object>) => Object;
    assignAllWith(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: Object,
        source: Object
      ) => any | void,
      objects: Array<Object>
    ): Object;
    at(paths: Array<string>): (object: Object) => Array<any>;
    at(paths: Array<string>, object: Object): Array<any>;
    props(paths: Array<string>): (object: Object) => Array<any>;
    props(paths: Array<string>, object: Object): Array<any>;
    paths(paths: Array<string>): (object: Object) => Array<any>;
    paths(paths: Array<string>, object: Object): Array<any>;
    create<T>(prototype: T): $Supertype<T>;
    defaults(source: Object): (object: Object) => Object;
    defaults(source: Object, object: Object): Object;
    defaultsAll(objects: Array<Object>): Object;
    defaultsDeep(source: Object): (object: Object) => Object;
    defaultsDeep(source: Object, object: Object): Object;
    defaultsDeepAll(objects: Array<Object>): Object;
    // alias for _.toPairs
    entries(object: Object): Array<[string, any]>;
    // alias for _.toPairsIn
    entriesIn(object: Object): Array<[string, any]>;
    // alias for _.assignIn
    extend<A, B>(a: A): (b: B) => A & B;
    extend<A, B>(a: A, b: B): A & B;
    // alias for _.assignInWith
    extendWith<T: Object, A: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void
    ): ((object: T) => (s1: A) => Object) & ((object: T, s1: A) => Object);
    extendWith<T: Object, A: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void,
      object: T
    ): (s1: A) => Object;
    extendWith<T: Object, A: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A
      ) => any | void,
      object: T,
      s1: A
    ): Object;
    findKey<A, T: { [id: any]: A }>(
      predicate: OPredicate<A>
    ): (object: T) => string | void;
    findKey<A, T: { [id: any]: A }>(
      predicate: OPredicate<A>,
      object: T
    ): string | void;
    findLastKey<A, T: { [id: any]: A }>(
      predicate: OPredicate<A>
    ): (object: T) => string | void;
    findLastKey<A, T: { [id: any]: A }>(
      predicate: OPredicate<A>,
      object: T
    ): string | void;
    forIn(iteratee: OIteratee<*>): (object: Object) => Object;
    forIn(iteratee: OIteratee<*>, object: Object): Object;
    forInRight(iteratee: OIteratee<*>): (object: Object) => Object;
    forInRight(iteratee: OIteratee<*>, object: Object): Object;
    forOwn(iteratee: OIteratee<*>): (object: Object) => Object;
    forOwn(iteratee: OIteratee<*>, object: Object): Object;
    forOwnRight(iteratee: OIteratee<*>): (object: Object) => Object;
    forOwnRight(iteratee: OIteratee<*>, object: Object): Object;
    functions(object: Object): Array<string>;
    functionsIn(object: Object): Array<string>;
    get(path: Array<string> | string): (object: Object | Array<any>) => any;
    get(path: Array<string> | string, object: Object | Array<any>): any;
    prop(path: Array<string> | string): (object: Object | Array<any>) => any;
    prop(path: Array<string> | string, object: Object | Array<any>): any;
    path(path: Array<string> | string): (object: Object | Array<any>) => any;
    path(path: Array<string> | string, object: Object | Array<any>): any;
    getOr(
      defaultValue: any
    ): ((
      path: Array<string> | string
    ) => (object: Object | Array<any>) => any) &
      ((path: Array<string> | string, object: Object | Array<any>) => any);
    getOr(
      defaultValue: any,
      path: Array<string> | string
    ): (object: Object | Array<any>) => any;
    getOr(
      defaultValue: any,
      path: Array<string> | string,
      object: Object | Array<any>
    ): any;
    propOr(
      defaultValue: any
    ): ((
      path: Array<string> | string
    ) => (object: Object | Array<any>) => any) &
      ((path: Array<string> | string, object: Object | Array<any>) => any);
    propOr(
      defaultValue: any,
      path: Array<string> | string
    ): (object: Object | Array<any>) => any;
    propOr(
      defaultValue: any,
      path: Array<string> | string,
      object: Object | Array<any>
    ): any;
    pathOr(
      defaultValue: any
    ): ((
      path: Array<string> | string
    ) => (object: Object | Array<any>) => any) &
      ((path: Array<string> | string, object: Object | Array<any>) => any);
    pathOr(
      defaultValue: any,
      path: Array<string> | string
    ): (object: Object | Array<any>) => any;
    pathOr(
      defaultValue: any,
      path: Array<string> | string,
      object: Object | Array<any>
    ): any;
    has(path: Array<string> | string): (object: Object) => boolean;
    has(path: Array<string> | string, object: Object): boolean;
    hasIn(path: Array<string> | string): (object: Object) => boolean;
    hasIn(path: Array<string> | string, object: Object): boolean;
    invert(object: Object): Object;
    invertObj(object: Object): Object;
    invertBy(iteratee: Function): (object: Object) => Object;
    invertBy(iteratee: Function, object: Object): Object;
    invoke(path: Array<string> | string): (object: Object) => any;
    invoke(path: Array<string> | string, object: Object): any;
    invokeArgs(
      path: Array<string> | string
    ): ((object: Object) => (args: Array<any>) => any) &
      ((object: Object, args: Array<any>) => any);
    invokeArgs(
      path: Array<string> | string,
      object: Object
    ): (args: Array<any>) => any;
    invokeArgs(
      path: Array<string> | string,
      object: Object,
      args: Array<any>
    ): any;
    keys<K>(object: { [key: K]: any }): Array<K>;
    keys(object: Object): Array<string>;
    keysIn(object: Object): Array<string>;
    mapKeys(iteratee: OIteratee<*>): (object: Object) => Object;
    mapKeys(iteratee: OIteratee<*>, object: Object): Object;
    mapValues(iteratee: OIteratee<*>): (object: Object) => Object;
    mapValues(iteratee: OIteratee<*>, object: Object): Object;
    merge(object: Object): (source: Object) => Object;
    merge(object: Object, source: Object): Object;
    mergeAll(objects: Array<Object>): Object;
    mergeWith<T: Object, A: Object, B: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B
      ) => any | void
    ): ((object: T) => (s1: A) => Object) & ((object: T, s1: A) => Object);
    mergeWith<T: Object, A: Object, B: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B
      ) => any | void,
      object: T
    ): (s1: A) => Object;
    mergeWith<T: Object, A: Object, B: Object>(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: T,
        source: A | B
      ) => any | void,
      object: T,
      s1: A
    ): Object;
    mergeAllWith(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: Object,
        source: Object
      ) => any | void
    ): (objects: Array<Object>) => Object;
    mergeAllWith(
      customizer: (
        objValue: any,
        srcValue: any,
        key: string,
        object: Object,
        source: Object
      ) => any | void,
      objects: Array<Object>
    ): Object;
    omit(props: Array<string>): (object: Object) => Object;
    omit(props: Array<string>, object: Object): Object;
    omitAll(props: Array<string>): (object: Object) => Object;
    omitAll(props: Array<string>, object: Object): Object;
    omitBy<A, T: { [id: any]: A }>(
      predicate: OPredicate<A>
    ): (object: T) => Object;
    omitBy<A, T: { [id: any]: A }>(predicate: OPredicate<A>, object: T): Object;
    pick(props: Array<string>): (object: Object) => Object;
    pick(props: Array<string>, object: Object): Object;
    pickAll(props: Array<string>): (object: Object) => Object;
    pickAll(props: Array<string>, object: Object): Object;
    pickBy<A, T: { [id: any]: A }>(
      predicate: OPredicate<A>
    ): (object: T) => Object;
    pickBy<A, T: { [id: any]: A }>(predicate: OPredicate<A>, object: T): Object;
    result(path: Array<string> | string): (object: Object) => any;
    result(path: Array<string> | string, object: Object): any;
    set(
      path: Array<string> | string
    ): ((value: any) => (object: Object) => Object) &
      ((value: any, object: Object) => Object);
    set(path: Array<string> | string, value: any): (object: Object) => Object;
    set(path: Array<string> | string, value: any, object: Object): Object;
    assoc(
      path: Array<string> | string
    ): ((value: any) => (object: Object) => Object) &
      ((value: any, object: Object) => Object);
    assoc(path: Array<string> | string, value: any): (object: Object) => Object;
    assoc(path: Array<string> | string, value: any, object: Object): Object;
    assocPath(
      path: Array<string> | string
    ): ((value: any) => (object: Object) => Object) &
      ((value: any, object: Object) => Object);
    assocPath(
      path: Array<string> | string,
      value: any
    ): (object: Object) => Object;
    assocPath(path: Array<string> | string, value: any, object: Object): Object;
    setWith<T>(
      customizer: (nsValue: any, key: string, nsObject: T) => any
    ): ((
      path: Array<string> | string
    ) => ((value: any) => (object: T) => Object) &
      ((value: any, object: T) => Object)) &
      ((path: Array<string> | string, value: any) => (object: T) => Object) &
      ((path: Array<string> | string, value: any, object: T) => Object);
    setWith<T>(
      customizer: (nsValue: any, key: string, nsObject: T) => any,
      path: Array<string> | string
    ): ((value: any) => (object: T) => Object) &
      ((value: any, object: T) => Object);
    setWith<T>(
      customizer: (nsValue: any, key: string, nsObject: T) => any,
      path: Array<string> | string,
      value: any
    ): (object: T) => Object;
    setWith<T>(
      customizer: (nsValue: any, key: string, nsObject: T) => any,
      path: Array<string> | string,
      value: any,
      object: T
    ): Object;
    toPairs(object: Object | Array<*>): Array<[string, any]>;
    toPairsIn(object: Object): Array<[string, any]>;
    transform(
      iteratee: OIteratee<*>
    ): ((
      accumulator: any
    ) => (collection: Object | $ReadOnlyArray<any>) => any) &
      ((accumulator: any, collection: Object | $ReadOnlyArray<any>) => any);
    transform(
      iteratee: OIteratee<*>,
      accumulator: any
    ): (collection: Object | $ReadOnlyArray<any>) => any;
    transform(
      iteratee: OIteratee<*>,
      accumulator: any,
      collection: Object | $ReadOnlyArray<any>
    ): any;
    unset(path: Array<string> | string): (object: Object) => Object;
    unset(path: Array<string> | string, object: Object): Object;
    dissoc(path: Array<string> | string): (object: Object) => Object;
    dissoc(path: Array<string> | string, object: Object): Object;
    dissocPath(path: Array<string> | string): (object: Object) => Object;
    dissocPath(path: Array<string> | string, object: Object): Object;
    update(
      path: string[] | string
    ): ((updater: Function) => (object: Object) => Object) &
      ((updater: Function, object: Object) => Object);
    update(
      path: string[] | string,
      updater: Function
    ): (object: Object) => Object;
    update(path: string[] | string, updater: Function, object: Object): Object;
    updateWith(
      customizer: Function
    ): ((
      path: string[] | string
    ) => ((updater: Function) => (object: Object) => Object) &
      ((updater: Function, object: Object) => Object)) &
      ((
        path: string[] | string,
        updater: Function
      ) => (object: Object) => Object) &
      ((path: string[] | string, updater: Function, object: Object) => Object);
    updateWith(
      customizer: Function,
      path: string[] | string
    ): ((updater: Function) => (object: Object) => Object) &
      ((updater: Function, object: Object) => Object);
    updateWith(
      customizer: Function,
      path: string[] | string,
      updater: Function
    ): (object: Object) => Object;
    updateWith(
      customizer: Function,
      path: string[] | string,
      updater: Function,
      object: Object
    ): Object;
    values(object: Object): Array<any>;
    valuesIn(object: Object): Array<any>;

    tap<T>(interceptor: (value: T) => any): (value: T) => T;
    tap<T>(interceptor: (value: T) => any, value: T): T;
    thru<T1, T2>(interceptor: (value: T1) => T2): (value: T1) => T2;
    thru<T1, T2>(interceptor: (value: T1) => T2, value: T1): T2;

    // String
    camelCase(string: string): string;
    capitalize(string: string): string;
    deburr(string: string): string;
    endsWith(target: string): (string: string) => boolean;
    endsWith(target: string, string: string): boolean;
    escape(string: string): string;
    escapeRegExp(string: string): string;
    kebabCase(string: string): string;
    lowerCase(string: string): string;
    lowerFirst(str
Download .txt
gitextract_xt59y45s/

├── .editorconfig
├── .eslintrc
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── __tests__/
│   ├── data/
│   │   └── users.ts
│   ├── database_spec.ts
│   ├── request_spec.ts
│   ├── response_spec.ts
│   ├── router_spec.ts
│   └── server_spec.ts
├── create-readme.js
├── examples/
│   ├── dummy/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── bower.json
│   │   ├── index.html
│   │   └── package.json
│   ├── github-explorer/
│   │   ├── .firebaserc
│   │   ├── README.md
│   │   ├── database.rules.json
│   │   ├── firebase.json
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── styles.css
│   │   └── styles.scss
│   ├── react/
│   │   ├── .nvmrc
│   │   ├── example/
│   │   │   ├── app.tsx
│   │   │   ├── index.html
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── package.json
│   │   └── tsconfig.json
│   └── todo-app/
│       ├── .firebaserc
│       ├── README.md
│       ├── database.rules.json
│       ├── firebase.json
│       ├── index.html
│       └── package.json
├── flow-typed/
│   └── npm/
│       ├── jest_v22.x.x.js
│       └── lodash_v4.x.x.js
├── jest.config.js
├── jestFrameworkSetup.js
├── md/
│   ├── end.md
│   └── start.md
├── package.json
├── perf/
│   └── index.js
├── src/
│   ├── Database/
│   │   └── index.ts
│   ├── Request/
│   │   └── index.ts
│   ├── Response/
│   │   └── index.ts
│   ├── Router/
│   │   └── index.ts
│   ├── Server/
│   │   └── index.ts
│   ├── config/
│   │   └── environment.ts
│   ├── index.ts
│   ├── interceptors/
│   │   ├── fetchInterceptor.ts
│   │   ├── index.ts
│   │   ├── interceptorHelper.ts
│   │   └── xhrInterceptor.ts
│   ├── serializers/
│   │   ├── index.ts
│   │   └── json-api.ts
│   └── utils.ts
├── tsconfig.dist.json
├── tsconfig.json
├── typings/
│   ├── parse-url/
│   │   └── index.d.ts
│   ├── path-match/
│   │   └── index.d.ts
│   └── query-string/
│       └── index.d.ts
├── webpack.config.js
└── webpack.perf.config.js
Download .txt
SYMBOL INDEX (107 symbols across 14 files)

FILE: __tests__/data/users.ts
  type UserId (line 3) | type UserId = string;
  type User (line 5) | type User = {

FILE: __tests__/database_spec.ts
  type Book (line 7) | type Book = {
  type Schema (line 12) | type Schema = {
  type SetupOptions (line 17) | type SetupOptions = {

FILE: examples/react/example/app.tsx
  type AppState (line 33) | interface AppState {
  class App (line 37) | class App extends Component <{}, AppState> {
    method componentDidMount (line 42) | componentDidMount() {
    method getFilesFetch (line 48) | async getFilesFetch() {
    method getFilesXHR (line 54) | async getFilesXHR() {
    method getFilesPromiseXHR (line 64) | getFilesPromiseXHR() {
    method postFilePromiseXHR (line 74) | postFilePromiseXHR() {
    method render (line 84) | render() {

FILE: jestFrameworkSetup.js
  class Request (line 1) | class Request {
  class Response (line 5) | class Response {
    method constructor (line 7) | constructor(body) {
    method json (line 12) | json() {

FILE: src/Database/index.ts
  type DataType (line 6) | type DataType = any;
  type DatabaseSchema (line 8) | interface DatabaseSchema {
  type CollectionStore (line 12) | type CollectionStore<M extends DatabaseSchema> = {
  type Collection (line 16) | interface Collection<D extends DataType> {
  type DataFactory (line 22) | type DataFactory<D extends DataType> = () => D;
  type RecordId (line 24) | type RecordId = number;
  type DataRecord (line 26) | interface DataRecord<D extends DataType> {
  class Database (line 31) | class Database<M extends DatabaseSchema> {
    method constructor (line 34) | constructor() {
    method all (line 38) | all<K extends keyof M>(collectionName: K): DataRecord<M[K]>[] {
    method belongsTo (line 43) | belongsTo<K extends keyof M>(
    method create (line 56) | create<K extends keyof M>(
    method delete (line 73) | delete<K extends keyof M>(
    method exists (line 90) | exists<K extends keyof M>(collectionName: K): boolean {
    method find (line 94) | find<K extends keyof M>(
    method findOne (line 102) | findOne<K extends keyof M>(
    method first (line 109) | first<K extends keyof M>(collectionName: K): DataRecord<M[K]> | undefi...
    method last (line 114) | last<K extends keyof M>(collectionName: K): DataRecord<M[K]> | undefin...
    method push (line 119) | push<K extends keyof M>(
    method register (line 136) | register<K extends keyof M>(
    method reset (line 147) | reset() {
    method update (line 151) | update<K extends keyof M>(
    method getCollection (line 175) | getCollection<K extends keyof M>(
  class CollectionNotFoundError (line 187) | class CollectionNotFoundError extends Error {
    method constructor (line 188) | constructor(collectionName: string) {
  class RecordNotFoundError (line 193) | class RecordNotFoundError extends Error {
    method constructor (line 194) | constructor(collectionName: string, id: RecordId) {

FILE: src/Request/index.ts
  type KakapoRequestOptions (line 1) | interface KakapoRequestOptions {
  class KakapoRequest (line 8) | class KakapoRequest {
    method constructor (line 14) | constructor(options: KakapoRequestOptions) {

FILE: src/Response/index.ts
  class KakapoResponse (line 1) | class KakapoResponse {
    method constructor (line 6) | constructor(
    method error (line 16) | get error() {
    method ok (line 20) | get ok() {
    method wrap (line 24) | static wrap(response: any): KakapoResponse {

FILE: src/Router/index.ts
  type RouterConfig (line 25) | interface RouterConfig {
  class Router (line 29) | class Router<M extends DatabaseSchema> {
    method constructor (line 32) | constructor(
    method get (line 43) | get(path: string, handler: RouterHandler<M>) {
    method post (line 47) | post(path: string, handler: RouterHandler<M>) {
    method put (line 51) | put(path: string, handler: RouterHandler<M>) {
    method delete (line 55) | delete(path: string, handler: RouterHandler<M>) {
    method head (line 59) | head(path: string, handler: RouterHandler<M>) {
    method register (line 63) | register(method: string, path: string, handler: RouterHandler<M>) {
    method intercept (line 67) | intercept() {
    method reset (line 75) | reset() {

FILE: src/Server/index.ts
  class Server (line 7) | class Server<M extends DatabaseSchema> {
    method constructor (line 11) | constructor(readonly config: any = {}) {}
    method use (line 13) | use(entity: Database<M> | Router<M>) {
    method remove (line 28) | remove(entity: Database<M> | Router<M>) {
    method linkEntities (line 41) | linkEntities() {

FILE: src/interceptors/fetchInterceptor.ts
  class FakeFetchFactory (line 27) | class FakeFetchFactory<M extends DatabaseSchema> {
    method constructor (line 30) | constructor() {
    method use (line 34) | use(config: InterceptorConfig<M>) {
    method getFetch (line 38) | getFetch(): typeof fetch {
  function isFakeFetch (line 105) | function isFakeFetch<M extends DatabaseSchema>(fetch: any): fetch is Fak...

FILE: src/interceptors/index.ts
  type Interceptors (line 4) | interface Interceptors {

FILE: src/interceptors/interceptorHelper.ts
  type RouterHandler (line 10) | type RouterHandler<M extends DatabaseSchema> = (
  type InterceptorConfig (line 15) | interface InterceptorConfig<M extends DatabaseSchema> {
  type UrlDetails (line 22) | interface UrlDetails {
  type Interceptor (line 49) | interface Interceptor<M extends DatabaseSchema> {
  method getDB (line 58) | getDB() {
  method getDelay (line 61) | getDelay() {
  method getHandler (line 64) | getHandler(url, method) {
  method getParams (line 70) | getParams(url, method) {
  method getQuery (line 77) | getQuery(url) {

FILE: src/interceptors/xhrInterceptor.ts
  type ProgressEventType (line 11) | type ProgressEventType = keyof XMLHttpRequestEventTargetEventMap;
  type ProgressEventHandler (line 12) | type ProgressEventHandler<K extends ProgressEventType> = (
  type ProgressEventListener (line 15) | type ProgressEventListener<K extends ProgressEventType> =
  class FakeXMLHttpRequest (line 24) | class FakeXMLHttpRequest<M extends DatabaseSchema> {
    method constructor (line 28) | constructor() {
    method use (line 32) | use(config: InterceptorConfig<M>) {
    method shouldIntercept (line 36) | shouldIntercept(method: string, url: string): boolean {
    method open (line 55) | open(
    method status (line 70) | get status(): number {
    method readyState (line 75) | get readyState(): number {
    method _setReadyState (line 82) | _setReadyState(readyState: number): void {
    method response (line 90) | get response(): any {
    method responseText (line 94) | get responseText(): string {
    method setRequestHeader (line 109) | setRequestHeader(header: string, value: string): void {
    method getResponseHeader (line 115) | getResponseHeader(header: string): string {
    method send (line 119) | send(data?: any): void {
    method _handleResponse (line 159) | _handleResponse({ code, headers, body }: KakapoResponse): void {
    method addEventListener (line 205) | addEventListener<K extends ProgressEventType>(
    method removeEventListener (line 212) | removeEventListener<K extends ProgressEventType>(
    method nativeSend (line 234) | nativeSend(data?: any): void {
  type AddEventListenerOptions (line 266) | interface AddEventListenerOptions {
  class FakeXMLHttpRequestEventTarget (line 272) | class FakeXMLHttpRequestEventTarget {
    method addEventListener (line 273) | addEventListener(

FILE: src/utils.ts
  function mapRequestInfoToUrlString (line 1) | function mapRequestInfoToUrlString(requestInfo: RequestInfo): string {
Condensed preview — 69 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (332K chars).
[
  {
    "path": ".editorconfig",
    "chars": 244,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitesp"
  },
  {
    "path": ".eslintrc",
    "chars": 264,
    "preview": "{\n  \"parser\":  \"@typescript-eslint/parser\",\n  \"parserOptions\": {\n    \"ecmaVersion\": 2018,\n    \"sourceType\":  \"module\"\n  "
  },
  {
    "path": ".gitignore",
    "chars": 431,
    "preview": "*~\n.directory\n.Trash-*\nlogs\n*.log\npids\n*.pid\n*.seed\nlib-cov\n.lock-wscript\nbuild/Release\nnode_modules\ndist/\nnpm-debug.log"
  },
  {
    "path": ".travis.yml",
    "chars": 110,
    "preview": "language: node_js\nnode_js:\n  - '8'\ncache: yarn\nscript:\n  - yarn\n  - yarn test:ci\nnotifications:\n  email: false"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 15459,
    "preview": "\nn.n.n / 2016-06-16\n==================\n\n  * Merge pull request #121 from devlucky/feature/disconnect\n  * v0.2.0\n\nv0.2.0 "
  },
  {
    "path": "LICENSE",
    "chars": 1122,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016 @oskarcieslik - @zzarcon (https://github.com/devlucky)\n\nPermission is hereby g"
  },
  {
    "path": "README.md",
    "chars": 18850,
    "preview": "# Kakapo.js <img src=\"https://sdl-stickershop.line.naver.jp/products/0/0/1/1087538/LINEStorePC/main.png?__=20150924\" wid"
  },
  {
    "path": "__tests__/data/users.ts",
    "chars": 437,
    "preview": "import * as Faker from 'faker';\n\nexport type UserId = string;\n\nexport type User = {\n  id: UserId,\n  firstName: string,\n "
  },
  {
    "path": "__tests__/database_spec.ts",
    "chars": 6229,
    "preview": "import * as Faker from 'faker';\n\nimport { Database, DataFactory } from '../src/Database';\nimport { User, UserId, userFac"
  },
  {
    "path": "__tests__/request_spec.ts",
    "chars": 748,
    "preview": "import { Server, Router } from '../src';\n\ntest.skip('Request # headers', () => {\n  expect.assertions(2);\n\n  const server"
  },
  {
    "path": "__tests__/response_spec.ts",
    "chars": 2342,
    "preview": "import { Server, KakapoResponse, Router } from '../src';\n\n// TODO: stub native Response\ndescribe.skip('Response', () => "
  },
  {
    "path": "__tests__/router_spec.ts",
    "chars": 8245,
    "preview": "import { Server, Router, KakapoResponse } from '../src';\nimport { isFakeFetch } from '../src/interceptors/fetchIntercept"
  },
  {
    "path": "__tests__/server_spec.ts",
    "chars": 2560,
    "preview": "// @TODO Test Server's config\nimport { Database, Router, Server } from '../src';\n\nconst xhrRequest = (url: string) => {\n"
  },
  {
    "path": "create-readme.js",
    "chars": 631,
    "preview": "'use strict';\nconst fs = require('fs');\nconst request = require('superagent');\nconst readmeUrl = 'https://cdn.rawgit.com"
  },
  {
    "path": "examples/dummy/.gitignore",
    "chars": 21,
    "preview": "bower_components\ndist"
  },
  {
    "path": "examples/dummy/README.md",
    "chars": 707,
    "preview": "#Kakapo Dummy App example\n> Just shows how to integrate Kakapo.js in you app in multiple flavours\n\nThis Example shows di"
  },
  {
    "path": "examples/dummy/bower.json",
    "chars": 345,
    "preview": "{\n  \"name\": \"kakapo-dummy-app\",\n  \"description\": \"Dummy app that shows how to integrate Kakapo.js\",\n  \"main\": \"index.js\""
  },
  {
    "path": "examples/dummy/index.html",
    "chars": 630,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Kakapo dummy app</title>\n  <!---->\n  <!-- Unco"
  },
  {
    "path": "examples/dummy/package.json",
    "chars": 663,
    "preview": "{\n  \"name\": \"kakapo-dummy-app\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Dummy app that shows how to integrate Kakapo.js\""
  },
  {
    "path": "examples/github-explorer/.firebaserc",
    "chars": 64,
    "preview": "{\n  \"projects\": {\n    \"default\": \"kakapo-github-explorer\"\n  }\n}\n"
  },
  {
    "path": "examples/github-explorer/README.md",
    "chars": 295,
    "preview": "# Example - Github explorer\n> Example of a github user explorer powered by Kakapo.js - [DEMO](https://kakapo-github-expl"
  },
  {
    "path": "examples/github-explorer/database.rules.json",
    "chars": 38,
    "preview": "{\n  \".read\": true,\n  \".write\": true\n}\n"
  },
  {
    "path": "examples/github-explorer/firebase.json",
    "chars": 199,
    "preview": "{\n  \"database\": {\n    \"rules\": \"database.rules.json\"\n  },\n  \"hosting\": {\n    \"public\": \".\",\n    \"rewrites\": [\n      {\n  "
  },
  {
    "path": "examples/github-explorer/index.html",
    "chars": 1651,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <link href=\"https://fonts.googleapis.com/icon?family=Material+Icons\" rel=\""
  },
  {
    "path": "examples/github-explorer/package.json",
    "chars": 359,
    "preview": "{\n  \"name\": \"kakapo-github-explorer\",\n  \"version\": \"0.1.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n  "
  },
  {
    "path": "examples/github-explorer/styles.css",
    "chars": 907,
    "preview": "nav {\n  padding: 0 10px;\n  margin-bottom: 20px; }\n  nav #nav-mobile label {\n    color: #ccc; }\n    nav #nav-mobile label"
  },
  {
    "path": "examples/github-explorer/styles.scss",
    "chars": 849,
    "preview": "nav {\n  padding: 0 10px;\n  margin-bottom: 20px;\n\n  #nav-mobile label {\n    color: #ccc;\n\n    &.active {\n      display: n"
  },
  {
    "path": "examples/react/.nvmrc",
    "chars": 5,
    "preview": "8.5.0"
  },
  {
    "path": "examples/react/example/app.tsx",
    "chars": 1643,
    "preview": "import * as React from 'react';\nimport {Component} from 'react';\nimport {Server, Router} from '../../../dist';\nimport {A"
  },
  {
    "path": "examples/react/example/index.html",
    "chars": 190,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Example</title>\n</head>\n<body>\n  <div id=\"app\""
  },
  {
    "path": "examples/react/example/index.tsx",
    "chars": 155,
    "preview": "import * as React from 'react';\nimport * as ReactDOM from 'react-dom';\nimport App from './app';\n\nReactDOM.render(<App />"
  },
  {
    "path": "examples/react/example/styled.ts",
    "chars": 82,
    "preview": "import styled from 'styled-components';\n\nexport const AppWrapper = styled.div`\n\n`;"
  },
  {
    "path": "examples/react/package.json",
    "chars": 424,
    "preview": "{\n  \"name\": \"kakapo-react-example\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n"
  },
  {
    "path": "examples/react/tsconfig.json",
    "chars": 558,
    "preview": "{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"strictNullChecks\": true,\n    \"strictFunctionTypes\": true,\n    \"noImpli"
  },
  {
    "path": "examples/todo-app/.firebaserc",
    "chars": 57,
    "preview": "{\n  \"projects\": {\n    \"default\": \"kakapo-todo-app\"\n  }\n}\n"
  },
  {
    "path": "examples/todo-app/README.md",
    "chars": 267,
    "preview": "# Example - TODO App\n> Example of a todo app powered by Kakapo.js - [DEMO](https://kakapo-todo-app.firebaseapp.com/)\n\n!["
  },
  {
    "path": "examples/todo-app/database.rules.json",
    "chars": 38,
    "preview": "{\n  \".read\": true,\n  \".write\": true\n}\n"
  },
  {
    "path": "examples/todo-app/firebase.json",
    "chars": 199,
    "preview": "{\n  \"database\": {\n    \"rules\": \"database.rules.json\"\n  },\n  \"hosting\": {\n    \"public\": \".\",\n    \"rewrites\": [\n      {\n  "
  },
  {
    "path": "examples/todo-app/index.html",
    "chars": 1205,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <title>Kakapo.js - TODO App</title>\n    <link r"
  },
  {
    "path": "examples/todo-app/package.json",
    "chars": 267,
    "preview": "{\n  \"name\": \"kakapo-todo-app\",\n  \"version\": \"0.1.0\",\n  \"description\": \"Todo app built with Kakapo.js\",\n  \"main\": \"index."
  },
  {
    "path": "flow-typed/npm/jest_v22.x.x.js",
    "chars": 20705,
    "preview": "// flow-typed signature: 069387a9f0aaed26ad0eb69da26f3e03\n// flow-typed version: 2c21d4538f/jest_v22.x.x/flow_>=v0.39.x\n"
  },
  {
    "path": "flow-typed/npm/lodash_v4.x.x.js",
    "chars": 190334,
    "preview": "// flow-typed signature: 213ae107c05372e2489e50a054136496\n// flow-typed version: 08e518e6e8/lodash_v4.x.x/flow_>=v0.63.x"
  },
  {
    "path": "jest.config.js",
    "chars": 210,
    "preview": "module.exports = {\n  transform: {\n    \"^.+\\\\.tsx?$\": \"ts-jest\"\n  },\n  testMatch: [\"**/__tests__/**/*_spec.ts?(x)\", \"**/?"
  },
  {
    "path": "jestFrameworkSetup.js",
    "chars": 319,
    "preview": "class Request {\n\n}\n\nclass Response {\n\n  constructor(body) {\n    this.body = body;\n    this.ok = true;\n  }\n\n  json() {\n  "
  },
  {
    "path": "md/end.md",
    "chars": 91,
    "preview": "# Authors \n\n[@rpunkfu](https://github.com/rpunkfu) - [@zzarcon](https://github.com/zzarcon)"
  },
  {
    "path": "md/start.md",
    "chars": 1658,
    "preview": "# Kakapo.js <img src=\"https://sdl-stickershop.line.naver.jp/products/0/0/1/1087538/LINEStorePC/main.png?__=20150924\" wid"
  },
  {
    "path": "package.json",
    "chars": 2652,
    "preview": "{\n  \"name\": \"kakapo\",\n  \"version\": \"4.0.6\",\n  \"description\": \"Next generation mocking framework in Javascript\",\n  \"main\""
  },
  {
    "path": "perf/index.js",
    "chars": 55,
    "preview": "const Kakapo=require('../dist');\n\nconsole.log(Kakapo);\n"
  },
  {
    "path": "src/Database/index.ts",
    "chars": 4825,
    "preview": "import sample from 'lodash.sample';\nimport first from 'lodash.first';\nimport last from 'lodash.last';\nimport filter from"
  },
  {
    "path": "src/Request/index.ts",
    "chars": 436,
    "preview": "export interface KakapoRequestOptions {\n    params: any;\n    query: any;\n    body?: any;\n    headers: any;\n}\n\nexport cla"
  },
  {
    "path": "src/Response/index.ts",
    "chars": 665,
    "preview": "export class KakapoResponse {\n  code: number;\n  body: any;\n  headers: { [header: string]: string };\n\n  constructor(\n    "
  },
  {
    "path": "src/Router/index.ts",
    "chars": 2297,
    "preview": "import merge from 'lodash.merge';\nimport forEach from 'lodash.foreach';\nimport { interceptors, Interceptors } from '../i"
  },
  {
    "path": "src/Server/index.ts",
    "chars": 1444,
    "preview": "import { Router } from '../Router';\nimport { Database, DatabaseSchema } from '../Database';\n\nconst isRouter = <M extends"
  },
  {
    "path": "src/config/environment.ts",
    "chars": 238,
    "preview": "declare var global: any;\n\nconst browserEnv = typeof window === 'object';\nconst nodeEnv = typeof global === 'object';\ncon"
  },
  {
    "path": "src/index.ts",
    "chars": 308,
    "preview": "export { Database, DataRecord } from './Database';\nexport { Router, RouterConfig } from './Router';\nexport { Server } fr"
  },
  {
    "path": "src/interceptors/fetchInterceptor.ts",
    "chars": 3864,
    "preview": "import { KakapoResponse } from '../Response';\nimport { KakapoRequest } from '../Request';\nimport {\n  interceptorHelper,\n"
  },
  {
    "path": "src/interceptors/index.ts",
    "chars": 355,
    "preview": "import * as xhrInterceptor from './xhrInterceptor';\nimport * as fetchInterceptor from './fetchInterceptor';\n\nexport inte"
  },
  {
    "path": "src/interceptors/interceptorHelper.ts",
    "chars": 2477,
    "preview": "import keys from 'lodash.keys';\nimport includes from 'lodash.includes';\nimport pathMatch from 'path-match';\nimport parse"
  },
  {
    "path": "src/interceptors/xhrInterceptor.ts",
    "chars": 8490,
    "preview": "import { KakapoResponse } from '../Response';\nimport { KakapoRequest } from '../Request';\nimport {\n  Interceptor,\n  Inte"
  },
  {
    "path": "src/serializers/index.ts",
    "chars": 28,
    "preview": "export * from './json-api';\n"
  },
  {
    "path": "src/serializers/json-api.ts",
    "chars": 487,
    "preview": "import pickBy from 'lodash.pickby';\n\n// @TODO (zzarcon): Implement 'included' support after relationships\nexport const J"
  },
  {
    "path": "src/utils.ts",
    "chars": 246,
    "preview": "export function mapRequestInfoToUrlString(requestInfo: RequestInfo): string {\n  if (requestInfo instanceof Request) {\n  "
  },
  {
    "path": "tsconfig.dist.json",
    "chars": 136,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./src\"\n  },\n  \"include\": [\n    \"src/**/*\",\n    "
  },
  {
    "path": "tsconfig.json",
    "chars": 492,
    "preview": "{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"noImplicitAny\": true,\n    \"removeComments\": true,\n    \"target\": \"es5\","
  },
  {
    "path": "typings/parse-url/index.d.ts",
    "chars": 27,
    "preview": "declare module 'parse-url';"
  },
  {
    "path": "typings/path-match/index.d.ts",
    "chars": 27,
    "preview": "declare module 'path-match'"
  },
  {
    "path": "typings/query-string/index.d.ts",
    "chars": 30,
    "preview": "declare module 'query-string';"
  },
  {
    "path": "webpack.config.js",
    "chars": 360,
    "preview": "module.exports = {\n  entry: './src',\n  output: {\n    path: './lib',\n    filename: 'kakapo.js',\n    publicPath: '/'\n  },\n"
  },
  {
    "path": "webpack.perf.config.js",
    "chars": 418,
    "preview": "const path = require('path');\n\nmodule.exports = {\n  mode: 'development',\n  entry: path.resolve(__dirname, './perf/index."
  }
]

About this extraction

This page contains the full source code of the devlucky/Kakapo.js GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 69 files (305.8 KB), approximately 87.6k tokens, and a symbol index with 107 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!