From f8d3a2a3238f5cc54af73038e98c9a5c2d9df417 Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Mon, 28 Oct 2019 08:35:04 +0100 Subject: [PATCH 1/8] hw5: mastery check edits --- .DS_Store | Bin 10244 -> 0 bytes .../README.md | 0 .../jsverify-util.js | 0 .../qunit-compat.js | 0 .../resources/jsverify.standalone.js | 0 .../resources/lodash.js | 0 .../resources/qunit-2.4.0.js | 0 .../resources/qunit.css | 0 .../script.js | 0 .../test.html | 0 .../test.js | 0 hw5/Claudio_Maggioni/app.js | 12 ++- hw5/Claudio_Maggioni/readme.md | 3 + .../routes/favourites/router.js | 100 +++++++++++------- .../views/favourite_partial.dust | 5 + hw5/Claudio_Maggioni/views/favourites.dust | 2 +- 16 files changed, 80 insertions(+), 42 deletions(-) delete mode 100644 .DS_Store rename hw2/{claudio_maggioni => Claudio_Maggioni}/README.md (100%) rename hw2/{claudio_maggioni => Claudio_Maggioni}/jsverify-util.js (100%) rename hw2/{claudio_maggioni => Claudio_Maggioni}/qunit-compat.js (100%) rename hw2/{claudio_maggioni => Claudio_Maggioni}/resources/jsverify.standalone.js (100%) rename hw2/{claudio_maggioni => Claudio_Maggioni}/resources/lodash.js (100%) rename hw2/{claudio_maggioni => Claudio_Maggioni}/resources/qunit-2.4.0.js (100%) rename hw2/{claudio_maggioni => Claudio_Maggioni}/resources/qunit.css (100%) rename hw2/{claudio_maggioni => Claudio_Maggioni}/script.js (100%) rename hw2/{claudio_maggioni => Claudio_Maggioni}/test.html (100%) rename hw2/{claudio_maggioni => Claudio_Maggioni}/test.js (100%) create mode 100644 hw5/Claudio_Maggioni/readme.md diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index c5ea1ff5835263c58859204ef9834db8b874187e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMYiu0V6~3SCBr}t7JPrhVH;H#+*Ll@Ryx#Szd9CdY!Nh6Y*ui!Z;_P~-@xpp{ z*;(63jKQ=&+NweP0UAxZa>ilxp-Gw0rO?qlwm@7(X+JB%^3k4Alrc^P90-CP%rhJg^)*K%C7lWwn&f)A4}g0mlP55AgZHOE;H6 zTTV$SrVe_DEda?9Qj3ey22YUm+A?U%DJjW97i3kEvMTH?24r>8d+l;TTTV$St25Y} z57<4!-l0JBPVIX|afYCj&eQRL&M z+j)BA-1&*yC-1l@2LyXkU}XgZd|-BTacitYo=y}!6G_R@y_FrEs;$;b-8XdJct}4y zXsjKh7eA89#F7c?CNpi395l)-8f@oKGSQtjxxH^F86O=dE5@4{=+BsEGu$@M)PLMcrZXL)u|dNawalX?wG|sPL)4E5g zVv)Gnn+T7X#-CJGRH}5j-TkAH*lnY+%sHb*QD)W})~XSHy9Nb zca{4SigJSMJJKdSrCQ(O-liI1rPrdDlTFm=J5|F{dvB$0E35i+zhXqyWASjrj7wFM z-l7=R*%wx!nU? z-xiIUQAJT|vY);txK$==_Ww~P#Q4>kV7*;LVH;Tk3$ZSCnx)wUyPI8P)9eX$nLWjx zV=uAS*;V#i_8xnm{e^wN{t7^Yj#8{a1uEgjdTfOc4e(<>Za^mvp$nhEah$--IE5j^ zF@hvg7{i^I!sqaLd>QxRK3v2Dco@@o4By4~@I(9yzaURZ|$}n4b6MnasVj!=5t_~ zk3|7Li7$b>EUv^ipCPQT->^~l93w=UXBUePV-?4qB1&(n_IL~qI+_5P;6030y0d*6$Uru2KetdD91QU^UH#>LvE^6 zr}cFkt2ckLzVTE0Lo=l!UN!B*QcgKK2>;hrRF=Bjt_@i>DvUyfI4H+QqK_(%OPdq$ zA_95uH6E8MKl&*axq8c1mnJ3x5sq9_w?os!d>}%QYkUowOU@G_NV%%1S#xFQ3lW=K zxqFZ1%FRM@Uf}9ro6A)&Cy7ZyjLzdas3>`Cl%pWYJOSl7!cGG#Vvw(5*R1ixl7Q_1)Fp(;SoG8V)rtBglBODKf_D-CEmi@5|25;DU98# zc`%+OoKp*d)qVXzE%dR1^-Z0BDZVUPS5>ohNj}L3(UKH02ZtQX#3 zJF!bFb^_RoeT2L=bkK6=FmXvYj?$9nByq_gamg(WPgE^vtQSd%f|!7@>RV2{Qtn> z|NocI3p;P(c);<%NA3ZXgnB~l)NJG2M*wB`alAN( nAzSv`h1Uy`p35mIDMi=+{Aa-2^D$@t@9h86_QCW2&Hn#CaW;cU diff --git a/hw2/claudio_maggioni/README.md b/hw2/Claudio_Maggioni/README.md similarity index 100% rename from hw2/claudio_maggioni/README.md rename to hw2/Claudio_Maggioni/README.md diff --git a/hw2/claudio_maggioni/jsverify-util.js b/hw2/Claudio_Maggioni/jsverify-util.js similarity index 100% rename from hw2/claudio_maggioni/jsverify-util.js rename to hw2/Claudio_Maggioni/jsverify-util.js diff --git a/hw2/claudio_maggioni/qunit-compat.js b/hw2/Claudio_Maggioni/qunit-compat.js similarity index 100% rename from hw2/claudio_maggioni/qunit-compat.js rename to hw2/Claudio_Maggioni/qunit-compat.js diff --git a/hw2/claudio_maggioni/resources/jsverify.standalone.js b/hw2/Claudio_Maggioni/resources/jsverify.standalone.js similarity index 100% rename from hw2/claudio_maggioni/resources/jsverify.standalone.js rename to hw2/Claudio_Maggioni/resources/jsverify.standalone.js diff --git a/hw2/claudio_maggioni/resources/lodash.js b/hw2/Claudio_Maggioni/resources/lodash.js similarity index 100% rename from hw2/claudio_maggioni/resources/lodash.js rename to hw2/Claudio_Maggioni/resources/lodash.js diff --git a/hw2/claudio_maggioni/resources/qunit-2.4.0.js b/hw2/Claudio_Maggioni/resources/qunit-2.4.0.js similarity index 100% rename from hw2/claudio_maggioni/resources/qunit-2.4.0.js rename to hw2/Claudio_Maggioni/resources/qunit-2.4.0.js diff --git a/hw2/claudio_maggioni/resources/qunit.css b/hw2/Claudio_Maggioni/resources/qunit.css similarity index 100% rename from hw2/claudio_maggioni/resources/qunit.css rename to hw2/Claudio_Maggioni/resources/qunit.css diff --git a/hw2/claudio_maggioni/script.js b/hw2/Claudio_Maggioni/script.js similarity index 100% rename from hw2/claudio_maggioni/script.js rename to hw2/Claudio_Maggioni/script.js diff --git a/hw2/claudio_maggioni/test.html b/hw2/Claudio_Maggioni/test.html similarity index 100% rename from hw2/claudio_maggioni/test.html rename to hw2/Claudio_Maggioni/test.html diff --git a/hw2/claudio_maggioni/test.js b/hw2/Claudio_Maggioni/test.js similarity index 100% rename from hw2/claudio_maggioni/test.js rename to hw2/Claudio_Maggioni/test.js diff --git a/hw5/Claudio_Maggioni/app.js b/hw5/Claudio_Maggioni/app.js index f071055..926df66 100644 --- a/hw5/Claudio_Maggioni/app.js +++ b/hw5/Claudio_Maggioni/app.js @@ -50,10 +50,18 @@ fs.readFile(__dirname + '/db.json', { encoding: 'utf8' }, (e, data) => { app.use('/bookmarked', routers.bookmarked); }); -app.locals.writeFavs = () => { - fs.writeFile(__dirname + '/db.json', JSON.stringify(app.locals.favourites), +let writing = false; +app.locals.writeFavs = (done) => { + if (writing) { + setTimeout(() => app.locals.writeFavs(done), 100); + return; + } + writing = true; + fs.writeFile(__dirname + '/db.json', JSON.stringify(app.locals.favourites), { encoding: 'utf8' }, err => { if (err) console.error(err); + writing = false; + done(); }); } diff --git a/hw5/Claudio_Maggioni/readme.md b/hw5/Claudio_Maggioni/readme.md new file mode 100644 index 0000000..4e13e9d --- /dev/null +++ b/hw5/Claudio_Maggioni/readme.md @@ -0,0 +1,3 @@ +# Bonuses implemented: +- *Excercise 6*, Bookmarks +- *Excercise 7*, Persistent favourites diff --git a/hw5/Claudio_Maggioni/routes/favourites/router.js b/hw5/Claudio_Maggioni/routes/favourites/router.js index c7b8461..98e6f59 100644 --- a/hw5/Claudio_Maggioni/routes/favourites/router.js +++ b/hw5/Claudio_Maggioni/routes/favourites/router.js @@ -8,8 +8,9 @@ const router = express.Router(); let id = 1; -function nextId() { - return id++; +function nextId(favs) { + while (favs.some((newId => e => e._id == newId)(++id))); + return id; } function createFav(req, res) { @@ -20,26 +21,39 @@ function createFav(req, res) { } const favourite = { - _id: req.body._id ? req.body._id : nextId(), + _id: req.body._id ? req.body._id : nextId(req.app.locals.favourites), name: req.body.name, dataURL: req.body.dataURL, bookmarked: req.body.bookmarked, }; req.app.locals.favourites.push(favourite); - req.app.locals.writeFavs(); - - res.status = 201; - renderFav(req, res, favourite, false); + req.app.locals.writeFavs(() => { + res.status = 201; + renderFav(req, res, favourite, false); + }); } router.post('/', createFav); function renderFav(req, res, favs, list = true) { if (req.accepts('html')) { - res.render(list ? 'favourites.dust' : 'favourite.dust', - list ? { favs: favs } : Object.assign({b: favs.bookmarked === 'true' || - favs.bookmarked === true}, favs)); + let ctx; + if (list) { + const f = []; + for (const e of favs) { + f.push(Object.assign({ + b: e.bookmarked === 'true' || e.bookmarked === true + }, e)); + } + ctx = {favs: f}; + } else { + ctx = Object.assign({ + b: favs.bookmarked === 'true' || favs.bookmarked === true + }, favs); + } + + res.render(list ? 'favourites.dust' : 'favourite.dust', ctx); } else if (req.accepts('json')) { res.json(favs); } else { @@ -76,30 +90,38 @@ router.get('/:id', (req, res) => { } }); -router.put('/:id', (req, res) => { - const edit = req.app.locals.favourites - .find(e => e._id == req.params.id); +function handleUpdate(partial = false) { + return (req, res) => { + const edit = req.app.locals.favourites + .find(e => e._id == req.params.id); - if (!edit) { - createFav(req, res); - } else { - for (const key of ['dataURL', 'name']) { - if (req.body[key]) { - edit[key] = req.body[key]; - } else { - res.writeHead(400, { 'Content-Type': 'text/plain' }); - res.end('Bad PUT form parameters'); - return; + if (!edit) { + createFav(req, res); + } else { + for (const key of ['dataURL', 'name']) { + if (req.body[key]) { + edit[key] = req.body[key]; + } else if (!partial) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad PUT form parameters'); + return; + } } + + if (req.body.bookmarked !== undefined) { + edit.bookmarked = req.body.bookmarked; + } + req.app.locals.writeFavs(() => { + res.status = 200; + renderFav(req, res, edit, false); + }); } + }; +} - edit.bookmarked = !!req.body.bookmarked; - req.app.locals.writeFavs(); +router.put('/:id', handleUpdate()); +router.patch('/:id', handleUpdate(true)); - res.status = 200; - renderFav(req, res, edit, false); - } -}); router.delete('/:id', (req, res) => { let idx = -1; @@ -116,13 +138,13 @@ router.delete('/:id', (req, res) => { return; } else { req.app.locals.favourites.splice(idx, 1); - req.app.locals.writeFavs(); - - res.format({ - json: () => res.writeHead(204), - html: () => res.writeHead(302, { 'Location': '/favorites' }) + req.app.locals.writeFavs(() => { + res.format({ + json: () => res.writeHead(204), + html: () => res.writeHead(302, { 'Location': '/favorites' }) + }); + res.end(); }); - res.end(); } }); @@ -138,10 +160,10 @@ router.put('/:id/bookmarked', (req, res) => { res.end('Bad PUT bookmark form parameters'); } else { edit.bookmarked = req.body.bookmarked; - req.app.locals.writeFavs(); - - res.status = 200; - renderFav(req, res, edit, false); + req.app.locals.writeFavs(() => { + res.status = 200; + renderFav(req, res, edit, false); + }); } }); diff --git a/hw5/Claudio_Maggioni/views/favourite_partial.dust b/hw5/Claudio_Maggioni/views/favourite_partial.dust index c01bcc0..a431d83 100644 --- a/hw5/Claudio_Maggioni/views/favourite_partial.dust +++ b/hw5/Claudio_Maggioni/views/favourite_partial.dust @@ -2,6 +2,11 @@

{name}

{name} +{?b} +

+ Bookmarked +

+{/b} {?details} Details {:else} diff --git a/hw5/Claudio_Maggioni/views/favourites.dust b/hw5/Claudio_Maggioni/views/favourites.dust index ba29203..271d285 100644 --- a/hw5/Claudio_Maggioni/views/favourites.dust +++ b/hw5/Claudio_Maggioni/views/favourites.dust @@ -17,7 +17,7 @@ {/bookmarked} {#favs}
- {>"favourite_partial" name=name dataURL=dataURL _id=_id details="true" /} + {>"favourite_partial" name=name dataURL=dataURL _id=_id b=b details="true" /}
{:else} No favourites. From c6293aea8fa1a3ba89a088b59b33b049f7c8a0ae Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Mon, 28 Oct 2019 15:00:36 +0100 Subject: [PATCH 2/8] hw6: done task 1 & 2 (tests pass) --- hw6/Claudio_Maggioni/.gitignore | 1 + hw6/Claudio_Maggioni/app.js | 45 + hw6/Claudio_Maggioni/bin/www | 9 + hw6/Claudio_Maggioni/config.js | 11 + hw6/Claudio_Maggioni/models/Favorites.js | 20 + hw6/Claudio_Maggioni/package.json | 36 + hw6/Claudio_Maggioni/public/main.js | 15 + hw6/Claudio_Maggioni/public/qunit-compat.js | 5 + .../public/resources/jsverify.standalone.js | 5588 +++++ .../public/resources/lodash.js | 17084 ++++++++++++++++ .../public/resources/qunit-2.4.0.js | 5048 +++++ .../public/resources/qunit.css | 235 + hw6/Claudio_Maggioni/public/scripts/app.js | 259 + .../public/scripts/brushes.js | 53 + hw6/Claudio_Maggioni/public/scripts/undo.js | 37 + hw6/Claudio_Maggioni/public/style.css | 133 + hw6/Claudio_Maggioni/public/test.html | 26 + hw6/Claudio_Maggioni/public/test.js | 103 + .../routes/bookmarked/router.js | 24 + .../routes/favourites_db/router.js | 158 + hw6/Claudio_Maggioni/routes/root/router.js | 24 + hw6/Claudio_Maggioni/routes/routers.js | 35 + hw6/Claudio_Maggioni/routes/utils.js | 39 + hw6/Claudio_Maggioni/seed.js | 9 + .../test/routes/2.favorite.create.js | 56 + .../test/routes/3.favorite.read.js | 127 + .../test/routes/4.favorite.update.js | 44 + .../test/routes/5.favorite.delete.js | 60 + .../test/routes/6.bookmarked.read.js | 91 + hw6/Claudio_Maggioni/test/seed.js | 46 + hw6/Claudio_Maggioni/test/seedData.js | 47 + hw6/Claudio_Maggioni/views/500.dust | 14 + hw6/Claudio_Maggioni/views/favourite.dust | 13 + .../views/favourite_partial.dust | 28 + hw6/Claudio_Maggioni/views/favourites.dust | 28 + hw6/Claudio_Maggioni/views/index.dust | 41 + hw6/Claudio_Maggioni/yarn.lock | 2318 +++ 37 files changed, 31910 insertions(+) create mode 100644 hw6/Claudio_Maggioni/.gitignore create mode 100644 hw6/Claudio_Maggioni/app.js create mode 100755 hw6/Claudio_Maggioni/bin/www create mode 100644 hw6/Claudio_Maggioni/config.js create mode 100644 hw6/Claudio_Maggioni/models/Favorites.js create mode 100644 hw6/Claudio_Maggioni/package.json create mode 100644 hw6/Claudio_Maggioni/public/main.js create mode 100644 hw6/Claudio_Maggioni/public/qunit-compat.js create mode 100644 hw6/Claudio_Maggioni/public/resources/jsverify.standalone.js create mode 100644 hw6/Claudio_Maggioni/public/resources/lodash.js create mode 100644 hw6/Claudio_Maggioni/public/resources/qunit-2.4.0.js create mode 100644 hw6/Claudio_Maggioni/public/resources/qunit.css create mode 100644 hw6/Claudio_Maggioni/public/scripts/app.js create mode 100644 hw6/Claudio_Maggioni/public/scripts/brushes.js create mode 100644 hw6/Claudio_Maggioni/public/scripts/undo.js create mode 100644 hw6/Claudio_Maggioni/public/style.css create mode 100644 hw6/Claudio_Maggioni/public/test.html create mode 100644 hw6/Claudio_Maggioni/public/test.js create mode 100644 hw6/Claudio_Maggioni/routes/bookmarked/router.js create mode 100644 hw6/Claudio_Maggioni/routes/favourites_db/router.js create mode 100644 hw6/Claudio_Maggioni/routes/root/router.js create mode 100644 hw6/Claudio_Maggioni/routes/routers.js create mode 100644 hw6/Claudio_Maggioni/routes/utils.js create mode 100644 hw6/Claudio_Maggioni/seed.js create mode 100644 hw6/Claudio_Maggioni/test/routes/2.favorite.create.js create mode 100644 hw6/Claudio_Maggioni/test/routes/3.favorite.read.js create mode 100644 hw6/Claudio_Maggioni/test/routes/4.favorite.update.js create mode 100644 hw6/Claudio_Maggioni/test/routes/5.favorite.delete.js create mode 100644 hw6/Claudio_Maggioni/test/routes/6.bookmarked.read.js create mode 100644 hw6/Claudio_Maggioni/test/seed.js create mode 100644 hw6/Claudio_Maggioni/test/seedData.js create mode 100644 hw6/Claudio_Maggioni/views/500.dust create mode 100644 hw6/Claudio_Maggioni/views/favourite.dust create mode 100644 hw6/Claudio_Maggioni/views/favourite_partial.dust create mode 100644 hw6/Claudio_Maggioni/views/favourites.dust create mode 100644 hw6/Claudio_Maggioni/views/index.dust create mode 100644 hw6/Claudio_Maggioni/yarn.lock diff --git a/hw6/Claudio_Maggioni/.gitignore b/hw6/Claudio_Maggioni/.gitignore new file mode 100644 index 0000000..58bd488 --- /dev/null +++ b/hw6/Claudio_Maggioni/.gitignore @@ -0,0 +1 @@ +db.json diff --git a/hw6/Claudio_Maggioni/app.js b/hw6/Claudio_Maggioni/app.js new file mode 100644 index 0000000..b9367aa --- /dev/null +++ b/hw6/Claudio_Maggioni/app.js @@ -0,0 +1,45 @@ +// vim: set ts=2 sw=2 et tw=80: + +const express = require('express'); +const path = require('path'); +const logger = require('morgan'); +const bodyParser = require('body-parser'); +const kleiDust = require('klei-dust'); +const methodOverride = require('method-override'); +const fs = require('fs'); + +const mongoose = require('mongoose'); +mongoose.connect('mongodb://localhost/SA3_hw6', { + useNewUrlParser: true, + useUnifiedTopology: true, +}); + +require('./models/Favorites'); + +const app = express(); + +//configure app +app.use(logger('dev')); +app.set('views', __dirname + '/views'); +app.engine('dust', kleiDust.dust); +app.set('view engine', 'dust'); +app.set('view options', { layout: false }); + +app.use(methodOverride('_method')); + +// parse application/x-www-form-urlencoded +app.use(bodyParser.urlencoded({ extended: false })); + +// parse application/json +app.use(bodyParser.json()); + +app.use(express.static('public')); + + +// Initialize routers here +const routers = require('./routes/routers'); +app.use('/', routers.root); +app.use('/favorites', routers.favourites_db); +app.use('/bookmarked', routers.bookmarked); + +module.exports = app; diff --git a/hw6/Claudio_Maggioni/bin/www b/hw6/Claudio_Maggioni/bin/www new file mode 100755 index 0000000..6aa61f4 --- /dev/null +++ b/hw6/Claudio_Maggioni/bin/www @@ -0,0 +1,9 @@ +#!/usr/bin/env node +var debug = require('debug')('canvas-server'); +var app = require('../app'); + +app.set('port', process.env.PORT || 3000); + +var server = app.listen(app.get('port'), function() { + debug('Express server listening on port ' + server.address().port); +}); \ No newline at end of file diff --git a/hw6/Claudio_Maggioni/config.js b/hw6/Claudio_Maggioni/config.js new file mode 100644 index 0000000..0e4b090 --- /dev/null +++ b/hw6/Claudio_Maggioni/config.js @@ -0,0 +1,11 @@ +module.exports = { + //Server URL + url: "http://127.0.0.1:3000", + //Form structure + form: { + _id: "_id", + name: "name", + dataURL: "dataURL", + bookmarked: "bookmarked" // Optional + } +} diff --git a/hw6/Claudio_Maggioni/models/Favorites.js b/hw6/Claudio_Maggioni/models/Favorites.js new file mode 100644 index 0000000..6ed51e4 --- /dev/null +++ b/hw6/Claudio_Maggioni/models/Favorites.js @@ -0,0 +1,20 @@ +// vim: set ts=2 sw=2 et tw=80: + +const mongoose = require('mongoose'); + +const schema = new mongoose.Schema({ + _id: {}, + dataURL: { type: String, required: true }, + name: { type: String, required: true, default: '' }, + bookmarked: { + type: Boolean, + required: false, + default: false, + }, + dateCreated: { type: Date, required: true, default: Date.now } +}); + +const Favorite = mongoose.model('Favorite', schema); + + + diff --git a/hw6/Claudio_Maggioni/package.json b/hw6/Claudio_Maggioni/package.json new file mode 100644 index 0000000..1fdb255 --- /dev/null +++ b/hw6/Claudio_Maggioni/package.json @@ -0,0 +1,36 @@ +{ + "name": "wa-exercise-7-2017-2018", + "version": "0.0.0", + "description": "Exercise 7 of Web Atelier. Express.js and Mongoose", + "main": "app.js", + "scripts": { + "start": "DEBUG='canvas-server' nodemon ./bin/www", + "test": "npm run test-mocha", + "test-mocha": "./node_modules/mocha/bin/mocha -R spec ./test/routes ./test/hypermedia" + }, + "keywords": [ + "Node.js", + "Express.js", + "MongoDB", + "Mongoose", + "REST" + ], + "author": "Vincenzo Ferme, Andrea Gallidabino, Vasileios Triglianos, Ilya Yanok", + "license": "MIT", + "dependencies": { + "body-parser": "^1.19.0", + "debug": "^3.1.0", + "dustjs-linkedin": "^2.7.5", + "express": "^4.16.2", + "klei-dust": "^1.0.0", + "method-override": "^3.0.0", + "mongoose": "^5.7.7", + "morgan": "^1.9.0", + "request": "^2.88.0", + "supertest": "^3.0.0" + }, + "devDependencies": { + "mocha": "^4.0.1", + "should": "^13.1.3" + } +} diff --git a/hw6/Claudio_Maggioni/public/main.js b/hw6/Claudio_Maggioni/public/main.js new file mode 100644 index 0000000..01db374 --- /dev/null +++ b/hw6/Claudio_Maggioni/public/main.js @@ -0,0 +1,15 @@ +// vim: set ts=2 sw=2 tw=80 et: +// Enter your initialization code here + +function init() { + // Create canvas app + const app = new App({ + canvas: 'canvas', + buttons: { + clear: 'clear-btn', + camera: 'camera-btn', + undo: 'undo-btn' + }, + brushToolbar: 'brush-toolbar' + }); +} diff --git a/hw6/Claudio_Maggioni/public/qunit-compat.js b/hw6/Claudio_Maggioni/public/qunit-compat.js new file mode 100644 index 0000000..dec4568 --- /dev/null +++ b/hw6/Claudio_Maggioni/public/qunit-compat.js @@ -0,0 +1,5 @@ +let test = QUnit.test; +let equal = QUnit.assert.equal.bind(QUnit.assert); +let notEqual = QUnit.assert.notEqual.bind(QUnit.assert); +let deepEqual = QUnit.assert.deepEqual.bind(QUnit.assert); +let notDeepEqual = QUnit.assert.notDeepEqual.bind(QUnit.assert); diff --git a/hw6/Claudio_Maggioni/public/resources/jsverify.standalone.js b/hw6/Claudio_Maggioni/public/resources/jsverify.standalone.js new file mode 100644 index 0000000..800d0af --- /dev/null +++ b/hw6/Claudio_Maggioni/public/resources/jsverify.standalone.js @@ -0,0 +1,5588 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jsc = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o (arbitrary a | arbitrary b | ...)) + -> { key: arbitrary a, key: arbitrary b, ... }): + { key: arbitrary a, key: arbitrary b, ... } + ``` + + Mutually recursive definitions. Every reference to a sibling arbitrary + should go through the `tie` function. + + ```js + { arb1, arb2 } = jsc.letrec(function (tie) { + return { + arb1: jsc.tuple(jsc.int, jsc.oneof(jsc.const(null), tie("arb2"))), + arb2: jsc.tuple(jsc.bool, jsc.oneof(jsc.const(null), tie("arb1"))), + } + }); + ``` +*/ +function letrec(definition) { + // We must use a lazy dictionary because we do not know the key set + // before calling the definition. + var lazyArbs = {}; + + function tie(name) { + if (!lazyArbs.hasOwnProperty(name)) { + lazyArbs[name] = lazyArbitrary(); + } + return lazyArbs[name]; + } + + var strictArbs = definition(tie); + + Object.keys(lazyArbs).forEach(function (key) { + var strictArb = strictArbs[key]; + if (!strictArb) { + throw new Error("undefined lazy arbitrary: " + key); + } + lazyArbs[key].strict = strictArb; + }); + + return strictArbs; +} + +function recursive(arbZ, arbS) { + var genZ = arbZ.generator; + var genS = function (recGen) { + var recArb = arbitraryBless({ + generator: recGen, + shrink: shrink.noop, + show: show.def, + }); + return arbS(recArb).generator; + }; + + var gen = generator.recursive(genZ, genS); + return arbitraryBless({ + generator: gen, + shrink: shrink.noop, + show: show.def, + }); +} + +module.exports = { + nonshrink: nonshrink, + pair: pairArb, + either: either, + unit: unit, + dict: dictArb, + json: jsonArb, + nearray: nearrayArb, + array: arrayArb, + tuple: tuple, + sum: sum, + oneof: oneof, + recursive: recursive, + letrec: letrec, +}; + +},{"./arbitraryAssert.js":3,"./arbitraryBless.js":4,"./array.js":5,"./dict.js":7,"./generator.js":13,"./json.js":14,"./pair.js":16,"./show.js":21,"./shrink.js":22,"./utils.js":28,"assert":29}],3:[function(require,module,exports){ +"use strict"; + +var assert = require("assert"); + +function arbitraryAssert(arb) { + assert(arb !== undefined && arb !== null && typeof arb === "object", "arb should be an object"); + assert(typeof arb.generator === "function" && typeof arb.generator.map === "function", + "arb.generator should be a function"); + assert(typeof arb.shrink === "function" && typeof arb.shrink.smap === "function", + "arb.shrink should be a function"); + assert(typeof arb.show === "function", "arb.show should be a function"); + assert(typeof arb.smap === "function", "arb.smap should be a function"); +} + +module.exports = arbitraryAssert; + +},{"assert":29}],4:[function(require,module,exports){ +"use strict"; + +var show = require("./show.js"); + +/** + ### Arbitrary data +*/ + +// Blessing: i.e adding prototype +/* eslint-disable no-use-before-define */ +function arbitraryProtoSMap(f, g, newShow) { + /* jshint validthis:true */ + var arb = this; // eslint-disable-line no-invalid-this + return arbitraryBless({ + generator: arb.generator.map(f), + shrink: arb.shrink.smap(f, g), + show: newShow || show.def, + }); +} +/* eslint-enable no-use-before-define */ + +/** + - `.smap(f: a -> b, g: b -> a, newShow: (b -> string)?): arbitrary b` + + Transform `arbitrary a` into `arbitrary b`. For example: + + `g` should be a [right inverse](http://en.wikipedia.org/wiki/Surjective_function#Surjections_as_right_invertible_functions) of `f`, but doesn't need to be complete inverse. + i.e. i.e. `f` doesn't need to be invertible, only surjective. + + ```js + var positiveIntegersArb = nat.smap( + function (x) { return x + 1; }, + function (x) { return x - 1; }); + ``` + + ```js + var setNatArb = jsc.array(jsc.nat).smap(_.uniq, _.identity); + ``` + + Right inverse means that *f(g(y)) = y* for all *y* in *Y*. Here *Y* is a type of **arrays of unique natural numbers**. For them + ```js + _.uniq(_.identity(y)) = _.uniq(y) = y + ``` + + Opposite: *g(f(x))* for all *x* in *X*, doesn't need to hold. *X* is **arrays of natural numbers**: + ```js + _.identity(_uniq([0, 0])) = [0]] != [0, 0] + ``` + + We need an inverse for shrinking, and there right inverse is enough. We can always *pull back* `smap`ped value, shrink the preimage, and *map* or *push forward* shrunken preimages again. +*/ +function arbitraryBless(arb) { + arb.smap = arbitraryProtoSMap; + return arb; +} + +module.exports = arbitraryBless; + +},{"./show.js":21}],5:[function(require,module,exports){ +"use strict"; + +var arbitraryAssert = require("./arbitraryAssert.js"); +var arbitraryBless = require("./arbitraryBless.js"); +var generator = require("./generator.js"); +var show = require("./show.js"); +var shrink = require("./shrink.js"); +var utils = require("./utils.js"); + +function makeArray(flavour) { + return function arrayImpl(arb) { + arb = utils.force(arb); + + arbitraryAssert(arb); + + return arbitraryBless({ + generator: generator[flavour](arb.generator), + shrink: shrink[flavour](arb.shrink), + show: show.array(arb.show), + }); + }; +} + +var array = makeArray("array"); +var nearray = makeArray("nearray"); + +module.exports = { + array: array, + nearray: nearray, +}; + +},{"./arbitraryAssert.js":3,"./arbitraryBless.js":4,"./generator.js":13,"./show.js":21,"./shrink.js":22,"./utils.js":28}],6:[function(require,module,exports){ +"use strict"; + +var assert = require("assert"); + +var arbitraryBless = require("./arbitraryBless.js"); +var generator = require("./generator.js"); +var show = require("./show.js"); +var shrink = require("./shrink.js"); + +/** + - `bless(arb: {...}): arbitrary a` + + Bless almost arbitrary structure to be proper arbitrary. *Note*: this function mutates argument. + + #### Example: + + ```js + var arbTokens = jsc.bless({ + generator: function () { + switch (jsc.random(0, 2)) { + case 0: return "foo"; + case 1: return "bar"; + case 2: return "quux"; + } + } + }); + ``` +*/ +function bless(arb) { + assert(arb !== null && typeof arb === "object", "bless: arb should be an object"); + assert(typeof arb.generator === "function", "bless: arb.generator should be a function"); + + // default shrink + if (typeof arb.shrink !== "function") { + arb.shrink = shrink.noop; + } + + // default show + if (typeof arb.show !== "function") { + arb.show = show.def; + } + + generator.bless(arb.generator); + shrink.bless(arb.shrink); + + arbitraryBless(arb); + return arb; +} + +module.exports = bless; + +},{"./arbitraryBless.js":4,"./generator.js":13,"./show.js":21,"./shrink.js":22,"assert":29}],7:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +var arbitraryAssert = require("./arbitraryAssert.js"); +var array = require("./array.js"); +var generator = require("./generator.js"); +var pair = require("./pair.js"); +var string = require("./string.js"); +var utils = require("./utils.js"); + +function makeMapShow(elShow) { + return function (m) { + return "{" + Object.keys(m).map(function (k) { + return k + ": " + elShow(m[k]); + }).join(", ") + "}"; + }; +} + +/** + - `dict.generator(gen: generator a): generator (dict a)` +*/ +function generateDict(gen) { + var pairGen = generator.pair(string.string.generator, gen); + var arrayGen = generator.array(pairGen); + var result = arrayGen.map(utils.pairArrayToDict); + + return utils.curried2(result, arguments); +} + +function dict(arb) { + arb = utils.force(arb); + arbitraryAssert(arb); + + var pairArbitrary = pair.pair(string.string, arb); + var arrayArbitrary = array.array(pairArbitrary); + + return arrayArbitrary.smap(utils.pairArrayToDict, utils.dictToPairArray, makeMapShow(arb.show)); +} + +module.exports = { + arbitrary: dict, + generator: generateDict, +}; + +},{"./arbitraryAssert.js":3,"./array.js":5,"./generator.js":13,"./pair.js":16,"./string.js":24,"./utils.js":28}],8:[function(require,module,exports){ +"use strict"; + +var assert = require("assert"); + +/** + ### either +*/ + +function Left(value) { + this.value = value; +} + +function Right(value) { + this.value = value; +} + +/** + - `either.left(value: a): either a b` +*/ +function left(value) { + return new Left(value); +} + +/** + - `either.right(value: b): either a b` +*/ +function right(value) { + return new Right(value); +} + +/** + - `either.either(l: a -> x, r: b -> x): x` +*/ +Left.prototype.either = function lefteither(l) { + return l(this.value); +}; + +Right.prototype.either = function righteither(l, r) { + return r(this.value); +}; + +/** + - `either.isEqual(other: either a b): bool` + + TODO: add `eq` optional parameter +*/ +Left.prototype.isEqual = function leftIsEqual(other) { + assert(other instanceof Left || other instanceof Right, "isEqual: `other` parameter should be either"); + return other instanceof Left && this.value === other.value; +}; + +Right.prototype.isEqual = function rightIsEqual(other) { + assert(other instanceof Left || other instanceof Right, "isEqual: `other` parameter should be either"); + return other instanceof Right && this.value === other.value; +}; + +/** + - `either.bimap(f: a -> c, g: b -> d): either c d` + + ```js + either.bimap(compose(f, g), compose(h, i)) ≡ either.bimap(g, i).bimap(f, h); + ``` + +*/ +Left.prototype.bimap = function leftBimap(f) { + return new Left(f(this.value)); +}; + +Right.prototype.bimap = function rightBimap(f, g) { + return new Right(g(this.value)); +}; + +/** + - `either.first(f: a -> c): either c b` + + ```js + either.first(f) ≡ either.bimap(f, utils.identity) + ``` +*/ +Left.prototype.first = function leftFirst(f) { + return new Left(f(this.value)); +}; + +Right.prototype.first = function rightFirst() { + return this; +}; + +/** + - `either.second(g: b -> d): either a d` + + ```js + either.second(g) === either.bimap(utils.identity, g) + ``` +*/ +Left.prototype.second = function leftSecond() { + return this; +}; + +Right.prototype.second = function rightSecond(g) { + return new Right(g(this.value)); +}; + +module.exports = { + left: left, + right: right, +}; + +},{"assert":29}],9:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +var arbitrary = require("./arbitrary.js"); +var fn = require("./fn.js"); +var primitive = require("./primitive.js"); +var small = require("./small.js"); +var string = require("./string.js"); +var utils = require("./utils.js"); + +var environment = utils.merge(primitive, string, { + pair: arbitrary.pair, + unit: arbitrary.unit, + either: arbitrary.either, + dict: arbitrary.dict, + array: arbitrary.array, + nearray: arbitrary.nearray, + json: arbitrary.json, + fn: fn.fn, + fun: fn.fn, + nonshrink: arbitrary.nonshrink, + small: small.arbitrary, +}); + +module.exports = environment; + +},{"./arbitrary.js":2,"./fn.js":11,"./primitive.js":17,"./small.js":23,"./string.js":24,"./utils.js":28}],10:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +var utils = require("./utils.js"); + +/* + #### FMap (eq : a -> a -> bool) : FMap a + + Finite map, with any object a key. + + Short summary of member functions: + + - FMap.insert (key : a) (value : any) : void + - FMap.get (key : a) : any + - FMap.contains (key : a) : obool +*/ +function FMap(eq) { + this.eq = eq || utils.isEqual; + this.data = []; +} + +FMap.prototype.contains = function FMapContains(key) { + for (var i = 0; i < this.data.length; i++) { + if (this.eq(this.data[i][0], key)) { + return true; + } + } + + return false; +}; + +FMap.prototype.insert = function FMapInsert(key, value) { + for (var i = 0; i < this.data.length; i++) { + if (this.eq(this.data[i][0], key)) { + this.data[i] = [key, value]; + return; + } + } + + this.data.push([key, value]); +}; + +FMap.prototype.get = function FMapGet(key) { // eslint-disable-line consistent-return + for (var i = 0; i < this.data.length; i++) { + if (this.eq(this.data[i][0], key)) { + return this.data[i][1]; + } + } +}; + +module.exports = FMap; + +},{"./utils.js":28}],11:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +var arbitraryBless = require("./arbitraryBless.js"); +var generator = require("./generator.js"); +var FMap = require("./finitemap.js"); +var json = require("./json.js"); +var shrink = require("./shrink.js"); +var utils = require("./utils.js"); + +/** + ### Arbitrary functions + + - `fn(arb: arbitrary a): arbitrary (b -> a)` + - `fun(arb: arbitrary a): arbitrary (b -> a)` +*/ + +function fn(arb) { + arb = utils.force(arb || json.json); + + return arbitraryBless({ + generator: generator.bless(function (size) { + var m = new FMap(); + + var f = function (arg) { + if (!m.contains(arg)) { + var value = arb.generator(size); + m.insert(arg, value); + } + + return m.get(arg); + }; + + f.internalMap = m; + return f; + }), + + shrink: shrink.noop, + show: function (f) { + return "[" + f.internalMap.data.map(function (item) { + return "" + item[0] + ": " + arb.show(item[1]); + }).join(", ") + "]"; + }, + }); +} + +module.exports = { + fn: fn, + fun: fn, +}; + +},{"./arbitraryBless.js":4,"./finitemap.js":10,"./generator.js":13,"./json.js":14,"./shrink.js":22,"./utils.js":28}],12:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +var trampa = require("trampa"); + +/** + #### isPromise p : bool + + Optimistic duck-type check for promises. + Returns `true` if p is an object with `.then` function property. +*/ +function isPromise(p) { + /* eslint-disable no-new-object */ + return new Object(p) === p && typeof p.then === "function"; + /* eslint-enable non-new-object */ +} + +/** + #### map (Functor f) => (p : f a) (g : a -> b) : f b + + This is functor map, known as `map` or `fmap`. + Essentially `f(p)`. If `p` is promise, returns new promise. + Using `map` makes code look very much [CPS-style](http://en.wikipedia.org/wiki/Continuation-passing_style). +*/ +function map(p, g) { + if (isPromise(p)) { + return p.then(function (x) { + return map(x, g); + }); + } else if (trampa.isTrampoline(p)) { + return p.jump(function (x) { + return map(x, g); + }); + } else { + return g(p); + } +} + +/** + #### bind (Functor f) => (k : a -> f b) (xs : a) (h : b -> f c) -> f c + + This is almost monadic bind. +*/ +function bind(f, xs, h) { + var r; + var exc; + try { + r = f.apply(undefined, xs); + } catch (e) { + r = false; + exc = e; + } + + if (isPromise(r)) { + return r.then( + h, + function (e) { + // exc is always unset here + return h(false, e); + } + ); + } else { + return h(r, exc); + } +} + +// recursively unwrap trampoline and promises +function run(x) { + if (isPromise(x)) { + return x.then(run); + } else if (trampa.isTrampoline(x)) { + return run(x.run()); + } else { + return x; + } +} + +function pure(x) { + if (isPromise(x)) { + return x; + } else { + return trampa.wrap(x); + } +} + +module.exports = { + isPromise: isPromise, + map: map, + pure: pure, + bind: bind, + run: run, +}; + +},{"trampa":32}],13:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +var assert = require("assert"); +var either = require("./either.js"); +var random = require("./random.js"); +var sum = require("./sum.js"); +var utils = require("./utils.js"); + +/** + ### Generator functions + + A generator function, `generator a`, is a function `(size: nat) -> a`, which generates a value of given size. + + Generator combinators are auto-curried: + + ```js + var xs = jsc.generator.array(jsc.nat.generator, 1); // ≡ + var ys = jsc.generator.array(jsc.nat.generator)(1); + ``` + + In purely functional approach `generator a` would be explicitly stateful computation: + `(size: nat, rng: randomstate) -> (a, randomstate)`. + *JSVerify* uses an implicit random number generator state, + but the value generation is deterministic (tests are reproducible), + if the primitives from *random* module are used. +*/ + +// Blessing: i.e adding prototype +/* eslint-disable no-use-before-define */ +function generatorProtoMap(f) { + /* jshint validthis:true */ + var generator = this; // eslint-disable-line no-invalid-this + generatorAssert(generator); + return generatorBless(function (size) { + return f(generator(size)); + }); +} + +function generatorProtoFlatMap(f) { + /* jshint validthis:true */ + var generator = this; // eslint-disable-line no-invalid-this + generatorAssert(generator); + return generatorBless(function (size) { + return f(generator(size))(size); + }); +} +/* eslint-enable no-use-before-define */ + +function generatorAssert(generator) { + assert(typeof generator === "function", "generator should be a function"); + assert(generator.map === generatorProtoMap, "generator.map should be a function"); + assert(generator.flatmap === generatorProtoFlatMap, "generator.flatmap should be a function"); + assert(generator.flatMap === generatorProtoFlatMap, "generator.flatMap should be a function"); +} + +/** + - `generator.bless(f: nat -> a): generator a` + + Bless function with `.map` and `.flatmap` properties. + + - `.map(f: a -> b): generator b` + + Map `generator a` into `generator b`. For example: + + ```js + positiveIntegersGenerator = nat.generator.map( + function (x) { return x + 1; }); + ``` + + - `.flatmap(f: a -> generator b): generator b` + + Monadic bind for generators. Also `flatMap` version is supported. +*/ +function generatorBless(generator) { + generator.map = generatorProtoMap; + generator.flatmap = generatorProtoFlatMap; + generator.flatMap = generatorProtoFlatMap; + return generator; +} + +/** + - `generator.constant(x: a): generator a` +*/ +function generateConstant(x) { + return generatorBless(function () { + return x; + }); +} + +/** + - `generator.combine(gen: generator a..., f: a... -> b): generator b` +*/ +function generatorCombine() { + var generators = Array.prototype.slice.call(arguments, 0, -1); + var f = arguments[arguments.length - 1]; + + return generatorBless(function (size) { + var values = generators.map(function (gen) { + return gen(size); + }); + + return f.apply(undefined, values); + }); +} + +/** + - `generator.oneof(gens: list (generator a)): generator a` +*/ +function generateOneof(generators) { + // TODO: generator + generators.forEach(function (gen) { + assert(typeof gen === "function"); + }); + + var result = generatorBless(function (size) { + var idx = random(0, generators.length - 1); + var gen = generators[idx]; + return gen(size); + }); + + return utils.curried2(result, arguments); +} + +// Helper, essentially: log2(size + 1) +function logsize(size) { + return Math.max(Math.round(Math.log(size + 1) / Math.log(2), 0)); +} + +/** + - `generator.recursive(genZ: generator a, genS: generator a -> generator a): generator a` +*/ +function generatorRecursive(genZ, genS) { + return generatorBless(function (size) { + function rec(n, sizep) { + if (n <= 0 || random(0, 3) === 0) { + return genZ(sizep); + } else { + return genS(generatorBless(function (sizeq) { + return rec(n - 1, sizeq); + }))(sizep); + } + } + + return rec(logsize(size), size); + }); +} + +/** + - `generator.pair(genA: generator a, genB: generator b): generator (a, b)` +*/ +function generatePair(genA, genB) { + var result = generatorBless(function (size) { + return [genA(size), genB(size)]; + }); + + return utils.curried3(result, arguments); +} + +/** + - `generator.either(genA: generator a, genB: generator b): generator (either a b)` +*/ +function generateEither(genA, genB) { + var result = generatorBless(function (size) { // eslint-disable-line consistent-return + var n = random(0, 1); + switch (n) { + case 0: return either.left(genA(size)); + case 1: return either.right(genB(size)); + // no default + } + }); + + return utils.curried3(result, arguments); +} +/** + - `generator.unit: generator ()` + + `unit` is an empty tuple, i.e. empty array in JavaScript representation. This is useful as a building block. +*/ +var generateUnit = generatorBless(function () { + return []; +}); + +/** + - `generator.tuple(gens: (generator a, generator b...)): generator (a, b...)` +*/ +function generateTuple(gens) { + var len = gens.length; + var result = generatorBless(function (size) { + var r = []; + for (var i = 0; i < len; i++) { + r[i] = gens[i](size); + } + return r; + }); + + return utils.curried2(result, arguments); +} + +/** + - `generator.sum(gens: (generator a, generator b...)): generator (a | b...)` +*/ +function generateSum(gens) { + var len = gens.length; + var result = generatorBless(function (size) { + var idx = random(0, len - 1); + return sum.addend(idx, len, gens[idx](size)); + }); + + return utils.curried2(result, arguments); +} + +/** + - `generator.array(gen: generator a): generator (array a)` +*/ +function generateArray(gen) { + var result = generatorBless(function (size) { + var arrsize = random(0, logsize(size)); + var arr = new Array(arrsize); + for (var i = 0; i < arrsize; i++) { + arr[i] = gen(size); + } + return arr; + }); + + return utils.curried2(result, arguments); +} + +/** + - `generator.nearray(gen: generator a): generator (array a)` +*/ +function generateNEArray(gen) { + var result = generatorBless(function (size) { + var arrsize = random(1, Math.max(logsize(size), 1)); + var arr = new Array(arrsize); + for (var i = 0; i < arrsize; i++) { + arr[i] = gen(size); + } + return arr; + }); + + return utils.curried2(result, arguments); +} + +/** + - `generator.dict(gen: generator a): generator (dict a)` +*/ + +module.exports = { + pair: generatePair, + either: generateEither, + unit: generateUnit, + tuple: generateTuple, + sum: generateSum, + array: generateArray, + nearray: generateNEArray, + oneof: generateOneof, + constant: generateConstant, + bless: generatorBless, + combine: generatorCombine, + recursive: generatorRecursive, +}; + +},{"./either.js":8,"./random.js":18,"./sum.js":26,"./utils.js":28,"assert":29}],14:[function(require,module,exports){ +"use strict"; + +var assert = require("assert"); + +var arbitraryBless = require("./arbitraryBless.js"); +var dict = require("./dict.js"); +var generator = require("./generator.js"); +var primitive = require("./primitive.js"); +var show = require("./show.js"); +var shrink = require("./shrink.js"); +var string = require("./string.js"); +var utils = require("./utils.js"); + +var nullArb = primitive.constant(null); + +var generateInteger = primitive.integer.generator; +var generateNumber = primitive.number.generator; +var generateBool = primitive.bool.generator; +var generateString = string.string.generator; +var generateNull = nullArb.generator; + +var generateJson = generator.recursive( + generator.oneof([ + generateInteger, + generateNumber, + generateBool, + generateString, + generateNull, + ]), + function (gen) { + return generator.oneof([generator.array(gen), dict.generator(gen)]); + }); + +// Forward declaration +var shrinkDictJson; +var shrinkJson; + +function shrinkRecJson(json) { + if (Array.isArray(json)) { + return shrink.array(shrinkJson, json); + } else { + return shrinkDictJson(json); + } +} + +shrinkJson = shrink.bless(function (json) { + assert(typeof json !== "function"); + + if (json === null) { + return nullArb.shrink(json); + } + + switch (typeof json) { + case "boolean": return primitive.bool.shrink(json); + case "number": return primitive.number.shrink(json); + case "string": return string.string.shrink(json); + default: return shrinkRecJson(json); + } +}); + +shrinkDictJson = (function () { + var pairShrink = shrink.pair(string.string.shrink, shrinkJson); + var arrayShrink = shrink.array(pairShrink); + + return arrayShrink.smap(utils.pairArrayToDict, utils.dictToPairArray); +}()); + +var json = arbitraryBless({ + generator: generateJson, + shrink: shrinkJson, + show: show.def, +}); + +module.exports = { + json: json, +}; + +},{"./arbitraryBless.js":4,"./dict.js":7,"./generator.js":13,"./primitive.js":17,"./show.js":21,"./shrink.js":22,"./string.js":24,"./utils.js":28,"assert":29}],15:[function(require,module,exports){ +/* @flow weak */ +/** + # JSVerify + + + + > Property-based checking. Like QuickCheck. + + [![Build Status](https://secure.travis-ci.org/jsverify/jsverify.svg?branch=master)](http://travis-ci.org/jsverify/jsverify) + [![NPM version](https://badge.fury.io/js/jsverify.svg)](http://badge.fury.io/js/jsverify) + [![Dependency Status](https://david-dm.org/jsverify/jsverify.svg)](https://david-dm.org/jsverify/jsverify) + [![devDependency Status](https://david-dm.org/jsverify/jsverify/dev-status.svg)](https://david-dm.org/jsverify/jsverify#info=devDependencies) + [![Code Climate](https://img.shields.io/codeclimate/github/jsverify/jsverify.svg)](https://codeclimate.com/github/jsverify/jsverify) + + ## Getting Started + + Install the module with: `npm install jsverify` + + ## Synopsis + + ```js + var jsc = require("jsverify"); + + // forall (f : bool -> bool) (b : bool), f (f (f b)) = f(b). + var boolFnAppliedThrice = + jsc.forall("bool -> bool", "bool", function (f, b) { + return f(f(f(b))) === f(b); + }); + + jsc.assert(boolFnAppliedThrice); + // OK, passed 100 tests + ``` +*/ +"use strict"; + +/** + ## Documentation + + ### Usage with [mocha](http://mochajs.org/) + + Using jsverify with mocha is easy, just define the properties and use `jsverify.assert`. + + Starting from version 0.4.3 you can write your specs without any boilerplate: + + ```js + describe("sort", function () { + jsc.property("idempotent", "array nat", function (arr) { + return _.isEqual(sort(sort(arr)), sort(arr)); + }); + }); + ``` + + Starting from version 0.8.0 you can write the specs in TypeScript. There are + typings provided. The drawback is that you cannot use type DSL: + + ```typescript + describe("basic jsverify usage", () => { + jsc.property("(b && b) === b", jsc.bool, b => (b && b) === b); + + jsc.property("boolean fn thrice", jsc.fn(jsc.bool), jsc.bool, (f, b) => + f(f(f(b))) === f(b) + ); + }); + ``` + + You can also provide `--jsverifyRngState state` command line argument, to run tests with particular random generator state. + + ``` + $ mocha examples/nat.js + + 1) natural numbers are less than 90: + Error: Failed after 49 tests and 1 shrinks. rngState: 074e9b5f037a8c21d6; Counterexample: 90; + + $ mocha examples/nat.js --grep 'are less than' --jsverifyRngState 074e9b5f037a8c21d6 + + 1) natural numbers are less than 90: + Error: Failed after 1 tests and 1 shrinks. rngState: 074e9b5f037a8c21d6; Counterexample: 90; + ``` + + Erroneous case is found with first try. + + ### Usage with [jasmine](https://jasmine.github.io/) + + Check [jasmineHelpers.js](helpers/jasmineHelpers.js) and [jasmineHelpers2.js](helpers/jasmineHelpers2.js) for jasmine 1.3 and 2.0 respectively. + + ## API Reference + + > _Testing shows the presence, not the absence of bugs._ + > + > Edsger W. Dijkstra + + To show that propositions hold, we need to construct proofs. + There are two extremes: proof by example (unit tests) and formal (machine-checked) proof. + Property-based testing is somewhere in between. + We formulate propositions, invariants or other properties we believe to hold, but + only test it to hold for numerous (randomly generated) values. + + Types and function signatures are written in [Coq](http://coq.inria.fr/)/[Haskell](http://www.haskell.org/haskellwiki/Haskell)-influenced style: + C# -style `List filter(List v, Func predicate)` is represented by + `filter(v: array T, predicate: T -> bool): array T` in our style. + + Methods and objects live in `jsc` object, e.g. `shrink.bless` method is used by + ```js + var jsc = require("jsverify"); + var foo = jsc.shrink.bless(...); + ``` + + Methods starting with `.dot` are prototype methods: + ```js + var arb = jsc.nat; + var arb2 = jsc.nat.smap(f, g); + ``` + + `jsverify` can operate with both synchronous and asynchronous-promise properties. + Generally every property can be wrapped inside [functor](http://learnyouahaskell.com/functors-applicative-functors-and-monoids), + for now in either identity or promise functor, for synchronous and promise properties respectively. +*/ + +var assert = require("assert"); +var lazyseq = require("lazy-seq"); + +var api = require("./api.js"); +var either = require("./either.js"); +var environment = require("./environment.js"); +var FMap = require("./finitemap.js"); +var fn = require("./fn.js"); +var functor = require("./functor.js"); +var random = require("./random.js"); +var show = require("./show.js"); +var shrink = require("./shrink.js"); +var suchthat = require("./suchthat.js"); +var sum = require("./sum.js"); +var typify = require("./typify.js"); +var utils = require("./utils.js"); + +/** + ### Properties +*/ + +function shrinkResult(arbs, x, test, size, shrinksN, exc, transform) { + assert(arbs.length === x.length, "shrinkResult: arbs and x has to be of same size"); + assert(typeof size === "number", "shrinkResult: size should be number"); + assert(typeof shrinksN === "number", "shrinkResult: shrinkN should be number"); + + var shrinks = utils.pluck(arbs, "shrink"); + var shows = utils.pluck(arbs, "show"); + + var shrinked = shrink.tuple(shrinks, x); + + var shrinkP = lazyseq.fold(shrinked, true, function (y, rest) { + var t = test(size, y, shrinksN + 1); + return functor.map(t, function (tprime) { + return tprime !== true ? tprime : rest(); + }); + }); + + return functor.map(shrinkP, function (shrinkPPrime) { + if (shrinkPPrime === true) { + var res = { + counterexample: x, + counterexamplestr: show.tuple(shows, x), + shrinks: shrinksN, + exc: exc, + }; + return transform(res); + } else { + return shrinkPPrime; + } + }); +} + +function isArbitrary(arb) { + return (typeof arb === "object" || typeof arb === "function") && + typeof arb.generator === "function" && + typeof arb.shrink === "function" && + typeof arb.show === "function"; +} + +/** + - `forall(arbs: arbitrary a ..., userenv: (map arbitrary)?, prop : a -> property): property` + + Property constructor +*/ +function forall() { + var args = Array.prototype.slice.call(arguments); + var gens = args.slice(0, -1); + var property = args[args.length - 1]; + var env; + + var lastgen = gens[gens.length - 1]; + + if (!isArbitrary(lastgen) && typeof lastgen !== "string") { + env = utils.merge(environment, lastgen); + gens = gens.slice(0, -1); + } else { + env = environment; + } + + assert(gens.length > 0, "forall requires at least single generator"); + + // Map typify-dsl to hard generators + gens = gens.map(function (g) { + g = typeof g === "string" ? typify.parseTypify(env, g) : g; + return utils.force(g); + }); + + assert(typeof property === "function", "property should be a function"); + + function test(size, x, shrinks) { + assert(Array.isArray(x), "generators results should be always tuple"); + + return functor.bind(property, x, function (r, exc) { + if (r === true) { + return true; + } else if (typeof r === "function") { + var rRec = r(size); + + return functor.map(rRec, function (rRecPrime) { + if (rRecPrime === true) { + return true; + } else { + return shrinkResult(gens, x, test, size, shrinks, exc, function (rr) { + return { + counterexample: rr.counterexample.concat(rRecPrime.counterexample), + counterexamplestr: rr.counterexamplestr, // + "; " + rRec.counterexamplestr, + shrinks: rr.shrinks, + exc: rr.exc || rRecPrime.exc, + }; + }); + } + }); + } else { + return shrinkResult(gens, x, test, size, shrinks, exc || r, utils.identity); + } + }); + } + + return function (size) { + var x = gens.map(function (arb) { return arb.generator(size); }); + var r = test(size, x, 0); + return r; + }; +} + +function formatFailedCase(r, state, includeStack) { + var msg = "Failed after " + r.tests + " tests and " + r.shrinks + " shrinks. "; + msg += "rngState: " + (r.rngState || state) + "; "; + msg += "Counterexample: " + r.counterexamplestr + "; "; + if (r.exc) { + if (r.exc instanceof Error) { + msg += "Exception: " + r.exc.message; + if (includeStack) { + msg += "\nStack trace: " + r.exc.stack; + } + } else { + msg += "Error: " + r.exc; + } + } + return msg; +} + +function findRngState(argv) { // eslint-disable-line consistent-return + for (var i = 0; i < argv.length - 1; i++) { + if (argv[i] === "--jsverifyRngState") { + return argv[i + 1]; + } + } +} + +/** + - `check (prop: property, opts: checkoptions?): result` + + Run random checks for given `prop`. If `prop` is promise based, result is also wrapped in promise. + + Options: + - `opts.tests` - test count to run, default 100 + - `opts.size` - maximum size of generated values, default 50 + - `opts.quiet` - do not `console.log` + - `opts.rngState` - state string for the rng + + The `result` is `true` if check succeeds, otherwise it's an object with various fields: + - `counterexample` - an input for which property fails. + - `tests` - number of tests run before failing case is found + - `shrinks` - number of shrinks performed + - `exc` - an optional exception thrown by property function + - `rngState` - random number generator's state before execution of the property +*/ +function check(property, opts) { + opts = opts || {}; + opts.size = opts.size || 50; + opts.tests = opts.tests || 100; + opts.quiet = opts.quiet || false; + + assert(typeof property === "function", "property should be a function"); + + var state; + + if (opts.rngState) { + random.setStateString(opts.rngState); + } else if (typeof process !== "undefined") { + var argvState = findRngState(process.argv); + if (argvState) { + random.setStateString(argvState); + } + } + + function loop(i) { + state = random.currentStateString(); + if (i > opts.tests) { + return true; + } + + var size = random(0, opts.size); + + // wrap non-promises in trampoline + var r = functor.pure(property(size)); + + return functor.map(r, function (rPrime) { + if (rPrime === true) { + return loop(i + 1); + } else { + rPrime.tests = i; + /* global console */ + if (!opts.quiet) { + console.error(formatFailedCase(rPrime, state, true), rPrime.counterexample); + } + return rPrime; + } + }); + } + + return functor.run(functor.map(loop(1), function (r) { + if (r === true) { + if (!opts.quiet) { console.info("OK, passed " + opts.tests + " tests"); } + } else { + r.rngState = state; + } + + return r; + })); +} + +/** + - `assert(prop: property, opts: checkoptions?) : void` + + Same as `check`, but throw exception if property doesn't hold. +*/ +function checkThrow(property, opts) { + opts = opts || {}; + if (opts.quiet === undefined) { + opts.quiet = true; + } + + return functor.run(functor.map(check(property, opts), function (r) { + if (r !== true) { + if (r.exc instanceof Error) { + r.exc.message = formatFailedCase(r); + throw r.exc; + } else { + throw new Error(formatFailedCase(r)); + } + } + })); +} + +/** + - `property(name: string, ...)` + + Assuming there is globally defined `it`, the same as: + + ```js + it(name, function () { + jsc.assert(jsc.forall(...)); + } + ``` + + You can use `property` to write facts too: + ```js + jsc.property("+0 === -0", function () { + return +0 === -0; + }); + ``` +*/ +function bddProperty(name) { + /* global it: true */ + var args = Array.prototype.slice.call(arguments, 1); + if (args.length === 1) { + it(name, function () { + return functor.run(functor.map(args[0](), function (result) { // eslint-disable-line consistent-return + if (typeof result === "function") { + return checkThrow(result); + } else if (result !== true) { + throw new Error(name + " doesn't hold"); + } + })); + }); + } else { + var prop = forall.apply(undefined, args); + it(name, function () { + return checkThrow(prop); + }); + } + /* global it: false */ +} + +/** + - `compile(desc: string, env: typeEnv?): arbitrary a` + + Compile the type description in provided type environment, or default one. +*/ +function compile(str, env) { + env = env ? utils.merge(environment, env) : environment; + return typify.parseTypify(env, str); +} + +/** + - `sampler(arb: arbitrary a, genSize: nat = 10): (sampleSize: nat?) -> a` + + Create a sampler for a given arbitrary with an optional size. Handy when used in + a REPL: + ``` + > jsc = require('jsverify') // or require('./lib/jsverify') w/in the project + ... + > jsonSampler = jsc.sampler(jsc.json, 4) + [Function] + > jsonSampler() + 0.08467432763427496 + > jsonSampler() + [ [ [] ] ] + > jsonSampler() + '' + > sampledJson(2) + [-0.4199344692751765, false] + ``` +*/ +function sampler(arb, size) { + size = typeof size === "number" ? Math.abs(size) : 10; + return function (count) { + if (typeof count === "number") { + var acc = []; + count = Math.abs(count); + for (var i = 0; i < count; i++) { + acc.push(arb.generator(size)); + } + return acc; + } else { + return arb.generator(size); + } + }; +} + +/** + - `throws(block: () -> a, error: class?, message: string?): bool` + + Executes nullary function `block`. Returns `true` if `block` throws. See [assert.throws](https://nodejs.org/api/assert.html#assert_assert_throws_block_error_message) +*/ +function throws(block, error, message) { + assert(error === undefined || typeof error === "function", "throws: error parameter must be a constructor"); + assert(message === undefined || typeof message === "string", "throws: message parameter must be a string"); + + try { + block(); + return false; + } catch (e) { + if (error !== undefined) { + if (e instanceof error) { + return message === undefined || e.message === message; + } else { + return false; + } + } else { + return true; + } + } +} + +/** + - `assertForall(arbs: arbitrary a ..., userenv: (map arbitrary)?, prop : a -> property): void` + + Combines 'assert' and 'forall'. + Constructs a property with forall from arguments, then throws an exception if the property doesn't hold. + Options for 'assert' cannot be set here - use assert(forall(...)) if you need that. +*/ +function assertForall() { + return checkThrow(forall.apply(null, arguments)); +} + +/** + - `checkForall(arbs: arbitrary a ..., userenv: (map arbitrary)?, prop : a -> property): result` + + Combines 'check' and 'forall'. + Constructs a property with forall from arguments, and returns a value based on if the property holds or not. + See 'check' for description of return value. + + Options for 'check' cannot be set here - use check(forall(...)) if you need that. +*/ +function checkForall() { + return check(forall.apply(null, arguments)); +} + +/** + ### Types + + - `generator a` is a function `(size: nat) -> a`. + - `show` is a function `a -> string`. + - `shrink` is a function `a -> [a]`, returning *smaller* values. + - `arbitrary a` is a triple of generator, shrink and show functions. + - `{ generator: nat -> a, shrink : a -> array a, show: a -> string }` + + ### Blessing + + We chose to represent generators and shrinks by functions, yet we would + like to have additional methods on them. Thus we *bless* objects with + additional properties. + + Usually you don't need to bless anything explicitly, as all combinators + return blessed values. + + See [perldoc for bless](http://perldoc.perl.org/functions/bless.html). +*/ + +/// include ./typify.js +/// include ./arbitraryBless.js +/// include ./bless.js +/// include ./primitive.js +/// include ./arbitrary.js +/// include ./recordWithEnv.js +/// include ./record.js +/// include ./string.js +/// include ./fn.js +/// include ./small.js +/// include ./suchthat.js +/// include ./generator.js +/// include ./shrink.js +/// include ./show.js +/// include ./random.js +/// include ./either.js +/// include ./utils.js + +// Export +var jsc = { + forall: forall, + check: check, + assert: checkThrow, + assertForall: assertForall, + checkForall: checkForall, + property: bddProperty, + sampler: sampler, + throws: throws, + + // generators + fn: fn.fn, + fun: fn.fn, + suchthat: suchthat.suchthat, + + // either + left: either.left, + right: either.right, + + // sum + addend: sum.addend, + + // compile + compile: compile, + + generator: api.generator, + shrink: api.shrink, + + // internal utility lib + random: random, + + show: show, + utils: utils, + _: { + FMap: FMap, + }, +}; + +/* primitives */ +/* eslint-disable guard-for-in */ +for (var k in api.arbitrary) { + jsc[k] = api.arbitrary[k]; +} +/* eslint-enable guard-for-in */ + +module.exports = jsc; + +/// plain ../FAQ.md +/// plain ../CONTRIBUTING.md +/// plain ../CHANGELOG.md +/// plain ../related-work.md +/// plain ../LICENSE + +},{"./api.js":1,"./either.js":8,"./environment.js":9,"./finitemap.js":10,"./fn.js":11,"./functor.js":12,"./random.js":18,"./show.js":21,"./shrink.js":22,"./suchthat.js":25,"./sum.js":26,"./typify.js":27,"./utils.js":28,"assert":29,"lazy-seq":30}],16:[function(require,module,exports){ +"use strict"; + +var arbitraryAssert = require("./arbitraryAssert.js"); +var arbitraryBless = require("./arbitraryBless.js"); +var generator = require("./generator.js"); +var show = require("./show.js"); +var shrink = require("./shrink.js"); +var utils = require("./utils.js"); + +function pair(a, b) { + a = utils.force(a); + b = utils.force(b); + + arbitraryAssert(a); + arbitraryAssert(b); + + return arbitraryBless({ + generator: generator.pair(a.generator, b.generator), + shrink: shrink.pair(a.shrink, b.shrink), + show: show.pair(a.show, b.show), + }); +} + +module.exports = { + pair: pair, +}; + +},{"./arbitraryAssert.js":3,"./arbitraryBless.js":4,"./generator.js":13,"./show.js":21,"./shrink.js":22,"./utils.js":28}],17:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +var arbitraryBless = require("./arbitraryBless"); +var assert = require("assert"); +var generator = require("./generator.js"); +var random = require("./random.js"); +var show = require("./show.js"); +var shrink = require("./shrink.js"); +var utils = require("./utils.js"); + +/** + ### Primitive arbitraries +*/ + +function extendWithDefault(arb) { + var def = arb(); + arb.generator = def.generator; + arb.shrink = def.shrink; + arb.show = def.show; + arb.smap = def.smap; +} + +function numeric(impl) { + return function (minsize, maxsize) { + if (arguments.length === 2) { + var arb = arbitraryBless(impl(maxsize - minsize)); + var to = function to(x) { + return Math.abs(x) + minsize; + }; + var from = function from(x) { + return x - minsize; + }; + + return arb.smap(to, from); + } else if (arguments.length === 1) { + return arbitraryBless(impl(minsize /* as maxsize */)); + } else { + return arbitraryBless(impl()); + } + }; +} + +/** + - `integer: arbitrary integer` + - `integer(maxsize: nat): arbitrary integer` + - `integer(minsize: integer, maxsize: integer): arbitrary integer` + + Integers, ℤ +*/ +var integer = numeric(function integer(maxsize) { + return { + generator: generator.bless(function (size) { + size = maxsize === undefined ? size : maxsize; + return random(-size, size); + }), + shrink: shrink.bless(function (i) { + assert(typeof i === "number", "integer.shrink have to be a number"); + + i = Math.abs(i); + if (i === 0) { + return []; + } else { + var arr = [0]; + var j = utils.div2(i); + var k = Math.max(j, 1); + while (j < i) { + arr.push(j); + arr.push(-j); + k = Math.max(utils.div2(k), 1); + j += k; + } + return arr; + } + }), + + show: show.def, + }; +}); + +extendWithDefault(integer); + +/** + - `nat: arbitrary nat` + - `nat(maxsize: nat): arbitrary nat` + + Natural numbers, ℕ (0, 1, 2...) +*/ +function nat(maxsize) { + return arbitraryBless({ + generator: generator.bless(function (size) { + size = maxsize === undefined ? size : maxsize; + return random(0, size); + }), + shrink: shrink.bless(function (i) { + assert(typeof i === "number", "nat.shrink have to be a number"); + + var arr = []; + var j = utils.div2(i); + var k = Math.max(j, 1); + while (j < i) { + arr.push(j); + k = Math.max(utils.div2(k), 1); + j += k; + } + return arr; + }), + show: show.def, + }); +} + +extendWithDefault(nat); + +/** + - `number: arbitrary number` + - `number(maxsize: number): arbitrary number` + - `number(min: number, max: number): arbitrary number` + + JavaScript numbers, "doubles", ℝ. `NaN` and `Infinity` are not included. +*/ +var number = numeric(function number(maxsize) { + return { + generator: generator.bless(function (size) { + size = maxsize === undefined ? size : maxsize; + return random.number(-size, size); + }), + shrink: shrink.bless(function (x) { + assert(typeof x === "number", "number.shrink have to be a number"); + + if (Math.abs(x) > 1e-6) { + return [0, x / 2, -x / 2]; + } else { + return []; + } + }), + show: show.def, + }; +}); + +extendWithDefault(number); + +/** + - `uint8: arbitrary nat` + - `uint16: arbitrary nat` + - `uint32: arbitrary nat` +*/ +var uint8 = nat(0xff); +var uint16 = nat(0xffff); +var uint32 = nat(0xffffffff); + +/** + - `int8: arbitrary integer` + - `int16: arbitrary integer` + - `int32: arbitrary integer` +*/ +var int8 = integer(-0x80, 0x7f); +var int16 = integer(-0x8000, 0x7fff); +var int32 = integer(-0x80000000, 0x7fffffff); + +/** + - `bool: arbitrary bool` + + Booleans, `true` or `false`. +*/ +var bool = arbitraryBless({ + generator: generator.bless(function (/* size */) { + var i = random(0, 1); + return i === 1; + }), + + shrink: shrink.bless(function (b) { + assert(b === true || b === false, "bool.shrink excepts true or false"); + return b === true ? [false] : []; + }), + show: show.def, +}); + +/** + - `datetime: arbitrary datetime` + + Random datetime +*/ +var datetimeConst = 1416499879495; // arbitrary datetime + +function datetime(from, to) { + var toDate; + var fromDate; + var arb; + + if (arguments.length === 2) { + toDate = function toDateFn(x) { + return new Date(x); + }; + fromDate = function fromDateFn(x) { + return x.getTime(); + }; + from = fromDate(from); + to = fromDate(to); + arb = number(from, to); + + return arb.smap(toDate, fromDate); + } else { + toDate = function toDateFn(x) { + return new Date(x * 768000000 + datetimeConst); + }; + arb = number; + + return arbitraryBless({ + generator: arb.generator.map(toDate), + shrink: shrink.noop, + show: show.def, + }); + } +} + +extendWithDefault(datetime); + +/** + - `elements(args: array a): arbitrary a` + + Random element of `args` array. +*/ +function elements(args) { + assert(args.length !== 0, "elements: at least one parameter expected"); + + return arbitraryBless({ + generator: generator.bless(function (/* size */) { + var i = random(0, args.length - 1); + return args[i]; + }), + + shrink: shrink.bless(function (x) { + var idx = args.indexOf(x); + if (idx <= 0) { + return []; + } else { + return args.slice(0, idx); + } + }), + show: show.def, + }); +} + +/** + - `falsy: arbitrary *` + + Generates falsy values: `false`, `null`, `undefined`, `""`, `0`, and `NaN`. +*/ +var falsy = elements([false, null, undefined, "", 0, NaN]); +falsy.show = function (v) { + if (v !== v) { + return "falsy: NaN"; + } else if (v === "") { + return "falsy: empty string"; + } else if (v === undefined) { + return "falsy: undefined"; + } else { + return "falsy: " + v; + } +}; + +/** + - `constant(x: a): arbitrary a` + + Returns an unshrinkable arbitrary that yields the given object. +*/ +function constant(x) { + return arbitraryBless({ + generator: generator.constant(x), + shrink: shrink.noop, + show: show.def, + }); +} + +module.exports = { + integer: integer, + nat: nat, + int8: int8, + int16: int16, + int32: int32, + uint8: uint8, + uint16: uint16, + uint32: uint32, + number: number, + elements: elements, + bool: bool, + falsy: falsy, + constant: constant, + datetime: datetime, +}; + +},{"./arbitraryBless":4,"./generator.js":13,"./random.js":18,"./show.js":21,"./shrink.js":22,"./utils.js":28,"assert":29}],18:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +var rc4 = new (require("rc4").RC4small)(); + +/** + ### Random functions +*/ + +/** + - `random(min: int, max: int): int` + + Returns random int from `[min, max]` range inclusively. + + ```js + getRandomInt(2, 3) // either 2 or 3 + ``` +*/ +function randomInteger(min, max) { + return rc4.random(min, max); +} + +/** + - `random.number(min: number, max: number): number` + + Returns random number from `[min, max)` range. +*/ +function randomNumber(min, max) { + return rc4.randomFloat() * (max - min) + min; +} + +randomInteger.integer = randomInteger; +randomInteger.number = randomNumber; + +randomInteger.currentStateString = rc4.currentStateString.bind(rc4); +randomInteger.setStateString = rc4.setStateString.bind(rc4); + +module.exports = randomInteger; + +},{"rc4":31}],19:[function(require,module,exports){ +"use strict"; + +var arbitraryBless = require("./arbitraryBless.js"); +var generator = require("./generator.js"); +var utils = require("./utils.js"); +var shrink = require("./shrink.js"); + +/** + - `generator.record(gen: { key: generator a... }): generator { key: a... }` +*/ +function generatorRecord(spec) { + var keys = Object.keys(spec); + var result = generator.bless(function (size) { + var res = {}; + keys.forEach(function (k) { + res[k] = spec[k](size); + }); + return res; + }); + + return utils.curried2(result, arguments); +} + +/** + - `shrink.record(shrs: { key: shrink a... }): shrink { key: a... }` +*/ +function shrinkRecord(shrinksRecord) { + var keys = Object.keys(shrinksRecord); + var shrinks = keys.map(function (k) { return shrinksRecord[k]; }); + + var result = shrink.bless(function (rec) { + var values = keys.map(function (k) { return rec[k]; }); + var shrinked = shrink.tuple(shrinks, values); + + return shrinked.map(function (s) { + var res = {}; + keys.forEach(function (k, i) { + res[k] = s[i]; + }); + return res; + }); + }); + + return utils.curried2(result, arguments); +} + +function arbitraryRecord(spec) { + var generatorSpec = {}; + var shrinkSpec = {}; + var showSpec = {}; + + Object.keys(spec).forEach(function (k) { + var arb = utils.force(spec[k]); + generatorSpec[k] = arb.generator; + shrinkSpec[k] = arb.shrink; + showSpec[k] = arb.show; + }); + + return arbitraryBless({ + generator: generatorRecord(generatorSpec), + shrink: shrinkRecord(shrinkSpec), + show: function (m) { + return "{" + Object.keys(m).map(function (k) { + return k + ": " + showSpec[k](m[k]); + }).join(", ") + "}"; + }, + }); +} + +module.exports = { + generator: generatorRecord, + arbitrary: arbitraryRecord, + shrink: shrinkRecord, +}; + +},{"./arbitraryBless.js":4,"./generator.js":13,"./shrink.js":22,"./utils.js":28}],20:[function(require,module,exports){ +"use strict"; + +var environment = require("./environment.js"); +var record = require("./record.js"); +var typify = require("./typify.js"); +var utils = require("./utils.js"); + +/** + ### Arbitrary records + + - `record(spec: { key: arbitrary a... }, userenv: env?): arbitrary { key: a... }` + + Generates a javascript object with given record spec. +*/ +function recordWithEnv(spec, userenv) { + var env = userenv ? utils.merge(environment, userenv) : environment; + + var parsedSpec = {}; + Object.keys(spec).forEach(function (k) { + var arb = spec[k]; + parsedSpec[k] = typeof arb === "string" ? typify.parseTypify(env, arb) : arb; + }); + + return record.arbitrary(parsedSpec); +} + +module.exports = recordWithEnv; + +},{"./environment.js":9,"./record.js":19,"./typify.js":27,"./utils.js":28}],21:[function(require,module,exports){ + +/* @flow weak */ +"use strict"; + +/** + ### Show functions +*/ + +var utils = require("./utils.js"); + +/** + - `show.def(x : a): string` + + Currently implemented as `JSON.stringify`. +*/ +function showDef(obj) { + return JSON.stringify(obj); +} + +/** + - `show.pair(showA: a -> string, showB: b -> string, x: (a, b)): string` +*/ +function showPair(showA, showB) { + var result = function (p) { + return "(" + showA(p[0]) + ", " + showB(p[1]) + ")"; + }; + + return utils.curried3(result, arguments); +} + +/** + - `show.either(showA: a -> string, showB: b -> string, e: either a b): string` +*/ +function showEither(showA, showB) { + function showLeft(value) { + return "Left(" + showA(value) + ")"; + } + + function showRight(value) { + return "Right(" + showB(value) + ")"; + } + + var result = function (e) { + return e.either(showLeft, showRight); + }; + + return utils.curried3(result, arguments); +} + +/** + - `show.tuple(shrinks: (a -> string, b -> string...), x: (a, b...)): string` +*/ +function showTuple(shows) { + var result = function (objs) { + var strs = []; + for (var i = 0; i < shows.length; i++) { + strs.push(shows[i](objs[i])); + } + return strs.join("; "); + }; + + return utils.curried2(result, arguments); +} + +/** + - `show.sum(shrinks: (a -> string, b -> string...), x: (a | b ...)): string` +*/ +function showSum(shows) { + var result = function (sum) { + return sum.fold(function (idx, n, value) { + return "Sum(" + idx + "/" + n + ": " + shows[idx](value) + ")"; + }); + }; + + return utils.curried2(result, arguments); +} + +/** + - `show.array(shrink: a -> string, x: array a): string` +*/ +function showArray(show) { + var result = function (arr) { + return "[" + arr.map(show).join(", ") + "]"; + }; + + return utils.curried2(result, arguments); +} + +module.exports = { + def: showDef, + pair: showPair, + either: showEither, + tuple: showTuple, + sum: showSum, + array: showArray, +}; + +},{"./utils.js":28}],22:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +var assert = require("assert"); +var either = require("./either.js"); +var lazyseq = require("lazy-seq"); +var sum = require("./sum.js"); +var utils = require("./utils.js"); + +/** + ### Shrink functions + + A shrink function, `shrink a`, is a function `a -> [a]`, returning an array of *smaller* values. + + Shrink combinators are auto-curried: + + ```js + var xs = jsc.shrink.array(jsc.nat.shrink, [1]); // ≡ + var ys = jsc.shrink.array(jsc.nat.shrink)([1]); + ``` +*/ + +// Blessing: i.e adding prototype +/* eslint-disable no-use-before-define */ +function shrinkProtoIsoMap(f, g) { + /* jshint validthis:true */ + var shrink = this; // eslint-disable-line no-invalid-this + return shrinkBless(function (value) { + return shrink(g(value)).map(f); + }); +} +/* eslint-enable no-use-before-define */ + +/** + - `shrink.bless(f: a -> [a]): shrink a` + + Bless function with `.smap` property. + + - `.smap(f: a -> b, g: b -> a): shrink b` + + Transform `shrink a` into `shrink b`. For example: + + ```js + positiveIntegersShrink = nat.shrink.smap( + function (x) { return x + 1; }, + function (x) { return x - 1; }); + ``` +*/ +function shrinkBless(shrink) { + shrink.smap = shrinkProtoIsoMap; + return shrink; +} + +/** + - `shrink.noop: shrink a` +*/ +var shrinkNoop = shrinkBless(function shrinkNoop() { + return []; +}); + +/** + - `shrink.pair(shrA: shrink a, shrB: shrink b): shrink (a, b)` +*/ +function shrinkPair(shrinkA, shrinkB) { + var result = shrinkBless(function (pair) { + assert(pair.length === 2, "shrinkPair: pair should be an Array of length 2"); + + var a = pair[0]; + var b = pair[1]; + + var shrinkedA = shrinkA(a); + var shrinkedB = shrinkB(b); + + var pairA = shrinkedA.map(function (ap) { + return [ap, b]; + }); + + if (Array.isArray(pairA)) { + pairA = lazyseq.fromArray(pairA); + } + + return pairA.append(function () { + var pairB = shrinkedB.map(function (bp) { + return [a, bp]; + }); + return pairB; + }); + }); + + return utils.curried3(result, arguments); +} + +/** + - `shrink.either(shrA: shrink a, shrB: shrink b): shrink (either a b)` +*/ +function shrinkEither(shrinkA, shrinkB) { + function shrinkLeft(value) { + return shrinkA(value).map(either.left); + } + + function shrinkRight(value) { + return shrinkB(value).map(either.right); + } + + var result = shrinkBless(function (e) { + return e.either(shrinkLeft, shrinkRight); + }); + + return utils.curried3(result, arguments); +} + +// We represent non-empty linked list as +// singl x = [x] +// cons h t = [h, t] +function fromLinkedList(ll) { + assert(ll.length === 1 || ll.length === 2, "linked list must be either [] or [x, linkedlist]"); + if (ll.length === 1) { + return [ll[0]]; + } else { + return [ll[0]].concat(fromLinkedList(ll[1])); + } +} + +function toLinkedList(arr) { + assert(Array.isArray(arr) && arr.length > 0, "toLinkedList expects non-empty array"); + if (arr.length === 1) { + return [arr[0]]; + } else { + return [arr[0], toLinkedList(arr.slice(1))]; + } +} + +function toSingleton(x) { + return [x]; +} + +// Vec a 1 → a +function fromSingleton(a) { + return a[0]; +} + +function flattenShrink(shrinksLL) { + if (shrinksLL.length === 1) { + return shrinksLL[0].smap(toSingleton, fromSingleton); + } else { + var head = shrinksLL[0]; + var tail = shrinksLL[1]; + return shrinkPair(head, flattenShrink(tail)); + } +} + +/** + - `shrink.tuple(shrs: (shrink a, shrink b...)): shrink (a, b...)` +*/ +function shrinkTuple(shrinks) { + assert(shrinks.length > 0, "shrinkTuple needs > 0 values"); + var shrinksLL = toLinkedList(shrinks); + var shrink = flattenShrink(shrinksLL); + var result = shrinkBless(function (tuple) { + assert(tuple.length === shrinks.length, "shrinkTuple: not-matching params"); + var ll = toLinkedList(tuple); + return shrink(ll).map(fromLinkedList); + }); + + return utils.curried2(result, arguments); +} + +/** + - `shrink.sum(shrs: (shrink a, shrink b...)): shrink (a | b...)` +*/ +function shrinkSum(shrinks) { + assert(shrinks.length > 0, "shrinkTuple needs > 0 values"); + var result = shrinkBless(function (s) { + return s.fold(function (idx, len, value) { + assert(len === shrinks.length, "shrinkSum: not-matching params"); + return shrinks[idx](value).map(function (shrinked) { + return sum.addend(idx, len, shrinked); + }); + }); + }); + + return utils.curried2(result, arguments); +} + +function shrinkArrayWithMinimumSize(size) { + function shrinkArrayImpl(shrink) { + var result = shrinkBless(function (arr) { + assert(Array.isArray(arr), "shrinkArrayImpl() expects array, got: " + arr); + if (arr.length <= size) { + return lazyseq.nil; + } else { + var x = arr[0]; + var xs = arr.slice(1); + + return lazyseq.cons(xs, lazyseq.nil) + .append(shrink(x).map(function (xp) { return [xp].concat(xs); })) + .append(shrinkArrayImpl(shrink, xs).map(function (xsp) { return [x].concat(xsp); })); + } + }); + + return utils.curried2(result, arguments); + } + + return shrinkArrayImpl; +} + +/** + - `shrink.array(shr: shrink a): shrink (array a)` +*/ +var shrinkArray = shrinkArrayWithMinimumSize(0); + +/** + - `shrink.nearray(shr: shrink a): shrink (nearray a)` +*/ +var shrinkNEArray = shrinkArrayWithMinimumSize(1); + +module.exports = { + noop: shrinkNoop, + pair: shrinkPair, + either: shrinkEither, + tuple: shrinkTuple, + sum: shrinkSum, + array: shrinkArray, + nearray: shrinkNEArray, + bless: shrinkBless, +}; + +},{"./either.js":8,"./sum.js":26,"./utils.js":28,"assert":29,"lazy-seq":30}],23:[function(require,module,exports){ +"use strict"; + +var generator = require("./generator.js"); +var arbitraryBless = require("./arbitraryBless.js"); +var arbitraryAssert = require("./arbitraryAssert.js"); +var utils = require("./utils.js"); + +/** + ### Small arbitraries + + - `generator.small(gen: generator a): generator a` + - `small(arb: arbitrary a): arbitrary a` + + Create a generator (abitrary) which will generate smaller values, i.e. generator's `size` parameter is decreased logarithmically. + + ```js + jsc.property("small array of small natural numbers", "small (array nat)", function (arr) { + return Array.isArray(arr); + }); + + jsc.property("small array of normal natural numbers", "(small array) nat", function (arr) { + return Array.isArray(arr); + }); + ``` +*/ + +function smallGenerator(gen) { + // TODO: assertGenerator(gen) + return generator.bless(function (size) { + return gen(utils.ilog2(size)); + }); +} + +function smallArbitraryImpl(arb) { + arbitraryAssert(arb); + return arbitraryBless({ + generator: smallGenerator(arb.generator), + shrink: arb.shrink, + show: arb.show, + }); +} + +function smallArbitrary(arb) { + if (typeof arb === "function") { + return function () { + var resArb = arb.apply(arb, arguments); + return smallArbitraryImpl(resArb); + }; + } else { /* if (typeof arb === "object") */ + return smallArbitraryImpl(arb); + } +} + +module.exports = { + generator: smallGenerator, + arbitrary: smallArbitrary, +}; + +},{"./arbitraryAssert.js":3,"./arbitraryBless.js":4,"./generator.js":13,"./utils.js":28}],24:[function(require,module,exports){ +"use strict"; + +var array = require("./array.js"); +var primitive = require("./primitive.js"); +var utils = require("./utils.js"); + +/** + ### Arbitrary strings +*/ + +function fromCode(code) { + return String.fromCharCode(code); +} + +function toCode(c) { + return c.charCodeAt(0); +} + +/** + - `char: arbitrary char` — Single character +*/ +var char = primitive.nat(0xff).smap(fromCode, toCode); + +/** + - `asciichar: arbitrary char` — Single ascii character (0x20-0x7e inclusive, no DEL) +*/ +var asciichar = primitive.integer(0x20, 0x7e).smap(fromCode, toCode); + +/** + - `string: arbitrary string` +*/ +var string = array.array(char).smap(utils.charArrayToString, utils.stringToCharArray); + +/** + - `nestring: arbitrary string` — Generates strings which are not empty. +*/ +var nestring = array.nearray(char).smap(utils.charArrayToString, utils.stringToCharArray); + +/** + - `asciistring: arbitrary string` +*/ +var asciistring = array.array(asciichar).smap(utils.charArrayToString, utils.stringToCharArray); + +/** + - `asciinestring: arbitrary string` +*/ +var asciinestring = array.nearray(asciichar).smap(utils.charArrayToString, utils.stringToCharArray); + +module.exports = { + char: char, + asciichar: asciichar, + string: string, + nestring: nestring, + asciistring: asciistring, + asciinestring: asciinestring, +}; + +},{"./array.js":5,"./primitive.js":17,"./utils.js":28}],25:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +var environment = require("./environment.js"); +var typify = require("./typify.js"); +var utils = require("./utils.js"); +var generator = require("./generator.js"); +var shrink = require("./shrink.js"); +var arbitraryBless = require("./arbitraryBless.js"); + +/** + ### Restricting arbitraries + + - `suchthat(arb: arbitrary a, userenv: env?, p : a -> bool): arbitrary a` + Arbitrary of values that satisfy `p` predicate. It's advised that `p`'s accept rate is high. +*/ +function suchthat(arb, userenv, predicate) { + var env; + if (arguments.length === 2) { + predicate = userenv; + env = environment; + } else { + env = utils.merge(environment, userenv); + } + + arb = typeof arb === "string" ? typify.parseTypify(env, arb) : arb; + arb = utils.force(arb); + + return arbitraryBless({ + generator: generator.bless(function (size) { + for (var i = 0; ; i++) { + // if 5 tries failed, increase size + if (i > 5) { + i = 0; + size += 1; + } + + var x = arb.generator(size); + if (predicate(x)) { + return x; + } + } + }), + + shrink: shrink.bless(function (x) { + return arb.shrink(x).filter(predicate); + }), + + show: arb.show, + }); +} + +module.exports = { + suchthat: suchthat, +}; + +},{"./arbitraryBless.js":4,"./environment.js":9,"./generator.js":13,"./shrink.js":22,"./typify.js":27,"./utils.js":28}],26:[function(require,module,exports){ +"use strict"; + +var assert = require("assert"); + +/** + ### sum (n-ary either) + + See: [Wikipedia](https://en.wikipedia.org/wiki/Tagged_union) +*/ + +function Addend(idx, len, value) { + assert(len > 0, "Addend: 0 < len"); // empty sum is void - cannot create such + assert(idx >= 0 && idx < len, "Addend: 0 <= idx < len"); + this.idx = idx; + this.len = len; + this.value = value; +} + +/** + - `sum.addend(idx: nat, n: nat, value: a): sum (... a ...)` +*/ +function addend(idx, len, value) { + return new Addend(idx, len, value); +} + +/** + - `.fold(f: (idx: nat, n: nat, value: a) -> b): b` +*/ +Addend.prototype.fold = function (f) { + return f(this.idx, this.len, this.value); +}; + +module.exports = { + addend: addend, +}; + +},{"assert":29}],27:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +/** + ### DSL for input parameters + + There is a small DSL to help with `forall`. For example the two definitions below are equivalent: + ```js + var bool_fn_applied_thrice = jsc.forall("bool -> bool", "bool", check); + var bool_fn_applied_thrice = jsc.forall(jsc.fn(jsc.bool), jsc.bool, check); + ``` + + The DSL is based on a subset of language recognized by [typify-parser](https://github.com/phadej/typify-parser): + - *identifiers* are fetched from the predefined environment. + - *applications* are applied as one could expect: `"array bool"` is evaluated to `jsc.array(jsc.bool)`. + - *functions* are supported: `"bool -> bool"` is evaluated to `jsc.fn(jsc.bool)`. + - *square brackets* are treated as a shorthand for the array type: `"[nat]"` is evaluated to `jsc.array(jsc.nat)`. + - *union*: `"bool | nat"` is evaluated to `jsc.sum([jsc.bool, jsc.nat])`. + - **Note** `oneof` cannot be shrunk, because the union is untagged, we don't know which shrink to use. + - *conjunction*: `"bool & nat"` is evaluated to `jsc.tuple(jsc.bool, jsc.nat)`. + - *anonymous records*: `"{ b: bool; n: nat }"` is evaluated to `jsc.record({ b: jsc.bool, n: jsc.nat })`. + - *EXPERIMENTAL: recursive types*: `"rec list -> unit | (nat & list)"`. +*/ + +var arbitrary = require("./arbitrary.js"); +var assert = require("assert"); +var record = require("./record.js"); +var array = require("./array.js"); +var fn = require("./fn.js"); +var typifyParser = require("typify-parser"); +var utils = require("./utils.js"); + +// Forward declarations +var compileType; +var compileTypeArray; + +function compileIdent(env, type) { + var g = env[type.value]; + if (!g) { + throw new Error("Unknown arbitrary: " + type.value); + } + return g; +} + +function compileApplication(env, type) { + var callee = compileType(env, type.callee); + var args = compileTypeArray(env, type.args); + + return callee.apply(undefined, args); +} + +function compileFunction(env, type) { + // we don't care about argument type + var result = compileType(env, type.result); + return fn.fn(result); +} + +function compileBrackets(env, type) { + var arg = compileType(env, type.arg); + return array.array(arg); +} + +function compileDisjunction(env, type) { + var args = compileTypeArray(env, type.args); + return arbitrary.sum(args); +} + +function compileConjunction(env, type) { + var args = compileTypeArray(env, type.args); + return arbitrary.tuple(args); +} + +function compileRecord(env, type) { + // TODO: use mapValues + var spec = {}; + Object.keys(type.fields).forEach(function (key) { + spec[key] = compileType(env, type.fields[key]); + }); + return record.arbitrary(spec); +} + +function compileRecursive(env, type) { + assert(type.arg.type === "disjunction", "recursive type's argument should be disjunction"); + + // bound variable + var name = type.name; + + var par = utils.partition(type.arg.args, function (t) { + return typifyParser.freeVars(t).indexOf(name) === -1; + }); + + var terminal = par[0]; + + if (terminal.length === 0) { + throw new Error("Recursive type without non-recursive branch"); + } + + var terminalArb = compileType(env, { + type: "disjunction", + args: terminal, + }); + + return arbitrary.recursive(terminalArb, function (arb) { + var arbEnv = {}; + arbEnv[name] = arb; + var newEnv = utils.merge(env, arbEnv); + return compileType(newEnv, type.arg); + }); +} + +compileType = function compileTypeFn(env, type) { + switch (type.type) { + case "ident": return compileIdent(env, type); + case "application": return compileApplication(env, type); + case "function": return compileFunction(env, type); + case "brackets": return compileBrackets(env, type); + case "disjunction": return compileDisjunction(env, type); + case "conjunction": return compileConjunction(env, type); + case "record": return compileRecord(env, type); + case "number": return type.value; + case "recursive": return compileRecursive(env, type); + default: throw new Error("Unsupported typify ast type: " + type.type); + } +}; + +compileTypeArray = function compileTypeArrayFn(env, types) { + return types.map(function (type) { + return compileType(env, type); + }); +}; + +function parseTypify(env, str) { + var type = typifyParser(str); + return compileType(env, type); +} + +module.exports = { + parseTypify: parseTypify, +}; + +},{"./arbitrary.js":2,"./array.js":5,"./fn.js":11,"./record.js":19,"./utils.js":28,"assert":29,"typify-parser":33}],28:[function(require,module,exports){ +/* @flow weak */ +"use strict"; + +var isArray = Array.isArray; +function isObject(o) { + /* eslint-disable no-new-object */ + return new Object(o) === o; + /* eslint-enable no-new-object */ +} + +/* undefined-safe isNaN */ +function isNaN(n) { + return typeof n === "number" && n !== n; +} + +/** + ### Utility functions + + Utility functions are exposed (and documented) only to make contributions to jsverify more easy. + The changes here don't follow semver, i.e. there might be backward-incompatible changes even in patch releases. + + Use [underscore.js](http://underscorejs.org/), [lodash](https://lodash.com/), [ramda](http://ramda.github.io/ramdocs/docs/), [lazy.js](http://danieltao.com/lazy.js/) or some other utility belt. +*/ + +/* Simple sort */ +function sort(arr) { + var res = arr.slice(); + res.sort(); + return res; +} + +/** + - `utils.isEqual(x: json, y: json): bool` + + Equality test for `json` objects. +*/ +function isEqual(a, b) { + var i; + + if (isNaN(a) && isNaN(b)) { + return true; + } + + if (a === b) { + return true; + } else if (isArray(a) && isArray(b) && a.length === b.length) { + for (i = 0; i < a.length; i++) { + if (!isEqual(a[i], b[i])) { + return false; + } + } + return true; + } else if (isObject(a) && isObject(b) && !isArray(a) && !isArray(b)) { + var akeys = Object.keys(a); + var bkeys = Object.keys(b); + if (!isEqual(sort(akeys), sort(bkeys))) { + return false; + } + + for (i = 0; i < akeys.length; i++) { + if (!isEqual(a[akeys[i]], b[akeys[i]])) { + return false; + } + } + return true; + } + + return false; +} + +/** + - `utils.isApproxEqual(x: a, y: b, opts: obj): bool` + + Tests whether two objects are approximately and optimistically equal. + Returns `false` only if they are distinguishable not equal. + Returns `true` when `x` and `y` are `NaN`. + This function works with cyclic data. + + Takes optional 'opts' parameter with properties: + + - `fnEqual` - whether all functions are considered equal (default: yes) + - `depth` - how deep to recurse until treating as equal (default: 5) +*/ +function isApproxEqual(x, y, opts) { + opts = opts || {}; + var fnEqual = opts.fnEqual !== false; + var depth = opts.depth || 5; // totally arbitrary + + // state contains pairs we checked (or are still checking, but assume equal!) + var state = []; + + function loop(a, b, n) { + if (isNaN(a) && isNaN(b)) { + return true; + } + + // trivial check + if (a === b) { + return true; + } + + // depth check + if (n >= depth) { + return true; + } + + var i; + + // check if pair already occured + for (i = 0; i < state.length; i++) { + if (state[i][0] === a && state[i][1] === b) { + return true; + } + } + + // add to state + state.push([a, b]); + + if (typeof a === "function" && typeof b === "function") { + return fnEqual; + } + + if (isArray(a) && isArray(b) && a.length === b.length) { + for (i = 0; i < a.length; i++) { + if (!loop(a[i], b[i], n + 1)) { + return false; + } + } + return true; + } else if (isObject(a) && isObject(b) && !isArray(a) && !isArray(b)) { + var akeys = Object.keys(a); + var bkeys = Object.keys(b); + if (!loop(sort(akeys), sort(bkeys), n + 1)) { + return false; + } + + for (i = 0; i < akeys.length; i++) { + if (!loop(a[akeys[i]], b[akeys[i]], n + 1)) { + return false; + } + } + return true; + } + + return false; + } + return loop(x, y, 0); +} + +function identity(x) { + return x; +} + +function pluck(arr, key) { + return arr.map(function (e) { + return e[key]; + }); +} + +/** + - `utils.force(x: a | () -> a) : a` + + Evaluate `x` as nullary function, if it is one. +*/ +function force(arb) { + return (typeof arb === "function") ? arb() : arb; +} + +/** + - `utils.merge(x... : obj): obj` + + Merge two objects, a bit like `_.extend({}, x, y)`. +*/ +function merge() { + var res = {}; + + for (var i = 0; i < arguments.length; i++) { + var arg = arguments[i]; + var keys = Object.keys(arg); + for (var j = 0; j < keys.length; j++) { + var key = keys[j]; + res[key] = arg[key]; + } + } + + return res; +} + +function div2(x) { + return Math.floor(x / 2); +} + +function log2(x) { + return Math.log(x) / Math.log(2); +} + +function ilog2(x) { + return x <= 0 ? 0 : Math.floor(log2(x)); +} + +function curriedN(n) { + var n1 = n - 1; + return function curriedNInstance(result, args) { + if (args.length === n) { + return result(args[n1]); + } else { + return result; + } + }; +} + +var curried2 = curriedN(2); +var curried3 = curriedN(3); + +function charArrayToString(arr) { + return arr.join(""); +} + +function stringToCharArray(str) { + return str.split(""); +} + +function pairArrayToDict(arrayOfPairs) { + var res = {}; + arrayOfPairs.forEach(function (p) { + res[p[0]] = p[1]; + }); + return res; +} + +function dictToPairArray(m) { + var res = []; + Object.keys(m).forEach(function (k) { + res.push([k, m[k]]); + }); + return res; +} + +function partition(arr, pred) { + var truthy = []; + var falsy = []; + + for (var i = 0; i < arr.length; i++) { + var x = arr[i]; + if (pred(x)) { + truthy.push(x); + } else { + falsy.push(x); + } + } + + return [truthy, falsy]; +} + +module.exports = { + isArray: isArray, + isObject: isObject, + isEqual: isEqual, + isApproxEqual: isApproxEqual, + identity: identity, + pluck: pluck, + force: force, + merge: merge, + div2: div2, + ilog2: ilog2, + curried2: curried2, + curried3: curried3, + charArrayToString: charArrayToString, + stringToCharArray: stringToCharArray, + pairArrayToDict: pairArrayToDict, + dictToPairArray: dictToPairArray, + partition: partition, +}; + +},{}],29:[function(require,module,exports){ +'use strict'; + +// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js +// original notice: + +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +function compare(a, b) { + if (a === b) { + return 0; + } + + var x = a.length; + var y = b.length; + + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i]; + y = b[i]; + break; + } + } + + if (x < y) { + return -1; + } + if (y < x) { + return 1; + } + return 0; +} +function isBuffer(b) { + if (global.Buffer && typeof global.Buffer.isBuffer === 'function') { + return global.Buffer.isBuffer(b); + } + return !!(b != null && b._isBuffer); +} + +// based on node assert, original notice: + +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Originally from narwhal.js (http://narwhaljs.org) +// Copyright (c) 2009 Thomas Robinson <280north.com> +// +// 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 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. + +var util = require('util/'); +var hasOwn = Object.prototype.hasOwnProperty; +var pSlice = Array.prototype.slice; +var functionsHaveNames = (function () { + return function foo() {}.name === 'foo'; +}()); +function pToString (obj) { + return Object.prototype.toString.call(obj); +} +function isView(arrbuf) { + if (isBuffer(arrbuf)) { + return false; + } + if (typeof global.ArrayBuffer !== 'function') { + return false; + } + if (typeof ArrayBuffer.isView === 'function') { + return ArrayBuffer.isView(arrbuf); + } + if (!arrbuf) { + return false; + } + if (arrbuf instanceof DataView) { + return true; + } + if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) { + return true; + } + return false; +} +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = module.exports = ok; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) + +var regex = /\s*function\s+([^\(\s]*)\s*/; +// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js +function getName(func) { + if (!util.isFunction(func)) { + return; + } + if (functionsHaveNames) { + return func.name; + } + var str = func.toString(); + var match = str.match(regex); + return match && match[1]; +} +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } else { + // non v8 browsers so we can have a stacktrace + var err = new Error(); + if (err.stack) { + var out = err.stack; + + // try to strip useless frames + var fn_name = getName(stackStartFunction); + var idx = out.indexOf('\n' + fn_name); + if (idx >= 0) { + // once we have located the function frame + // we need to strip out everything before it (and its line) + var next_line = out.indexOf('\n', idx + 1); + out = out.substring(next_line + 1); + } + + this.stack = out; + } + } +}; + +// assert.AssertionError instanceof Error +util.inherits(assert.AssertionError, Error); + +function truncate(s, n) { + if (typeof s === 'string') { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } +} +function inspect(something) { + if (functionsHaveNames || !util.isFunction(something)) { + return util.inspect(something); + } + var rawname = getName(something); + var name = rawname ? ': ' + rawname : ''; + return '[Function' + name + ']'; +} +function getMessage(self) { + return truncate(inspect(self.actual), 128) + ' ' + + self.operator + ' ' + + truncate(inspect(self.expected), 128); +} + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); +} +assert.ok = ok; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected, false)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } +}; + +assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { + if (!_deepEqual(actual, expected, true)) { + fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual); + } +}; + +function _deepEqual(actual, expected, strict, memos) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + } else if (isBuffer(actual) && isBuffer(expected)) { + return compare(actual, expected) === 0; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); + + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; + + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if ((actual === null || typeof actual !== 'object') && + (expected === null || typeof expected !== 'object')) { + return strict ? actual === expected : actual == expected; + + // If both values are instances of typed arrays, wrap their underlying + // ArrayBuffers in a Buffer each to increase performance + // This optimization requires the arrays to have the same type as checked by + // Object.prototype.toString (aka pToString). Never perform binary + // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their + // bit patterns are not identical. + } else if (isView(actual) && isView(expected) && + pToString(actual) === pToString(expected) && + !(actual instanceof Float32Array || + actual instanceof Float64Array)) { + return compare(new Uint8Array(actual.buffer), + new Uint8Array(expected.buffer)) === 0; + + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else if (isBuffer(actual) !== isBuffer(expected)) { + return false; + } else { + memos = memos || {actual: [], expected: []}; + + var actualIndex = memos.actual.indexOf(actual); + if (actualIndex !== -1) { + if (actualIndex === memos.expected.indexOf(expected)) { + return true; + } + } + + memos.actual.push(actual); + memos.expected.push(expected); + + return objEquiv(actual, expected, strict, memos); + } +} + +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv(a, b, strict, actualVisitedObjects) { + if (a === null || a === undefined || b === null || b === undefined) + return false; + // if one is a primitive, the other must be same + if (util.isPrimitive(a) || util.isPrimitive(b)) + return a === b; + if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) + return false; + var aIsArgs = isArguments(a); + var bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) + return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b, strict); + } + var ka = objectKeys(a); + var kb = objectKeys(b); + var key, i; + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length !== kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] !== kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) + return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected, false)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +}; + +assert.notDeepStrictEqual = notDeepStrictEqual; +function notDeepStrictEqual(actual, expected, message) { + if (_deepEqual(actual, expected, true)) { + fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual); + } +} + + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } +}; + +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } + + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } + + try { + if (actual instanceof expected) { + return true; + } + } catch (e) { + // Ignore. The instanceof check doesn't work for arrow functions. + } + + if (Error.isPrototypeOf(expected)) { + return false; + } + + return expected.call({}, actual) === true; +} + +function _tryBlock(block) { + var error; + try { + block(); + } catch (e) { + error = e; + } + return error; +} + +function _throws(shouldThrow, block, expected, message) { + var actual; + + if (typeof block !== 'function') { + throw new TypeError('"block" argument must be a function'); + } + + if (typeof expected === 'string') { + message = expected; + expected = null; + } + + actual = _tryBlock(block); + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); + } + + var userProvidedMessage = typeof message === 'string'; + var isUnwantedException = !shouldThrow && util.isError(actual); + var isUnexpectedException = !shouldThrow && actual && !expected; + + if ((isUnwantedException && + userProvidedMessage && + expectedException(actual, expected)) || + isUnexpectedException) { + fail(actual, expected, 'Got unwanted exception' + message); + } + + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } +} + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws(true, block, error, message); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { + _throws(false, block, error, message); +}; + +assert.ifError = function(err) { if (err) throw err; }; + +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + if (hasOwn.call(obj, key)) keys.push(key); + } + return keys; +}; + +},{"util/":36}],30:[function(require,module,exports){ +/** + # lazy-seq + + > Lazy sequences + + [![Build Status](https://secure.travis-ci.org/phadej/lazy-seq.svg?branch=master)](http://travis-ci.org/phadej/lazy-seq) + [![NPM version](https://badge.fury.io/js/lazy-seq.svg)](http://badge.fury.io/js/lazy-seq) + [![Dependency Status](https://david-dm.org/phadej/lazy-seq.svg)](https://david-dm.org/phadej/lazy-seq) + [![devDependency Status](https://david-dm.org/phadej/lazy-seq/dev-status.svg)](https://david-dm.org/phadej/lazy-seq#info=devDependencies) + [![Code Climate](https://img.shields.io/codeclimate/github/phadej/lazy-seq.svg)](https://codeclimate.com/github/phadej/lazy-seq) + + ## Lazy? + + The list structure could be defined as + + ```hs + data Seq a = Nil | Cons a (Seq a) + ``` + + The `Cons` constuctor takes two arguments, so there are four different laziness variants: + + ```hs + Cons (Strict a) (Strict (Seq a)) -- 1. fully strict + Cons (Lazy a) (Strict (Seq a)) -- 2. lazy values + Cons (Strict a) (Lazy (Seq a)) -- 3. lazy structure + Cons (Lazy a) (Lazy (Seq a)) -- 4. fully lazy + ``` + + This module implements the third variant: lazy structure, but strict values. + + ## Example + + ```js + var ones = lazyseq.cons(1, function () { return ones; }); + console.log(ones === ones.tail()); // true! + ``` + + ## Why? + + This package is originally made to optimise shrink operations in [jsverify](http://jsverify.github.io/), a property-based testing library. + + ## API +*/ + +"use strict"; + +var assert = require("assert"); + +/** + - *nil : Seq a* — Empty sequence. + + - *cons : (head : a, tail : Array a | Seq a | () → Array a | () → Seq a) → Seq a* : Cons a value to the front of a sequence (list or thunk). +*/ +var nil = {}; + +/** + - *.isNil : Boolean* — Constant time check, whether the sequence is empty. +*/ +nil.isNil = true; + +/** + - *.toString : () → String* — String representation. Doesn't force the tail. +*/ +nil.toString = function () { + return "nil"; +}; + +/** + - *.length : () → Nat* — Return the length of the sequene. Forces the structure. +*/ +nil.length = function () { + return 0; +}; + +/** + - *.toArray : () → Array a* — Convert the sequence to JavaScript array. +*/ +nil.toArray = function nilToArray() { + return []; +}; + +/** + - *.fold : (z : b, f : (a, () → b) → b) → b* — Fold from right. + + ```hs + fold nil x f = x + fold (cons h t) x f = f x (fold t x f) + ``` +*/ +nil.fold = function nilFold(x /*, f */) { + return x; +}; + +/** + - *.head : () → a* — Extract the first element of a sequence, which must be non-empty. +*/ +nil.head = function nilHead() { + throw new Error("nil.head"); +}; + +/** + - *.tail : () → Seq a* — Return the tail of the sequence. + + ```hs + tail nil = nil + tail (cons h t) = t + ``` +*/ +nil.tail = function nilTail() { + return nil; +}; + +/** + - *.nth : (n : Nat) → a* — Return nth value of the sequence. +*/ +nil.nth = function nilNth(n) { + assert(typeof n === "number"); + throw new Error("Can't get " + n + "th value of the nil"); +}; + +/** + - *.take : (n : Nat) → Seq a* — Take `n` first elements of the sequence. +*/ +nil.take = function (n) { + assert(typeof n === "number"); + return nil; +}; + +/** + - *.drop : (n : Nat) → Seq a* — Drop `n` first elements of the sequence. +*/ +nil.drop = function (n) { + assert(typeof n === "number"); + return nil; +}; + +/** + - *.map : (f : a → b) : Seq b* — The sequence obtained by applying `f` to each element of the original sequence. +*/ +nil.map = function (f) { + assert(typeof f === "function"); + return nil; +}; + +/** + - *.append : (ys : Seq a | Array a) : Seq a* — Append `ys` sequence. +*/ +nil.append = function (seq) { + if (typeof seq === "function") { + seq = seq(); + } + + if (Array.isArray(seq)) { + /* eslint-disable no-use-before-define */ + return fromArray(seq); + /* eslint-enable no-use-before-define */ + } else { + return seq; + } +}; + +/** + - *.filter : (p : a -> bool) : Seq a* — filter using `p` predicate. +*/ +nil.filter = function () { + return nil; +}; + +/** + - *.every : (p = identity: a -> b) : b | true — return first falsy value in the sequence, true otherwise. *N.B.* behaves slightly differently from `Array::every`. +*/ +nil.every = function () { + return true; +}; + +/** + - *.some : (p = identity: a -> b) : b | false — return first truthy value in the sequence, false otherwise. *N.B.* behaves slightly differently from `Array::some`. +*/ +nil.some = function () { + return false; +}; + +/** + - *.contains : (x : a) : bool — Returns `true` if `x` is in the sequence. +*/ +nil.contains = function () { + return false; +}; + +/** + - *.containsNot : (x : a) : bool — Returns `true` if `x` is not in the sequence. +*/ +nil.containsNot = function () { + return true; +}; + +// Default cons values are with strict semantics +function Cons(head, tail) { + this.headValue = head; + this.tailValue = tail; +} + +Cons.prototype.isNil = false; + +Cons.prototype.toString = function () { + return "Cons(" + this.headValue + ", " + this.tailValue + ")"; +}; + +Cons.prototype.length = function () { + return 1 + this.tail().length(); +}; + +Cons.prototype.toArray = function () { + var ptr = this; + var acc = []; + while (ptr !== nil) { + acc.push(ptr.headValue); + ptr = ptr.tail(); + } + return acc; +}; + +Cons.prototype.fold = function consFold(x, f) { + var self = this; + return f(this.headValue, function () { + return self.tail().fold(x, f); + }); +}; + +Cons.prototype.head = function consHead() { + return this.headValue; +}; + +Cons.prototype.tail = function consTail() { + return this.tailValue; +}; + +// But when cons is created, it's overloaded with lazy ones + +// Force tail to whnf. +function lazyConsForce() { + /* jshint validthis:true */ + var val = this.tailFn(); + /* eslint-disable no-use-before-define */ + this.tailValue = Array.isArray(val) ? fromArray(val) : val; + /* eslint-enable no-use-before-define */ + + delete this.tail; + delete this.force; + + return this; +} + +function lazyConsTail() { + /* jshint validthis:true */ + this.force(); + return this.tailValue; +} + +function delay(head, tail) { + assert(typeof tail === "function"); + + head.tailFn = tail; + head.tail = lazyConsTail; + + head.force = lazyConsForce; + return head; +} + +function cons(head, tail) { + if (typeof tail === "function") { + return delay(new Cons(head), tail); + } else if (Array.isArray(tail)) { + return delay(cons(head), function () { + /* eslint-disable no-use-before-define */ + return fromArray(tail); + /* eslint-enable no-use-before-define */ + }); + } else { + return new Cons(head, tail); + } +} + +// Rest of the functions. They might use cons + +Cons.prototype.nth = function consNth(n) { + assert(typeof n === "number"); + return n === 0 ? this.headValue : this.tail().nth(n - 1); +}; + +Cons.prototype.take = function consTake(n) { + assert(typeof n === "number"); + var that = this; + return n === 0 ? nil : cons(this.headValue, function () { + return that.tail().take(n - 1); + }); +}; + +Cons.prototype.drop = function consDrop(n) { + assert(typeof n === "number"); + return n === 0 ? this : this.tail().drop(n - 1); +}; + +Cons.prototype.map = function consMap(f) { + assert(typeof f === "function"); + var that = this; + return cons(f(that.headValue), function () { + return that.tail().map(f); + }); +}; + +Cons.prototype.append = function consAppend(seq) { + // Short circuit decidable: (++ []) ≡ id + if (seq === nil || (Array.isArray(seq) && seq.length === 0)) { + return this; + } + var that = this; + return cons(that.headValue, function () { + return that.tail().append(seq); + }); +}; + +Cons.prototype.filter = function consFilter(p) { + assert(typeof p === "function"); + var that = this; + if (p(that.headValue)) { + return cons(that.headValue, function () { + return that.tail().filter(p); + }); + } else { + return that.tail().filter(p); + } +}; + +Cons.prototype.every = function consEvery(p) { + p = p || function (x) { return x; }; + assert(typeof p === "function"); + var that = this; + var pHead = p(that.headValue); + if (!pHead) { + return pHead; + } else { + return that.tail().every(p); + } +}; + +Cons.prototype.some = function consSome(p) { + p = p || function (x) { return x; }; + assert(typeof p === "function"); + var that = this; + var pHead = p(that.headValue); + if (pHead) { + return pHead; + } else { + return that.tail().some(p); + } +}; + +Cons.prototype.contains = function consContains(x) { + var that = this; + if (x === that.headValue) { + return true; + } else { + return that.tail().contains(x); + } +}; + +Cons.prototype.containsNot = function consContainsNot(x) { + var that = this; + if (x === that.headValue) { + return false; + } else { + return that.tail().containsNot(x); + } +}; + +// Constructors +/** + - *fromArray: (arr : Array a) → Seq a* — Convert a JavaScript array into lazy sequence. +*/ +function fromArrayIter(arr, n) { + if (n < arr.length) { + return cons(arr[n], function () { + return fromArrayIter(arr, n + 1); + }); + } else { + return nil; + } +} + +function fromArray(arr) { + assert(Array.isArray(arr)); + return fromArrayIter(arr, 0); +} + +/** + - *singleton: (x : a) → Seq a* — Create a singleton sequence. +*/ +function singleton(x) { + return fromArray([x]); +} + +/** + - *append : (xs... : Array a | Seq a | () → Array a | () → Seq a) → Seq a* : Append one sequence-like to another. +*/ +function append() { + var acc = nil; + for (var i = 0; i < arguments.length; i++) { + acc = acc.append(arguments[i]); + } + return acc; +} + +/** + - *iterate : (x : a, f : a → a) → Seq a* — Create an infinite sequence of repeated applications of `f` to `x`: *x, f(x), f(f(x))…*. +*/ +function iterate(x, f) { + return cons(x, function () { + return iterate(f(x), f); + }); +} + +/** + - *fold : (seq : Seq a | Array a, z : b, f : (a, () → b) → b) : b* — polymorphic version of fold. Works with arrays too. +*/ +function listFold(list, z, f, n) { + if (n < list.length) { + return f(list[n], function () { + return listFold(list, z, f, n + 1); + }); + } else { + return z; + } +} + +function fold(list, z, f) { + if (Array.isArray(list)) { + return listFold(list, z, f, 0); + } else { + return list.fold(z, f); + } +} + +module.exports = { + nil: nil, + cons: cons, + append: append, + fromArray: fromArray, + singleton: singleton, + iterate: iterate, + fold: fold, +}; + +/// plain CHANGELOG.md +/// plain CONTRIBUTING.md + +},{"assert":29}],31:[function(require,module,exports){ +"use strict"; + +// Based on RC4 algorithm, as described in +// http://en.wikipedia.org/wiki/RC4 + +function isInteger(n) { + return parseInt(n, 10) === n; +} + +function createRC4(N) { + function identityPermutation() { + var s = new Array(N); + for (var i = 0; i < N; i++) { + s[i] = i; + } + return s; + } + + // :: string | array integer -> array integer + function seed(key) { + if (key === undefined) { + key = new Array(N); + for (var k = 0; k < N; k++) { + key[k] = Math.floor(Math.random() * N); + } + } else if (typeof key === "string") { + // to string + key = "" + key; + key = key.split("").map(function (c) { return c.charCodeAt(0) % N; }); + } else if (Array.isArray(key)) { + if (!key.every(function (v) { + return typeof v === "number" && v === (v | 0); + })) { + throw new TypeError("invalid seed key specified: not array of integers"); + } + } else { + throw new TypeError("invalid seed key specified"); + } + + var keylen = key.length; + + // resed state + var s = identityPermutation(); + + var j = 0; + for (var i = 0; i < N; i++) { + j = (j + s[i] + key[i % keylen]) % N; + var tmp = s[i]; + s[i] = s[j]; + s[j] = tmp; + } + + return s; + } + + /* eslint-disable no-shadow */ + function RC4(key) { + this.s = seed(key); + this.i = 0; + this.j = 0; + } + /* eslint-enable no-shadow */ + + RC4.prototype.randomNative = function () { + this.i = (this.i + 1) % N; + this.j = (this.j + this.s[this.i]) % N; + + var tmp = this.s[this.i]; + this.s[this.i] = this.s[this.j]; + this.s[this.j] = tmp; + + var k = this.s[(this.s[this.i] + this.s[this.j]) % N]; + + return k; + }; + + RC4.prototype.randomUInt32 = function () { + var a = this.randomByte(); + var b = this.randomByte(); + var c = this.randomByte(); + var d = this.randomByte(); + + return ((a * 256 + b) * 256 + c) * 256 + d; + }; + + RC4.prototype.randomFloat = function () { + return this.randomUInt32() / 0x100000000; + }; + + RC4.prototype.random = function () { + var a; + var b; + + if (arguments.length === 1) { + a = 0; + b = arguments[0]; + } else if (arguments.length === 2) { + a = arguments[0]; + b = arguments[1]; + } else { + throw new TypeError("random takes one or two integer arguments"); + } + + if (!isInteger(a) || !isInteger(b)) { + throw new TypeError("random takes one or two integer arguments"); + } + + return a + this.randomUInt32() % (b - a + 1); + }; + + RC4.prototype.currentState = function () { + return { + i: this.i, + j: this.j, + s: this.s.slice(), // copy + }; + }; + + RC4.prototype.setState = function (state) { + var s = state.s; + var i = state.i; + var j = state.j; + + /* eslint-disable yoda */ + if (!(i === (i | 0) && 0 <= i && i < N)) { + throw new Error("state.i should be integer [0, " + (N - 1) + "]"); + } + + if (!(j === (j | 0) && 0 <= j && j < N)) { + throw new Error("state.j should be integer [0, " + (N - 1) + "]"); + } + /* eslint-enable yoda */ + + // check length + if (!Array.isArray(s) || s.length !== N) { + throw new Error("state should be array of length " + N); + } + + // check that all params are there + for (var k = 0; k < N; k++) { + if (s.indexOf(k) === -1) { + throw new Error("state should be permutation of 0.." + (N - 1) + ": " + k + " is missing"); + } + } + + this.i = i; + this.j = j; + this.s = s.slice(); // assign copy + }; + + return RC4; +} + +var RC4 = createRC4(256); +RC4.prototype.randomByte = RC4.prototype.randomNative; + +var RC4small = createRC4(16); +RC4small.prototype.randomByte = function () { + var a = this.randomNative(); + var b = this.randomNative(); + + return a * 16 + b; +}; + +var ordA = "a".charCodeAt(0); +var ord0 = "0".charCodeAt(0); + +function toHex(n) { + return n < 10 ? String.fromCharCode(ord0 + n) : String.fromCharCode(ordA + n - 10); +} + +function fromHex(c) { + return parseInt(c, 16); +} + +RC4small.prototype.currentStateString = function () { + var state = this.currentState(); + + var i = toHex(state.i); + var j = toHex(state.j); + + var res = i + j + state.s.map(toHex).join(""); + return res; +}; + +RC4small.prototype.setStateString = function (stateString) { + if (!stateString.match(/^[0-9a-f]{18}$/)) { + throw new TypeError("RC4small stateString should be 18 hex character string"); + } + + var i = fromHex(stateString[0]); + var j = fromHex(stateString[1]); + var s = stateString.split("").slice(2).map(fromHex); + + this.setState({ + i: i, + j: j, + s: s, + }); +}; + +RC4.RC4small = RC4small; + +module.exports = RC4; + +},{}],32:[function(require,module,exports){ +"use strict"; + +/** + +# trampa + +Trampolines, to emulate tail-call recursion. + +[![Build Status](https://secure.travis-ci.org/phadej/trampa.svg?branch=master)](http://travis-ci.org/phadej/trampa) +[![NPM version](https://badge.fury.io/js/trampa.svg)](http://badge.fury.io/js/trampa) +[![Dependency Status](https://david-dm.org/trampa/trampa.svg)](https://david-dm.org/trampa/trampa) +[![devDependency Status](https://david-dm.org/trampa/trampa/dev-status.svg)](https://david-dm.org/trampa/trampa#info=devDependencies) +[![Code Climate](https://img.shields.io/codeclimate/github/phadej/trampa.svg)](https://codeclimate.com/github/phadej/trampa) + +## Synopsis + +```js +var trampa = require("trampa"); + +function loop(n, acc) { + return n === 0 ? trampa.wrap(acc) : trampa.lazy(function () { + return loop(n - 1, acc + 1); + }); +} + +loop(123456789, 0).run(); // doesn't cause stack overflow! +``` + +## API + +*/ + +// loosely based on https://apocalisp.wordpress.com/2011/10/26/tail-call-elimination-in-scala-monads/ + +var assert = require("assert"); + +function Done(x) { + this.x = x; +} + +function Cont(tramp, cont) { + assert(typeof cont === "function"); + this.tramp = tramp; + this.cont = cont; +} + +/** +- `isTrampoline(t: obj): bool` — Returns, whether `t` is a trampolined object. +*/ +function isTrampoline(t) { + return t instanceof Done || t instanceof Cont; +} + +/** +- `wrap(t: Trampoline a | a): Trampoline a` — Wrap `t` into trampoline, if it's not already one. +*/ +function wrap(t) { + return isTrampoline(t) ? t : new Done(t); +} + +/** +- `lazy(t : () -> Trampoline a | a)` — Wrap lazy computation into trampoline. Useful when constructing computations. +*/ +function lazy(computation) { + assert(typeof computation === "function", "lazy: computation should be function"); + return wrap().jump(computation); +} + +/** +- `Trampoline.jump(f : a -> b | Trampoline b)` — *map* or *flatmap* trampoline computation. Like `.then` for promises. +*/ +Done.prototype.jump = function (f) { + return new Cont(this, function (x) { + return wrap(f(x)); + }); +}; + +Cont.prototype.jump = Done.prototype.jump; + +function execute(curr, params) { + params = params || {}; + var debug = params.debug || false; + var log = params.log || console.log; + var stack = []; + + while (true) { // eslint-disable-line no-constant-condition + if (debug) { + log("trampoline execute: stack size " + stack.length); + } + + if (curr instanceof Done) { + if (stack.length === 0) { + return curr.x; + } else { + curr = stack[stack.length - 1](curr.x); + stack.pop(); + } + } else { + assert(curr instanceof Cont); + stack.push(curr.cont); + curr = curr.tramp; + } + } +} + +/** +- `Trampoline.run(): a` — Run the trampoline synchronously resulting a value. +*/ +Done.prototype.run = Cont.prototype.run = function (params) { + return execute(this, params); +}; + +module.exports = { + isTrampoline: isTrampoline, + wrap: wrap, + lazy: lazy, +}; + +/** +## Changelog + +- **1.0.0** — *2015-07-14* — Initial release +*/ + +},{"assert":29}],33:[function(require,module,exports){ +/** + # typify type parser + + > Type signature parser for typify + + [![Build Status](https://secure.travis-ci.org/phadej/typify-parser.svg?branch=master)](http://travis-ci.org/phadej/typify-parser) + [![NPM version](https://badge.fury.io/js/typify-parser.svg)](http://badge.fury.io/js/typify-parser) + [![Dependency Status](https://david-dm.org/phadej/typify-parser.svg)](https://david-dm.org/phadej/typify-parser) + [![devDependency Status](https://david-dm.org/phadej/typify-parser/dev-status.svg)](https://david-dm.org/phadej/typify-parser#info=devDependencies) + [![Code Climate](https://img.shields.io/codeclimate/github/phadej/typify-parser.svg)](https://codeclimate.com/github/phadej/typify-parser) + + Turns `(foo, bar 42) -> quux` into + ```js + { + "type": "function", + "arg": { + "type": "product", + "args": [ + { + "type": "ident", + "value": "foo" + }, + { + "type": "application", + "callee": { + "type": "ident", + "value": "bar" + }, + "args": [ + { + "type": "number", + "value": 42 + } + ] + } + ] + }, + "result": { + "type": "ident", + "value": "quux" + } + } + ``` + + ## Synopsis + + ```js + var parser = require("typify-parser"); + + // Example from above + var t = parser("(foo, bar 42) -> quux"); + + // Free vars + p.freeVars(t); // ['bar', 'foo', 'quux'] + p.freeVars(p("rec list -> () | a & list")) // ['a'] + ``` +*/ +"use strict"; + +function unescapeString(str) { + return str.replace(/\\(?:'|"|\\|n|x[0-9a-fA-F]{2})/g, function (match) { + switch (match[1]) { + case "'": return "'"; + case "\"": return "\""; + case "\\": return "\\"; + case "n": return "\n"; + case "x": return String.fromCharCode(parseInt(match.substr(2), 16)); + } + }); +} + +function lex(input) { + // Unicode + // top: 22a4 + // bottom: 22a5 + // and: 2227 + // or: 2228 + // times: \u00d7 + // to: 2192 + // ellipsis: 2026 + // blackboard 1: d835 dfd9 + var m = input.match(/^([ \t\r\n]+|[\u22a4\u22a5\u2227\u2228\u00d7\u2192\u2026]|\ud835\udfd9|_\|_|\*|\(\)|"(?:[^"\\]|\\[\\'"n]|\\x[0-9a-fA-F]{2})*"|'(?:[^'\\]|\\[\\'"n]|\\x[0-9a-fA-F]{2})*'|[0-9a-zA-Z_\$@]+|,|->|:|;|&|\||\.\.\.|\(|\)|\[|\]|\{|\}|\?)*$/); + if (m === null) { + throw new SyntaxError("Cannot lex type signature"); + } + m = input.match(/([ \t\r\n]+|[\u22a4\u22a5\u2227\u2228\u00d7\u2192\u2026]|\ud835\udfd9|_\|_|\*|\(\)|"(?:[^"\\]|\\[\\'"n]|\\x[0-9a-fA-F]{2})*"|'(?:[^'\\]|\\[\\'"n]|\\x[0-9a-fA-F]{2})*'|[0-9a-zA-Z_\$@]+|,|->|:|;|&|\||\.\.\.|\(|\)|\[|\]|\{|\}|\?)/g); + + return m + .map(function (token) { + switch (token) { + case "_|_": return { type: "false" }; + case "\u22a5": return { type: "false" }; + case "*": return { type: "true" }; + case "\u22a4": return { type: "true" }; + case "()": return { type: "unit" }; + case "\ud835\udfd9": return { type: "unit" }; + case "true": return { type: "bool", value: true }; + case "false": return { type: "bool", value: false }; + case "rec": return { type: "rec" }; + case "&": return { type: "&" }; + case "\u2227": return { type: "&" }; + case "|": return { type: "|" }; + case "\u2228": return { type: "|" }; + case ",": return { type: "," }; + case "\u00d7": return { type: "," }; + case ";": return { type: ";" }; + case ":": return { type: ":" }; + case "(": return { type: "(" }; + case ")": return { type: ")" }; + case "[": return { type: "[" }; + case "]": return { type: "]" }; + case "{": return { type: "{" }; + case "}": return { type: "}" }; + case "?": return { type: "?" }; + case "->": return { type: "->" }; + case "\u2192": return { type: "->" }; + case "...": return { type: "..." }; + case "\u2026": return { type: "..." }; + } + + // Whitespace + if (token.match(/^[ \r\r\n]+$/)) { + return null; + } + + if (token.match(/^[0-9]+/)) { + return { type: "number", value: parseInt(token, 10) }; + } + + if (token[0] === "'" || token[0] === "\"") { + token = token.slice(1, -1); + return { type: "string", value: unescapeString(token) }; + } + + return { type: "ident", value: token }; + }) + .filter(function (token) { + return token !== null; + }); +} + +function makePunctParser(type) { + return function (state) { + if (state.pos >= state.len) { + throw new SyntaxError("Expecting identifier, end-of-input found"); + } + + var token = state.tokens[state.pos]; + if (token.type !== type) { + throw new SyntaxError("Expecting '" + type + "', found: " + token.type); + } + state.pos += 1; + + return type; + }; +} + +var colonParser = makePunctParser(":"); +var openCurlyParser = makePunctParser("{"); +var closeCurlyParser = makePunctParser("}"); +var semicolonParser = makePunctParser(";"); +var openParenParser = makePunctParser("("); +var closeParenParser = makePunctParser(")"); +var openBracketParser = makePunctParser("["); +var closeBracketParser = makePunctParser("]"); +var recKeywordParser = makePunctParser("rec"); +var arrowParser = makePunctParser("->"); + +function nameParser(state) { + if (state.pos >= state.len) { + throw new SyntaxError("Expecting identifier, end-of-input found"); + } + + var token = state.tokens[state.pos]; + if (token.type !== "ident") { + throw new SyntaxError("Expecting 'ident', found: " + token.type); + } + state.pos += 1; + + return token.value; +} + +function recursiveParser(state) { + recKeywordParser(state); + var name = nameParser(state); + arrowParser(state); + var value = typeParser(state); // eslint-disable-line no-use-before-define + return { + type: "recursive", + name: name, + arg: value, + }; +} + +function recordParser(state) { + openCurlyParser(state); + + var token = state.tokens[state.pos]; + if (token && token.type === "}") { + closeCurlyParser(state); + return { type: "record", fields: {} }; + } + + var fields = {}; + + while (true) { // eslint-disable-line no-constant-condition + // read + var name = nameParser(state); + colonParser(state); + var value = typeParser(state); // eslint-disable-line no-use-before-define + + // assign to fields + fields[name] = value; + + // ending token + token = state.tokens[state.pos]; + + // break if } + if (token && token.type === "}") { + closeCurlyParser(state); + break; + } else if (token && token.type === ";") { + semicolonParser(state); + } else { + throw new SyntaxError("Expecting '}' or ';', found: " + token.type); + } + } + + return { type: "record", fields: fields }; +} + +function postfix(parser, postfixToken, constructor) { + return function (state) { + var arg = parser(state); + + var token = state.tokens[state.pos]; + if (token && token.type === postfixToken) { + state.pos += 1; + return { + type: constructor, + arg: arg, + }; + } else { + return arg; + } + }; +} + +// this ties the knot +var optionalParser = postfix(terminalParser, "?", "optional"); // eslint-disable-line no-use-before-define + +function applicationParser(state) { + var rator = optionalParser(state); + var rands = []; + + while (true) { // eslint-disable-line no-constant-condition + var pos = state.pos; + // XXX: we shouldn't use exceptions for this + try { + var arg = optionalParser(state); + rands.push(arg); + } catch (err) { + state.pos = pos; + break; + } + } + + if (rands.length === 0) { + return rator; + } else { + return { + type: "application", + callee: rator, + args: rands, + }; + } +} + +function separatedBy(parser, separator, constructor) { + return function (state) { + var list = [parser(state)]; + while (true) { // eslint-disable-line no-constant-condition + // separator + var token = state.tokens[state.pos]; + if (token && token.type === separator) { + state.pos += 1; + } else { + break; + } + + // right argument + list.push(parser(state)); + } + + if (list.length === 1) { + return list[0]; + } else { + return { + type: constructor, + args: list, + }; + } + }; +} + +var conjunctionParser = separatedBy(applicationParser, "&", "conjunction"); +var disjunctionParser = separatedBy(conjunctionParser, "|", "disjunction"); + +// TODO: combine with optional +var variadicParser = postfix(disjunctionParser, "...", "variadic"); + +function namedParser(state) { + var token1 = state.tokens[state.pos]; + var token2 = state.tokens[state.pos + 1]; + if (token1 && token2 && token1.type === "ident" && token2.type === ":") { + state.pos += 2; + var arg = namedParser(state); + return { + type: "named", + name: token1.value, + arg: arg, + }; + } else { + return variadicParser(state); + } +} + +var productParser = separatedBy(namedParser, ",", "product"); + +function functionParser(state) { + var v = productParser(state); + + var token = state.tokens[state.pos]; + if (token && token.type === "->") { + state.pos += 1; + var result = functionParser(state); + return { + type: "function", + arg: v, + result: result, + }; + } else { + return v; + } +} + +function typeParser(state) { + return functionParser(state); +} + +function parenthesesParser(state) { + openParenParser(state); + var type = typeParser(state); + closeParenParser(state); + return type; +} + +function bracketParser(state) { + openBracketParser(state); + var type = typeParser(state); + closeBracketParser(state); + return { + type: "brackets", + arg: type, + }; +} + +function terminalParser(state) { + if (state.pos >= state.len) { + throw new SyntaxError("Expecting terminal, end-of-input found"); + } + + var token = state.tokens[state.pos]; + switch (token.type) { + case "false": + case "true": + case "unit": + case "string": + case "number": + case "bool": + case "ident": + state.pos += 1; + return token; + case "{": + return recordParser(state); + case "(": + return parenthesesParser(state); + case "[": + return bracketParser(state); + case "rec": + return recursiveParser(state); + default: + throw new SyntaxError("Expecting terminal, " + token.type + " found"); + } +} + +function parse(input) { + // console.log(input); + var tokens = lex(input); + // console.log(tokens); + var state = { + pos: 0, + len: tokens.length, + tokens: tokens, + }; + + var res = typeParser(state); + // console.log(state); + if (state.pos !== state.len) { + throw new SyntaxError("expecting end-of-input, " + tokens[state.pos].type + " found"); + } + return res; +} + +function recordFreeVars(fields) { + var res = []; + for (var k in fields) { + var t = fields[k]; + res = res.concat(freeVarsImpl(t)); // eslint-disable-line no-use-before-define + } + return res; +} + +function concatFreeVars(ts) { + var res = []; + for (var i = 0; i < ts.length; i++) { + var t = ts[i]; + res = res.concat(freeVarsImpl(t)); // eslint-disable-line no-use-before-define + } + return res; +} + +function freeVarsImpl(t) { + switch (t.type) { + case "false": + case "true": + case "unit": + case "string": + case "number": + case "bool": + return []; + case "ident": return [t.value]; + case "record": return recordFreeVars(t.fields); + case "named": return freeVarsImpl(t.arg); + case "conjunction": return concatFreeVars(t.args); + case "disjunction": return concatFreeVars(t.args); + case "product": return concatFreeVars(t.args); + case "recursive": return freeVarsImpl(t.arg).filter(function (n) { + return n !== t.name; + }); + case "optional": return freeVarsImpl(t.arg); + case "brackets": return freeVarsImpl(t.arg); + case "variadic": return freeVarsImpl(t.arg); + case "application": return freeVarsImpl(t.callee).concat(concatFreeVars(t.args)); + case "function": return freeVarsImpl(t.arg).concat(freeVarsImpl(t.result)); + //default: throw new Error("Unknown type " + t.type); + } +} + +function uniq(arr) { + var res = []; + for (var i = 0; i < arr.length; i++) { + var x = arr[i]; + if (res.indexOf(x) === -1) { + res.push(x); + } + } + return res; +} + +function freeVars(t) { + var fvs = freeVarsImpl(t); + fvs.sort(); + return uniq(fvs); +} + +parse.freeVars = freeVars; + +module.exports = parse; + +},{}],34:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],35:[function(require,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; +} +},{}],36:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; + + +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global.process)) { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } + + if (process.noDeprecation === true) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +}; + + +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; + + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); +} +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } +} + + +function stylizeNoColor(str, styleType) { + return str; +} + + +function arrayToHash(array) { + var hash = {}; + + array.forEach(function(val, idx) { + hash[val] = true; + }); + + return hash; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); + + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } + + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +exports.isBuffer = require('./support/isBuffer'); + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} + + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} + + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = require('inherits'); + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; + +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +},{"./support/isBuffer":35,"inherits":34}]},{},[15])(15) +}); + diff --git a/hw6/Claudio_Maggioni/public/resources/lodash.js b/hw6/Claudio_Maggioni/public/resources/lodash.js new file mode 100644 index 0000000..b39ddce --- /dev/null +++ b/hw6/Claudio_Maggioni/public/resources/lodash.js @@ -0,0 +1,17084 @@ +/** + * @license + * Lodash + * Copyright JS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ +;(function() { + + /** Used as a safe reference for `undefined` in pre-ES5 environments. */ + var undefined; + + /** Used as the semantic version number. */ + var VERSION = '4.17.4'; + + /** Used as the size to enable large array optimizations. */ + var LARGE_ARRAY_SIZE = 200; + + /** Error message constants. */ + var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.', + FUNC_ERROR_TEXT = 'Expected a function'; + + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED = '__lodash_hash_undefined__'; + + /** Used as the maximum memoize cache size. */ + var MAX_MEMOIZE_SIZE = 500; + + /** Used as the internal argument placeholder. */ + var PLACEHOLDER = '__lodash_placeholder__'; + + /** Used to compose bitmasks for cloning. */ + var CLONE_DEEP_FLAG = 1, + CLONE_FLAT_FLAG = 2, + CLONE_SYMBOLS_FLAG = 4; + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG = 1, + COMPARE_UNORDERED_FLAG = 2; + + /** Used to compose bitmasks for function metadata. */ + var WRAP_BIND_FLAG = 1, + WRAP_BIND_KEY_FLAG = 2, + WRAP_CURRY_BOUND_FLAG = 4, + WRAP_CURRY_FLAG = 8, + WRAP_CURRY_RIGHT_FLAG = 16, + WRAP_PARTIAL_FLAG = 32, + WRAP_PARTIAL_RIGHT_FLAG = 64, + WRAP_ARY_FLAG = 128, + WRAP_REARG_FLAG = 256, + WRAP_FLIP_FLAG = 512; + + /** Used as default options for `_.truncate`. */ + var DEFAULT_TRUNC_LENGTH = 30, + DEFAULT_TRUNC_OMISSION = '...'; + + /** Used to detect hot functions by number of calls within a span of milliseconds. */ + var HOT_COUNT = 800, + HOT_SPAN = 16; + + /** Used to indicate the type of lazy iteratees. */ + var LAZY_FILTER_FLAG = 1, + LAZY_MAP_FLAG = 2, + LAZY_WHILE_FLAG = 3; + + /** Used as references for various `Number` constants. */ + var INFINITY = 1 / 0, + MAX_SAFE_INTEGER = 9007199254740991, + MAX_INTEGER = 1.7976931348623157e+308, + NAN = 0 / 0; + + /** Used as references for the maximum length and index of an array. */ + var MAX_ARRAY_LENGTH = 4294967295, + MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, + HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; + + /** Used to associate wrap methods with their bit flags. */ + var wrapFlags = [ + ['ary', WRAP_ARY_FLAG], + ['bind', WRAP_BIND_FLAG], + ['bindKey', WRAP_BIND_KEY_FLAG], + ['curry', WRAP_CURRY_FLAG], + ['curryRight', WRAP_CURRY_RIGHT_FLAG], + ['flip', WRAP_FLIP_FLAG], + ['partial', WRAP_PARTIAL_FLAG], + ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], + ['rearg', WRAP_REARG_FLAG] + ]; + + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + asyncTag = '[object AsyncFunction]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + domExcTag = '[object DOMException]', + errorTag = '[object Error]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + mapTag = '[object Map]', + numberTag = '[object Number]', + nullTag = '[object Null]', + objectTag = '[object Object]', + promiseTag = '[object Promise]', + proxyTag = '[object Proxy]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + symbolTag = '[object Symbol]', + undefinedTag = '[object Undefined]', + weakMapTag = '[object WeakMap]', + weakSetTag = '[object WeakSet]'; + + var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + + /** Used to match empty string literals in compiled template source. */ + var reEmptyStringLeading = /\b__p \+= '';/g, + reEmptyStringMiddle = /\b(__p \+=) '' \+/g, + reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; + + /** Used to match HTML entities and HTML characters. */ + var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, + reUnescapedHtml = /[&<>"']/g, + reHasEscapedHtml = RegExp(reEscapedHtml.source), + reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + + /** Used to match template delimiters. */ + var reEscape = /<%-([\s\S]+?)%>/g, + reEvaluate = /<%([\s\S]+?)%>/g, + reInterpolate = /<%=([\s\S]+?)%>/g; + + /** Used to match property names within property paths. */ + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/, + reLeadingDot = /^\./, + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + + /** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ + var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, + reHasRegExpChar = RegExp(reRegExpChar.source); + + /** Used to match leading and trailing whitespace. */ + var reTrim = /^\s+|\s+$/g, + reTrimStart = /^\s+/, + reTrimEnd = /\s+$/; + + /** Used to match wrap detail comments. */ + var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, + reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, + reSplitDetails = /,? & /; + + /** Used to match words composed of alphanumeric characters. */ + var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; + + /** Used to match backslashes in property paths. */ + var reEscapeChar = /\\(\\)?/g; + + /** + * Used to match + * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). + */ + var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; + + /** Used to match `RegExp` flags from their coerced string values. */ + var reFlags = /\w*$/; + + /** Used to detect bad signed hexadecimal string values. */ + var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + + /** Used to detect binary string values. */ + var reIsBinary = /^0b[01]+$/i; + + /** Used to detect host constructors (Safari). */ + var reIsHostCtor = /^\[object .+?Constructor\]$/; + + /** Used to detect octal string values. */ + var reIsOctal = /^0o[0-7]+$/i; + + /** Used to detect unsigned integer values. */ + var reIsUint = /^(?:0|[1-9]\d*)$/; + + /** Used to match Latin Unicode letters (excluding mathematical operators). */ + var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; + + /** Used to ensure capturing order of template delimiters. */ + var reNoMatch = /($^)/; + + /** Used to match unescaped characters in compiled string literals. */ + var reUnescapedString = /['\n\r\u2028\u2029\\]/g; + + /** Used to compose unicode character classes. */ + var rsAstralRange = '\\ud800-\\udfff', + rsComboMarksRange = '\\u0300-\\u036f', + reComboHalfMarksRange = '\\ufe20-\\ufe2f', + rsComboSymbolsRange = '\\u20d0-\\u20ff', + rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, + rsDingbatRange = '\\u2700-\\u27bf', + rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', + rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', + rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', + rsPunctuationRange = '\\u2000-\\u206f', + rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', + rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', + rsVarRange = '\\ufe0e\\ufe0f', + rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; + + /** Used to compose unicode capture groups. */ + var rsApos = "['\u2019]", + rsAstral = '[' + rsAstralRange + ']', + rsBreak = '[' + rsBreakRange + ']', + rsCombo = '[' + rsComboRange + ']', + rsDigits = '\\d+', + rsDingbat = '[' + rsDingbatRange + ']', + rsLower = '[' + rsLowerRange + ']', + rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', + rsFitz = '\\ud83c[\\udffb-\\udfff]', + rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', + rsNonAstral = '[^' + rsAstralRange + ']', + rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', + rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', + rsUpper = '[' + rsUpperRange + ']', + rsZWJ = '\\u200d'; + + /** Used to compose unicode regexes. */ + var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')', + rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')', + rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', + rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', + reOptMod = rsModifier + '?', + rsOptVar = '[' + rsVarRange + ']?', + rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', + rsOrdLower = '\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)', + rsOrdUpper = '\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)', + rsSeq = rsOptVar + reOptMod + rsOptJoin, + rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, + rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; + + /** Used to match apostrophes. */ + var reApos = RegExp(rsApos, 'g'); + + /** + * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and + * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). + */ + var reComboMark = RegExp(rsCombo, 'g'); + + /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ + var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); + + /** Used to match complex or compound words. */ + var reUnicodeWord = RegExp([ + rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', + rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')', + rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower, + rsUpper + '+' + rsOptContrUpper, + rsOrdUpper, + rsOrdLower, + rsDigits, + rsEmoji + ].join('|'), 'g'); + + /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ + var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); + + /** Used to detect strings that need a more robust regexp to match words. */ + var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; + + /** Used to assign default `context` object properties. */ + var contextProps = [ + 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', + 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', + 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', + 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', + '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' + ]; + + /** Used to make template sourceURLs easier to identify. */ + var templateCounter = -1; + + /** Used to identify `toStringTag` values of typed arrays. */ + var typedArrayTags = {}; + typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = + typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = + typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = + typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = + typedArrayTags[uint32Tag] = true; + typedArrayTags[argsTag] = typedArrayTags[arrayTag] = + typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = + typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = + typedArrayTags[errorTag] = typedArrayTags[funcTag] = + typedArrayTags[mapTag] = typedArrayTags[numberTag] = + typedArrayTags[objectTag] = typedArrayTags[regexpTag] = + typedArrayTags[setTag] = typedArrayTags[stringTag] = + typedArrayTags[weakMapTag] = false; + + /** Used to identify `toStringTag` values supported by `_.clone`. */ + var cloneableTags = {}; + cloneableTags[argsTag] = cloneableTags[arrayTag] = + cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = + cloneableTags[boolTag] = cloneableTags[dateTag] = + cloneableTags[float32Tag] = cloneableTags[float64Tag] = + cloneableTags[int8Tag] = cloneableTags[int16Tag] = + cloneableTags[int32Tag] = cloneableTags[mapTag] = + cloneableTags[numberTag] = cloneableTags[objectTag] = + cloneableTags[regexpTag] = cloneableTags[setTag] = + cloneableTags[stringTag] = cloneableTags[symbolTag] = + cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = + cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; + cloneableTags[errorTag] = cloneableTags[funcTag] = + cloneableTags[weakMapTag] = false; + + /** Used to map Latin Unicode letters to basic Latin letters. */ + var deburredLetters = { + // Latin-1 Supplement block. + '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', + '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', + '\xc7': 'C', '\xe7': 'c', + '\xd0': 'D', '\xf0': 'd', + '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', + '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', + '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', + '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', + '\xd1': 'N', '\xf1': 'n', + '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', + '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', + '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', + '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', + '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', + '\xc6': 'Ae', '\xe6': 'ae', + '\xde': 'Th', '\xfe': 'th', + '\xdf': 'ss', + // Latin Extended-A block. + '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', + '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', + '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', + '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', + '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', + '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', + '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', + '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', + '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', + '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', + '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', + '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', + '\u0134': 'J', '\u0135': 'j', + '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', + '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', + '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', + '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', + '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', + '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', + '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', + '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', + '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', + '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', + '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', + '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', + '\u0163': 't', '\u0165': 't', '\u0167': 't', + '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', + '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', + '\u0174': 'W', '\u0175': 'w', + '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', + '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', + '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', + '\u0132': 'IJ', '\u0133': 'ij', + '\u0152': 'Oe', '\u0153': 'oe', + '\u0149': "'n", '\u017f': 's' + }; + + /** Used to map characters to HTML entities. */ + var htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + + /** Used to map HTML entities to characters. */ + var htmlUnescapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'" + }; + + /** Used to escape characters for inclusion in compiled string literals. */ + var stringEscapes = { + '\\': '\\', + "'": "'", + '\n': 'n', + '\r': 'r', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + /** Built-in method references without a dependency on `root`. */ + var freeParseFloat = parseFloat, + freeParseInt = parseInt; + + /** Detect free variable `global` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + + /** Detect free variable `self`. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); + + /** Detect free variable `exports`. */ + var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports = freeModule && freeModule.exports === freeExports; + + /** Detect free variable `process` from Node.js. */ + var freeProcess = moduleExports && freeGlobal.process; + + /** Used to access faster Node.js helpers. */ + var nodeUtil = (function() { + try { + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} + }()); + + /* Node.js helper references. */ + var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, + nodeIsDate = nodeUtil && nodeUtil.isDate, + nodeIsMap = nodeUtil && nodeUtil.isMap, + nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, + nodeIsSet = nodeUtil && nodeUtil.isSet, + nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + + /*--------------------------------------------------------------------------*/ + + /** + * Adds the key-value `pair` to `map`. + * + * @private + * @param {Object} map The map to modify. + * @param {Array} pair The key-value pair to add. + * @returns {Object} Returns `map`. + */ + function addMapEntry(map, pair) { + // Don't return `map.set` because it's not chainable in IE 11. + map.set(pair[0], pair[1]); + return map; + } + + /** + * Adds `value` to `set`. + * + * @private + * @param {Object} set The set to modify. + * @param {*} value The value to add. + * @returns {Object} Returns `set`. + */ + function addSetEntry(set, value) { + // Don't return `set.add` because it's not chainable in IE 11. + set.add(value); + return set; + } + + /** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ + function apply(func, thisArg, args) { + switch (args.length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); + } + + /** + * A specialized version of `baseAggregator` for arrays. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function arrayAggregator(array, setter, iteratee, accumulator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + var value = array[index]; + setter(accumulator, value, iteratee(value), array); + } + return accumulator; + } + + /** + * A specialized version of `_.forEach` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEach(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.forEachRight` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEachRight(array, iteratee) { + var length = array == null ? 0 : array.length; + + while (length--) { + if (iteratee(array[length], length, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.every` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + */ + function arrayEvery(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; + } + + /** + * A specialized version of `_.filter` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function arrayFilter(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * A specialized version of `_.includes` for arrays without support for + * specifying an index to search from. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludes(array, value) { + var length = array == null ? 0 : array.length; + return !!length && baseIndexOf(array, value, 0) > -1; + } + + /** + * This function is like `arrayIncludes` except that it accepts a comparator. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @param {Function} comparator The comparator invoked per element. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludesWith(array, value, comparator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (comparator(value, array[index])) { + return true; + } + } + return false; + } + + /** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function arrayMap(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } + + /** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ + function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; + } + + /** + * A specialized version of `_.reduce` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the first element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduce(array, iteratee, accumulator, initAccum) { + var index = -1, + length = array == null ? 0 : array.length; + + if (initAccum && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; + } + + /** + * A specialized version of `_.reduceRight` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the last element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduceRight(array, iteratee, accumulator, initAccum) { + var length = array == null ? 0 : array.length; + if (initAccum && length) { + accumulator = array[--length]; + } + while (length--) { + accumulator = iteratee(accumulator, array[length], length, array); + } + return accumulator; + } + + /** + * A specialized version of `_.some` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function arraySome(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; + } + + /** + * Gets the size of an ASCII `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + var asciiSize = baseProperty('length'); + + /** + * Converts an ASCII `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function asciiToArray(string) { + return string.split(''); + } + + /** + * Splits an ASCII `string` into an array of its words. + * + * @private + * @param {string} The string to inspect. + * @returns {Array} Returns the words of `string`. + */ + function asciiWords(string) { + return string.match(reAsciiWord) || []; + } + + /** + * The base implementation of methods like `_.findKey` and `_.findLastKey`, + * without support for iteratee shorthands, which iterates over `collection` + * using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the found element or its key, else `undefined`. + */ + function baseFindKey(collection, predicate, eachFunc) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = key; + return false; + } + }); + return result; + } + + /** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOf(array, value, fromIndex) { + return value === value + ? strictIndexOf(array, value, fromIndex) + : baseFindIndex(array, baseIsNaN, fromIndex); + } + + /** + * This function is like `baseIndexOf` except that it accepts a comparator. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @param {Function} comparator The comparator invoked per element. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOfWith(array, value, fromIndex, comparator) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (comparator(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.isNaN` without support for number objects. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + */ + function baseIsNaN(value) { + return value !== value; + } + + /** + * The base implementation of `_.mean` and `_.meanBy` without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the mean. + */ + function baseMean(array, iteratee) { + var length = array == null ? 0 : array.length; + return length ? (baseSum(array, iteratee) / length) : NAN; + } + + /** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.propertyOf` without support for deep paths. + * + * @private + * @param {Object} object The object to query. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyOf(object) { + return function(key) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.reduce` and `_.reduceRight`, without support + * for iteratee shorthands, which iterates over `collection` using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} accumulator The initial value. + * @param {boolean} initAccum Specify using the first or last element of + * `collection` as the initial value. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the accumulated value. + */ + function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { + eachFunc(collection, function(value, index, collection) { + accumulator = initAccum + ? (initAccum = false, value) + : iteratee(accumulator, value, index, collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.sortBy` which uses `comparer` to define the + * sort order of `array` and replaces criteria objects with their corresponding + * values. + * + * @private + * @param {Array} array The array to sort. + * @param {Function} comparer The function to define sort order. + * @returns {Array} Returns `array`. + */ + function baseSortBy(array, comparer) { + var length = array.length; + + array.sort(comparer); + while (length--) { + array[length] = array[length].value; + } + return array; + } + + /** + * The base implementation of `_.sum` and `_.sumBy` without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the sum. + */ + function baseSum(array, iteratee) { + var result, + index = -1, + length = array.length; + + while (++index < length) { + var current = iteratee(array[index]); + if (current !== undefined) { + result = result === undefined ? current : (result + current); + } + } + return result; + } + + /** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ + function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; + } + + /** + * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array + * of key-value pairs for `object` corresponding to the property names of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the key-value pairs. + */ + function baseToPairs(object, props) { + return arrayMap(props, function(key) { + return [key, object[key]]; + }); + } + + /** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ + function baseUnary(func) { + return function(value) { + return func(value); + }; + } + + /** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ + function baseValues(object, props) { + return arrayMap(props, function(key) { + return object[key]; + }); + } + + /** + * Checks if a `cache` value for `key` exists. + * + * @private + * @param {Object} cache The cache to query. + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function cacheHas(cache, key) { + return cache.has(key); + } + + /** + * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the first unmatched string symbol. + */ + function charsStartIndex(strSymbols, chrSymbols) { + var index = -1, + length = strSymbols.length; + + while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the last unmatched string symbol. + */ + function charsEndIndex(strSymbols, chrSymbols) { + var index = strSymbols.length; + + while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Gets the number of `placeholder` occurrences in `array`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} placeholder The placeholder to search for. + * @returns {number} Returns the placeholder count. + */ + function countHolders(array, placeholder) { + var length = array.length, + result = 0; + + while (length--) { + if (array[length] === placeholder) { + ++result; + } + } + return result; + } + + /** + * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A + * letters to basic Latin letters. + * + * @private + * @param {string} letter The matched letter to deburr. + * @returns {string} Returns the deburred letter. + */ + var deburrLetter = basePropertyOf(deburredLetters); + + /** + * Used by `_.escape` to convert characters to HTML entities. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + var escapeHtmlChar = basePropertyOf(htmlEscapes); + + /** + * Used by `_.template` to escape characters for inclusion in compiled string literals. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + function escapeStringChar(chr) { + return '\\' + stringEscapes[chr]; + } + + /** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function getValue(object, key) { + return object == null ? undefined : object[key]; + } + + /** + * Checks if `string` contains Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a symbol is found, else `false`. + */ + function hasUnicode(string) { + return reHasUnicode.test(string); + } + + /** + * Checks if `string` contains a word composed of Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a word is found, else `false`. + */ + function hasUnicodeWord(string) { + return reHasUnicodeWord.test(string); + } + + /** + * Converts `iterator` to an array. + * + * @private + * @param {Object} iterator The iterator to convert. + * @returns {Array} Returns the converted array. + */ + function iteratorToArray(iterator) { + var data, + result = []; + + while (!(data = iterator.next()).done) { + result.push(data.value); + } + return result; + } + + /** + * Converts `map` to its key-value pairs. + * + * @private + * @param {Object} map The map to convert. + * @returns {Array} Returns the key-value pairs. + */ + function mapToArray(map) { + var index = -1, + result = Array(map.size); + + map.forEach(function(value, key) { + result[++index] = [key, value]; + }); + return result; + } + + /** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ + function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; + } + + /** + * Replaces all `placeholder` elements in `array` with an internal placeholder + * and returns an array of their indexes. + * + * @private + * @param {Array} array The array to modify. + * @param {*} placeholder The placeholder to replace. + * @returns {Array} Returns the new array of placeholder indexes. + */ + function replaceHolders(array, placeholder) { + var index = -1, + length = array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value === placeholder || value === PLACEHOLDER) { + array[index] = PLACEHOLDER; + result[resIndex++] = index; + } + } + return result; + } + + /** + * Converts `set` to an array of its values. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the values. + */ + function setToArray(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = value; + }); + return result; + } + + /** + * Converts `set` to its value-value pairs. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the value-value pairs. + */ + function setToPairs(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = [value, value]; + }); + return result; + } + + /** + * A specialized version of `_.indexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictIndexOf(array, value, fromIndex) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * A specialized version of `_.lastIndexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictLastIndexOf(array, value, fromIndex) { + var index = fromIndex + 1; + while (index--) { + if (array[index] === value) { + return index; + } + } + return index; + } + + /** + * Gets the number of symbols in `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the string size. + */ + function stringSize(string) { + return hasUnicode(string) + ? unicodeSize(string) + : asciiSize(string); + } + + /** + * Converts `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function stringToArray(string) { + return hasUnicode(string) + ? unicodeToArray(string) + : asciiToArray(string); + } + + /** + * Used by `_.unescape` to convert HTML entities to characters. + * + * @private + * @param {string} chr The matched character to unescape. + * @returns {string} Returns the unescaped character. + */ + var unescapeHtmlChar = basePropertyOf(htmlUnescapes); + + /** + * Gets the size of a Unicode `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + function unicodeSize(string) { + var result = reUnicode.lastIndex = 0; + while (reUnicode.test(string)) { + ++result; + } + return result; + } + + /** + * Converts a Unicode `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function unicodeToArray(string) { + return string.match(reUnicode) || []; + } + + /** + * Splits a Unicode `string` into an array of its words. + * + * @private + * @param {string} The string to inspect. + * @returns {Array} Returns the words of `string`. + */ + function unicodeWords(string) { + return string.match(reUnicodeWord) || []; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Create a new pristine `lodash` function using the `context` object. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Util + * @param {Object} [context=root] The context object. + * @returns {Function} Returns a new `lodash` function. + * @example + * + * _.mixin({ 'foo': _.constant('foo') }); + * + * var lodash = _.runInContext(); + * lodash.mixin({ 'bar': lodash.constant('bar') }); + * + * _.isFunction(_.foo); + * // => true + * _.isFunction(_.bar); + * // => false + * + * lodash.isFunction(lodash.foo); + * // => false + * lodash.isFunction(lodash.bar); + * // => true + * + * // Create a suped-up `defer` in Node.js. + * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; + */ + var runInContext = (function runInContext(context) { + context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps)); + + /** Built-in constructor references. */ + var Array = context.Array, + Date = context.Date, + Error = context.Error, + Function = context.Function, + Math = context.Math, + Object = context.Object, + RegExp = context.RegExp, + String = context.String, + TypeError = context.TypeError; + + /** Used for built-in method references. */ + var arrayProto = Array.prototype, + funcProto = Function.prototype, + objectProto = Object.prototype; + + /** Used to detect overreaching core-js shims. */ + var coreJsData = context['__core-js_shared__']; + + /** Used to resolve the decompiled source of functions. */ + var funcToString = funcProto.toString; + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; + + /** Used to generate unique IDs. */ + var idCounter = 0; + + /** Used to detect methods masquerading as native. */ + var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; + }()); + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto.toString; + + /** Used to infer the `Object` constructor. */ + var objectCtorString = funcToString.call(Object); + + /** Used to restore the original `_` reference in `_.noConflict`. */ + var oldDash = root._; + + /** Used to detect if a method is native. */ + var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); + + /** Built-in value references. */ + var Buffer = moduleExports ? context.Buffer : undefined, + Symbol = context.Symbol, + Uint8Array = context.Uint8Array, + allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, + getPrototype = overArg(Object.getPrototypeOf, Object), + objectCreate = Object.create, + propertyIsEnumerable = objectProto.propertyIsEnumerable, + splice = arrayProto.splice, + spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined, + symIterator = Symbol ? Symbol.iterator : undefined, + symToStringTag = Symbol ? Symbol.toStringTag : undefined; + + var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} + }()); + + /** Mocked built-ins. */ + var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout, + ctxNow = Date && Date.now !== root.Date.now && Date.now, + ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout; + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeCeil = Math.ceil, + nativeFloor = Math.floor, + nativeGetSymbols = Object.getOwnPropertySymbols, + nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, + nativeIsFinite = context.isFinite, + nativeJoin = arrayProto.join, + nativeKeys = overArg(Object.keys, Object), + nativeMax = Math.max, + nativeMin = Math.min, + nativeNow = Date.now, + nativeParseInt = context.parseInt, + nativeRandom = Math.random, + nativeReverse = arrayProto.reverse; + + /* Built-in method references that are verified to be native. */ + var DataView = getNative(context, 'DataView'), + Map = getNative(context, 'Map'), + Promise = getNative(context, 'Promise'), + Set = getNative(context, 'Set'), + WeakMap = getNative(context, 'WeakMap'), + nativeCreate = getNative(Object, 'create'); + + /** Used to store function metadata. */ + var metaMap = WeakMap && new WeakMap; + + /** Used to lookup unminified function names. */ + var realNames = {}; + + /** Used to detect maps, sets, and weakmaps. */ + var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map), + promiseCtorString = toSource(Promise), + setCtorString = toSource(Set), + weakMapCtorString = toSource(WeakMap); + + /** Used to convert symbols to primitives and strings. */ + var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object which wraps `value` to enable implicit method + * chain sequences. Methods that operate on and return arrays, collections, + * and functions can be chained together. Methods that retrieve a single value + * or may return a primitive value will automatically end the chain sequence + * and return the unwrapped value. Otherwise, the value must be unwrapped + * with `_#value`. + * + * Explicit chain sequences, which must be unwrapped with `_#value`, may be + * enabled using `_.chain`. + * + * The execution of chained methods is lazy, that is, it's deferred until + * `_#value` is implicitly or explicitly called. + * + * Lazy evaluation allows several methods to support shortcut fusion. + * Shortcut fusion is an optimization to merge iteratee calls; this avoids + * the creation of intermediate arrays and can greatly reduce the number of + * iteratee executions. Sections of a chain sequence qualify for shortcut + * fusion if the section is applied to an array and iteratees accept only + * one argument. The heuristic for whether a section qualifies for shortcut + * fusion is subject to change. + * + * Chaining is supported in custom builds as long as the `_#value` method is + * directly or indirectly included in the build. + * + * In addition to lodash methods, wrappers have `Array` and `String` methods. + * + * The wrapper `Array` methods are: + * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` + * + * The wrapper `String` methods are: + * `replace` and `split` + * + * The wrapper methods that support shortcut fusion are: + * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, + * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, + * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` + * + * The chainable wrapper methods are: + * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, + * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, + * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, + * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, + * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, + * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, + * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, + * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, + * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, + * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, + * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, + * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, + * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, + * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, + * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, + * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, + * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, + * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, + * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, + * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, + * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, + * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, + * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, + * `zipObject`, `zipObjectDeep`, and `zipWith` + * + * The wrapper methods that are **not** chainable by default are: + * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, + * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, + * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, + * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, + * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, + * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, + * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, + * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, + * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, + * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, + * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, + * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, + * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, + * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, + * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, + * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, + * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, + * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, + * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, + * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, + * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, + * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, + * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, + * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, + * `upperFirst`, `value`, and `words` + * + * @name _ + * @constructor + * @category Seq + * @param {*} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2, 3]); + * + * // Returns an unwrapped value. + * wrapped.reduce(_.add); + * // => 6 + * + * // Returns a wrapped value. + * var squares = wrapped.map(square); + * + * _.isArray(squares); + * // => false + * + * _.isArray(squares.value()); + * // => true + */ + function lodash(value) { + if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { + if (value instanceof LodashWrapper) { + return value; + } + if (hasOwnProperty.call(value, '__wrapped__')) { + return wrapperClone(value); + } + } + return new LodashWrapper(value); + } + + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} proto The object to inherit from. + * @returns {Object} Returns the new object. + */ + var baseCreate = (function() { + function object() {} + return function(proto) { + if (!isObject(proto)) { + return {}; + } + if (objectCreate) { + return objectCreate(proto); + } + object.prototype = proto; + var result = new object; + object.prototype = undefined; + return result; + }; + }()); + + /** + * The function whose prototype chain sequence wrappers inherit from. + * + * @private + */ + function baseLodash() { + // No operation performed. + } + + /** + * The base constructor for creating `lodash` wrapper objects. + * + * @private + * @param {*} value The value to wrap. + * @param {boolean} [chainAll] Enable explicit method chain sequences. + */ + function LodashWrapper(value, chainAll) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__chain__ = !!chainAll; + this.__index__ = 0; + this.__values__ = undefined; + } + + /** + * By default, the template delimiters used by lodash are like those in + * embedded Ruby (ERB) as well as ES2015 template strings. Change the + * following template settings to use alternative delimiters. + * + * @static + * @memberOf _ + * @type {Object} + */ + lodash.templateSettings = { + + /** + * Used to detect `data` property values to be HTML-escaped. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'escape': reEscape, + + /** + * Used to detect code to be evaluated. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'evaluate': reEvaluate, + + /** + * Used to detect `data` property values to inject. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'interpolate': reInterpolate, + + /** + * Used to reference the data object in the template text. + * + * @memberOf _.templateSettings + * @type {string} + */ + 'variable': '', + + /** + * Used to import variables into the compiled template. + * + * @memberOf _.templateSettings + * @type {Object} + */ + 'imports': { + + /** + * A reference to the `lodash` function. + * + * @memberOf _.templateSettings.imports + * @type {Function} + */ + '_': lodash + } + }; + + // Ensure wrappers are instances of `baseLodash`. + lodash.prototype = baseLodash.prototype; + lodash.prototype.constructor = lodash; + + LodashWrapper.prototype = baseCreate(baseLodash.prototype); + LodashWrapper.prototype.constructor = LodashWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. + * + * @private + * @constructor + * @param {*} value The value to wrap. + */ + function LazyWrapper(value) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__dir__ = 1; + this.__filtered__ = false; + this.__iteratees__ = []; + this.__takeCount__ = MAX_ARRAY_LENGTH; + this.__views__ = []; + } + + /** + * Creates a clone of the lazy wrapper object. + * + * @private + * @name clone + * @memberOf LazyWrapper + * @returns {Object} Returns the cloned `LazyWrapper` object. + */ + function lazyClone() { + var result = new LazyWrapper(this.__wrapped__); + result.__actions__ = copyArray(this.__actions__); + result.__dir__ = this.__dir__; + result.__filtered__ = this.__filtered__; + result.__iteratees__ = copyArray(this.__iteratees__); + result.__takeCount__ = this.__takeCount__; + result.__views__ = copyArray(this.__views__); + return result; + } + + /** + * Reverses the direction of lazy iteration. + * + * @private + * @name reverse + * @memberOf LazyWrapper + * @returns {Object} Returns the new reversed `LazyWrapper` object. + */ + function lazyReverse() { + if (this.__filtered__) { + var result = new LazyWrapper(this); + result.__dir__ = -1; + result.__filtered__ = true; + } else { + result = this.clone(); + result.__dir__ *= -1; + } + return result; + } + + /** + * Extracts the unwrapped value from its lazy wrapper. + * + * @private + * @name value + * @memberOf LazyWrapper + * @returns {*} Returns the unwrapped value. + */ + function lazyValue() { + var array = this.__wrapped__.value(), + dir = this.__dir__, + isArr = isArray(array), + isRight = dir < 0, + arrLength = isArr ? array.length : 0, + view = getView(0, arrLength, this.__views__), + start = view.start, + end = view.end, + length = end - start, + index = isRight ? end : (start - 1), + iteratees = this.__iteratees__, + iterLength = iteratees.length, + resIndex = 0, + takeCount = nativeMin(length, this.__takeCount__); + + if (!isArr || (!isRight && arrLength == length && takeCount == length)) { + return baseWrapperValue(array, this.__actions__); + } + var result = []; + + outer: + while (length-- && resIndex < takeCount) { + index += dir; + + var iterIndex = -1, + value = array[index]; + + while (++iterIndex < iterLength) { + var data = iteratees[iterIndex], + iteratee = data.iteratee, + type = data.type, + computed = iteratee(value); + + if (type == LAZY_MAP_FLAG) { + value = computed; + } else if (!computed) { + if (type == LAZY_FILTER_FLAG) { + continue outer; + } else { + break outer; + } + } + } + result[resIndex++] = value; + } + return result; + } + + // Ensure `LazyWrapper` is an instance of `baseLodash`. + LazyWrapper.prototype = baseCreate(baseLodash.prototype); + LazyWrapper.prototype.constructor = LazyWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ + function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; + } + + /** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty.call(data, key) ? data[key] : undefined; + } + + /** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); + } + + /** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ + function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; + } + + // Add methods to `Hash`. + Hash.prototype.clear = hashClear; + Hash.prototype['delete'] = hashDelete; + Hash.prototype.get = hashGet; + Hash.prototype.has = hashHas; + Hash.prototype.set = hashSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ + function listCacheClear() { + this.__data__ = []; + this.size = 0; + } + + /** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; + } + + /** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; + } + + /** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; + } + + /** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ + function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; + } + + // Add methods to `ListCache`. + ListCache.prototype.clear = listCacheClear; + ListCache.prototype['delete'] = listCacheDelete; + ListCache.prototype.get = listCacheGet; + ListCache.prototype.has = listCacheHas; + ListCache.prototype.set = listCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ + function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map || ListCache), + 'string': new Hash + }; + } + + /** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function mapCacheGet(key) { + return getMapData(this, key).get(key); + } + + /** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function mapCacheHas(key) { + return getMapData(this, key).has(key); + } + + /** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ + function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; + } + + // Add methods to `MapCache`. + MapCache.prototype.clear = mapCacheClear; + MapCache.prototype['delete'] = mapCacheDelete; + MapCache.prototype.get = mapCacheGet; + MapCache.prototype.has = mapCacheHas; + MapCache.prototype.set = mapCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * + * Creates an array cache object to store unique values. + * + * @private + * @constructor + * @param {Array} [values] The values to cache. + */ + function SetCache(values) { + var index = -1, + length = values == null ? 0 : values.length; + + this.__data__ = new MapCache; + while (++index < length) { + this.add(values[index]); + } + } + + /** + * Adds `value` to the array cache. + * + * @private + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. + */ + function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED); + return this; + } + + /** + * Checks if `value` is in the array cache. + * + * @private + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. + */ + function setCacheHas(value) { + return this.__data__.has(value); + } + + // Add methods to `SetCache`. + SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; + SetCache.prototype.has = setCacheHas; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Stack(entries) { + var data = this.__data__ = new ListCache(entries); + this.size = data.size; + } + + /** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ + function stackClear() { + this.__data__ = new ListCache; + this.size = 0; + } + + /** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; + } + + /** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function stackGet(key) { + return this.__data__.get(key); + } + + /** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function stackHas(key) { + return this.__data__.has(key); + } + + /** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ + function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; + } + + // Add methods to `Stack`. + Stack.prototype.clear = stackClear; + Stack.prototype['delete'] = stackDelete; + Stack.prototype.get = stackGet; + Stack.prototype.has = stackHas; + Stack.prototype.set = stackSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ + function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; + } + + /** + * A specialized version of `_.sample` for arrays. + * + * @private + * @param {Array} array The array to sample. + * @returns {*} Returns the random element. + */ + function arraySample(array) { + var length = array.length; + return length ? array[baseRandom(0, length - 1)] : undefined; + } + + /** + * A specialized version of `_.sampleSize` for arrays. + * + * @private + * @param {Array} array The array to sample. + * @param {number} n The number of elements to sample. + * @returns {Array} Returns the random elements. + */ + function arraySampleSize(array, n) { + return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length)); + } + + /** + * A specialized version of `_.shuffle` for arrays. + * + * @private + * @param {Array} array The array to shuffle. + * @returns {Array} Returns the new shuffled array. + */ + function arrayShuffle(array) { + return shuffleSelf(copyArray(array)); + } + + /** + * This function is like `assignValue` except that it doesn't assign + * `undefined` values. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignMergeValue(object, key, value) { + if ((value !== undefined && !eq(object[key], value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; + } + + /** + * Aggregates elements of `collection` on `accumulator` with keys transformed + * by `iteratee` and values set by `setter`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function baseAggregator(collection, setter, iteratee, accumulator) { + baseEach(collection, function(value, key, collection) { + setter(accumulator, value, iteratee(value), collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.assign` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssign(object, source) { + return object && copyObject(source, keys(source), object); + } + + /** + * The base implementation of `_.assignIn` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssignIn(object, source) { + return object && copyObject(source, keysIn(source), object); + } + + /** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } + } + + /** + * The base implementation of `_.at` without support for individual paths. + * + * @private + * @param {Object} object The object to iterate over. + * @param {string[]} paths The property paths to pick. + * @returns {Array} Returns the picked elements. + */ + function baseAt(object, paths) { + var index = -1, + length = paths.length, + result = Array(length), + skip = object == null; + + while (++index < length) { + result[index] = skip ? undefined : get(object, paths[index]); + } + return result; + } + + /** + * The base implementation of `_.clamp` which doesn't coerce arguments. + * + * @private + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + */ + function baseClamp(number, lower, upper) { + if (number === number) { + if (upper !== undefined) { + number = number <= upper ? number : upper; + } + if (lower !== undefined) { + number = number >= lower ? number : lower; + } + } + return number; + } + + /** + * The base implementation of `_.clone` and `_.cloneDeep` which tracks + * traversed objects. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} bitmask The bitmask flags. + * 1 - Deep clone + * 2 - Flatten inherited properties + * 4 - Clone symbols + * @param {Function} [customizer] The function to customize cloning. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The parent object of `value`. + * @param {Object} [stack] Tracks traversed objects and their clone counterparts. + * @returns {*} Returns the cloned value. + */ + function baseClone(value, bitmask, customizer, key, object, stack) { + var result, + isDeep = bitmask & CLONE_DEEP_FLAG, + isFlat = bitmask & CLONE_FLAT_FLAG, + isFull = bitmask & CLONE_SYMBOLS_FLAG; + + if (customizer) { + result = object ? customizer(value, key, object, stack) : customizer(value); + } + if (result !== undefined) { + return result; + } + if (!isObject(value)) { + return value; + } + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return copyArray(value, result); + } + } else { + var tag = getTag(value), + isFunc = tag == funcTag || tag == genTag; + + if (isBuffer(value)) { + return cloneBuffer(value, isDeep); + } + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + result = (isFlat || isFunc) ? {} : initCloneObject(value); + if (!isDeep) { + return isFlat + ? copySymbolsIn(value, baseAssignIn(result, value)) + : copySymbols(value, baseAssign(result, value)); + } + } else { + if (!cloneableTags[tag]) { + return object ? value : {}; + } + result = initCloneByTag(value, tag, baseClone, isDeep); + } + } + // Check for circular references and return its corresponding clone. + stack || (stack = new Stack); + var stacked = stack.get(value); + if (stacked) { + return stacked; + } + stack.set(value, result); + + var keysFunc = isFull + ? (isFlat ? getAllKeysIn : getAllKeys) + : (isFlat ? keysIn : keys); + + var props = isArr ? undefined : keysFunc(value); + arrayEach(props || value, function(subValue, key) { + if (props) { + key = subValue; + subValue = value[key]; + } + // Recursively populate clone (susceptible to call stack limits). + assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + return result; + } + + /** + * The base implementation of `_.conforms` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property predicates to conform to. + * @returns {Function} Returns the new spec function. + */ + function baseConforms(source) { + var props = keys(source); + return function(object) { + return baseConformsTo(object, source, props); + }; + } + + /** + * The base implementation of `_.conformsTo` which accepts `props` to check. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property predicates to conform to. + * @returns {boolean} Returns `true` if `object` conforms, else `false`. + */ + function baseConformsTo(object, source, props) { + var length = props.length; + if (object == null) { + return !length; + } + object = Object(object); + while (length--) { + var key = props[length], + predicate = source[key], + value = object[key]; + + if ((value === undefined && !(key in object)) || !predicate(value)) { + return false; + } + } + return true; + } + + /** + * The base implementation of `_.delay` and `_.defer` which accepts `args` + * to provide to `func`. + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {Array} args The arguments to provide to `func`. + * @returns {number|Object} Returns the timer id or timeout object. + */ + function baseDelay(func, wait, args) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return setTimeout(function() { func.apply(undefined, args); }, wait); + } + + /** + * The base implementation of methods like `_.difference` without support + * for excluding multiple arrays or iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Array} values The values to exclude. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + */ + function baseDifference(array, values, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + isCommon = true, + length = array.length, + result = [], + valuesLength = values.length; + + if (!length) { + return result; + } + if (iteratee) { + values = arrayMap(values, baseUnary(iteratee)); + } + if (comparator) { + includes = arrayIncludesWith; + isCommon = false; + } + else if (values.length >= LARGE_ARRAY_SIZE) { + includes = cacheHas; + isCommon = false; + values = new SetCache(values); + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee == null ? value : iteratee(value); + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var valuesIndex = valuesLength; + while (valuesIndex--) { + if (values[valuesIndex] === computed) { + continue outer; + } + } + result.push(value); + } + else if (!includes(values, computed, comparator)) { + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.forEach` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + */ + var baseEach = createBaseEach(baseForOwn); + + /** + * The base implementation of `_.forEachRight` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + */ + var baseEachRight = createBaseEach(baseForOwnRight, true); + + /** + * The base implementation of `_.every` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false` + */ + function baseEvery(collection, predicate) { + var result = true; + baseEach(collection, function(value, index, collection) { + result = !!predicate(value, index, collection); + return result; + }); + return result; + } + + /** + * The base implementation of methods like `_.max` and `_.min` which accepts a + * `comparator` to determine the extremum value. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The iteratee invoked per iteration. + * @param {Function} comparator The comparator used to compare values. + * @returns {*} Returns the extremum value. + */ + function baseExtremum(array, iteratee, comparator) { + var index = -1, + length = array.length; + + while (++index < length) { + var value = array[index], + current = iteratee(value); + + if (current != null && (computed === undefined + ? (current === current && !isSymbol(current)) + : comparator(current, computed) + )) { + var computed = current, + result = value; + } + } + return result; + } + + /** + * The base implementation of `_.fill` without an iteratee call guard. + * + * @private + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + */ + function baseFill(array, value, start, end) { + var length = array.length; + + start = toInteger(start); + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = (end === undefined || end > length) ? length : toInteger(end); + if (end < 0) { + end += length; + } + end = start > end ? 0 : toLength(end); + while (start < end) { + array[start++] = value; + } + return array; + } + + /** + * The base implementation of `_.filter` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function baseFilter(collection, predicate) { + var result = []; + baseEach(collection, function(value, index, collection) { + if (predicate(value, index, collection)) { + result.push(value); + } + }); + return result; + } + + /** + * The base implementation of `_.flatten` with support for restricting flattening. + * + * @private + * @param {Array} array The array to flatten. + * @param {number} depth The maximum recursion depth. + * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. + * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. + * @param {Array} [result=[]] The initial result value. + * @returns {Array} Returns the new flattened array. + */ + function baseFlatten(array, depth, predicate, isStrict, result) { + var index = -1, + length = array.length; + + predicate || (predicate = isFlattenable); + result || (result = []); + + while (++index < length) { + var value = array[index]; + if (depth > 0 && predicate(value)) { + if (depth > 1) { + // Recursively flatten arrays (susceptible to call stack limits). + baseFlatten(value, depth - 1, predicate, isStrict, result); + } else { + arrayPush(result, value); + } + } else if (!isStrict) { + result[result.length] = value; + } + } + return result; + } + + /** + * The base implementation of `baseForOwn` which iterates over `object` + * properties returned by `keysFunc` and invokes `iteratee` for each property. + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseFor = createBaseFor(); + + /** + * This function is like `baseFor` except that it iterates over properties + * in the opposite order. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseForRight = createBaseFor(true); + + /** + * The base implementation of `_.forOwn` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwn(object, iteratee) { + return object && baseFor(object, iteratee, keys); + } + + /** + * The base implementation of `_.forOwnRight` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwnRight(object, iteratee) { + return object && baseForRight(object, iteratee, keys); + } + + /** + * The base implementation of `_.functions` which creates an array of + * `object` function property names filtered from `props`. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} props The property names to filter. + * @returns {Array} Returns the function names. + */ + function baseFunctions(object, props) { + return arrayFilter(props, function(key) { + return isFunction(object[key]); + }); + } + + /** + * The base implementation of `_.get` without support for default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. + */ + function baseGet(object, path) { + path = castPath(path, object); + + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; + } + + /** + * The base implementation of `getAllKeys` and `getAllKeysIn` which uses + * `keysFunc` and `symbolsFunc` to get the enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Function} keysFunc The function to get the keys of `object`. + * @param {Function} symbolsFunc The function to get the symbols of `object`. + * @returns {Array} Returns the array of property names and symbols. + */ + function baseGetAllKeys(object, keysFunc, symbolsFunc) { + var result = keysFunc(object); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); + } + + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); + } + + /** + * The base implementation of `_.gt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, + * else `false`. + */ + function baseGt(value, other) { + return value > other; + } + + /** + * The base implementation of `_.has` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHas(object, key) { + return object != null && hasOwnProperty.call(object, key); + } + + /** + * The base implementation of `_.hasIn` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHasIn(object, key) { + return object != null && key in Object(object); + } + + /** + * The base implementation of `_.inRange` which doesn't coerce arguments. + * + * @private + * @param {number} number The number to check. + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @returns {boolean} Returns `true` if `number` is in the range, else `false`. + */ + function baseInRange(number, start, end) { + return number >= nativeMin(start, end) && number < nativeMax(start, end); + } + + /** + * The base implementation of methods like `_.intersection`, without support + * for iteratee shorthands, that accepts an array of arrays to inspect. + * + * @private + * @param {Array} arrays The arrays to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of shared values. + */ + function baseIntersection(arrays, iteratee, comparator) { + var includes = comparator ? arrayIncludesWith : arrayIncludes, + length = arrays[0].length, + othLength = arrays.length, + othIndex = othLength, + caches = Array(othLength), + maxLength = Infinity, + result = []; + + while (othIndex--) { + var array = arrays[othIndex]; + if (othIndex && iteratee) { + array = arrayMap(array, baseUnary(iteratee)); + } + maxLength = nativeMin(array.length, maxLength); + caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) + ? new SetCache(othIndex && array) + : undefined; + } + array = arrays[0]; + + var index = -1, + seen = caches[0]; + + outer: + while (++index < length && result.length < maxLength) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (!(seen + ? cacheHas(seen, computed) + : includes(result, computed, comparator) + )) { + othIndex = othLength; + while (--othIndex) { + var cache = caches[othIndex]; + if (!(cache + ? cacheHas(cache, computed) + : includes(arrays[othIndex], computed, comparator)) + ) { + continue outer; + } + } + if (seen) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.invert` and `_.invertBy` which inverts + * `object` with values transformed by `iteratee` and set by `setter`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform values. + * @param {Object} accumulator The initial inverted object. + * @returns {Function} Returns `accumulator`. + */ + function baseInverter(object, setter, iteratee, accumulator) { + baseForOwn(object, function(value, key, object) { + setter(accumulator, iteratee(value), key, object); + }); + return accumulator; + } + + /** + * The base implementation of `_.invoke` without support for individual + * method arguments. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {Array} args The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + */ + function baseInvoke(object, path, args) { + path = castPath(path, object); + object = parent(object, path); + var func = object == null ? object : object[toKey(last(path))]; + return func == null ? undefined : apply(func, object, args); + } + + /** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ + function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; + } + + /** + * The base implementation of `_.isArrayBuffer` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. + */ + function baseIsArrayBuffer(value) { + return isObjectLike(value) && baseGetTag(value) == arrayBufferTag; + } + + /** + * The base implementation of `_.isDate` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + */ + function baseIsDate(value) { + return isObjectLike(value) && baseGetTag(value) == dateTag; + } + + /** + * The base implementation of `_.isEqual` which supports partial comparisons + * and tracks traversed objects. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {boolean} bitmask The bitmask flags. + * 1 - Unordered comparison + * 2 - Partial comparison + * @param {Function} [customizer] The function to customize comparisons. + * @param {Object} [stack] Tracks traversed `value` and `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ + function baseIsEqual(value, other, bitmask, customizer, stack) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); + } + + /** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} [stack] Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = objIsArr ? arrayTag : getTag(object), + othTag = othIsArr ? arrayTag : getTag(other); + + objTag = objTag == argsTag ? objectTag : objTag; + othTag = othTag == argsTag ? objectTag : othTag; + + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, + isSameTag = objTag == othTag; + + if (isSameTag && isBuffer(object)) { + if (!isBuffer(other)) { + return false; + } + objIsArr = true; + objIsObj = false; + } + if (isSameTag && !objIsObj) { + stack || (stack = new Stack); + return (objIsArr || isTypedArray(object)) + ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) + : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); + } + if (!(bitmask & COMPARE_PARTIAL_FLAG)) { + var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + var objUnwrapped = objIsWrapped ? object.value() : object, + othUnwrapped = othIsWrapped ? other.value() : other; + + stack || (stack = new Stack); + return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); + } + } + if (!isSameTag) { + return false; + } + stack || (stack = new Stack); + return equalObjects(object, other, bitmask, customizer, equalFunc, stack); + } + + /** + * The base implementation of `_.isMap` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + */ + function baseIsMap(value) { + return isObjectLike(value) && getTag(value) == mapTag; + } + + /** + * The base implementation of `_.isMatch` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Array} matchData The property names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ + function baseIsMatch(object, source, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = Object(object); + while (index--) { + var data = matchData[index]; + if ((noCustomizer && data[2]) + ? data[1] !== object[data[0]] + : !(data[0] in object) + ) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var stack = new Stack; + if (customizer) { + var result = customizer(objValue, srcValue, key, object, source, stack); + } + if (!(result === undefined + ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) + : result + )) { + return false; + } + } + } + return true; + } + + /** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ + function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); + } + + /** + * The base implementation of `_.isRegExp` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + */ + function baseIsRegExp(value) { + return isObjectLike(value) && baseGetTag(value) == regexpTag; + } + + /** + * The base implementation of `_.isSet` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + */ + function baseIsSet(value) { + return isObjectLike(value) && getTag(value) == setTag; + } + + /** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ + function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; + } + + /** + * The base implementation of `_.iteratee`. + * + * @private + * @param {*} [value=_.identity] The value to convert to an iteratee. + * @returns {Function} Returns the iteratee. + */ + function baseIteratee(value) { + // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. + // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. + if (typeof value == 'function') { + return value; + } + if (value == null) { + return identity; + } + if (typeof value == 'object') { + return isArray(value) + ? baseMatchesProperty(value[0], value[1]) + : baseMatches(value); + } + return property(value); + } + + /** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); + } + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty.call(object, key) && key != 'constructor') { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.lt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, + * else `false`. + */ + function baseLt(value, other) { + return value < other; + } + + /** + * The base implementation of `_.map` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function baseMap(collection, iteratee) { + var index = -1, + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value, key, collection) { + result[++index] = iteratee(value, key, collection); + }); + return result; + } + + /** + * The base implementation of `_.matches` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + return matchesStrictComparable(matchData[0][0], matchData[0][1]); + } + return function(object) { + return object === source || baseIsMatch(object, source, matchData); + }; + } + + /** + * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatchesProperty(path, srcValue) { + if (isKey(path) && isStrictComparable(srcValue)) { + return matchesStrictComparable(toKey(path), srcValue); + } + return function(object) { + var objValue = get(object, path); + return (objValue === undefined && objValue === srcValue) + ? hasIn(object, path) + : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); + }; + } + + /** + * The base implementation of `_.merge` without support for multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {number} srcIndex The index of `source`. + * @param {Function} [customizer] The function to customize merged values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMerge(object, source, srcIndex, customizer, stack) { + if (object === source) { + return; + } + baseFor(source, function(srcValue, key) { + if (isObject(srcValue)) { + stack || (stack = new Stack); + baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + } + else { + var newValue = customizer + ? customizer(object[key], srcValue, (key + ''), object, source, stack) + : undefined; + + if (newValue === undefined) { + newValue = srcValue; + } + assignMergeValue(object, key, newValue); + } + }, keysIn); + } + + /** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {number} srcIndex The index of `source`. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize assigned values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { + var objValue = object[key], + srcValue = source[key], + stacked = stack.get(srcValue); + + if (stacked) { + assignMergeValue(object, key, stacked); + return; + } + var newValue = customizer + ? customizer(objValue, srcValue, (key + ''), object, source, stack) + : undefined; + + var isCommon = newValue === undefined; + + if (isCommon) { + var isArr = isArray(srcValue), + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); + + newValue = srcValue; + if (isArr || isBuff || isTyped) { + if (isArray(objValue)) { + newValue = objValue; + } + else if (isArrayLikeObject(objValue)) { + newValue = copyArray(objValue); + } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } + else if (isTyped) { + isCommon = false; + newValue = cloneTypedArray(srcValue, true); + } + else { + newValue = []; + } + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + newValue = objValue; + if (isArguments(objValue)) { + newValue = toPlainObject(objValue); + } + else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { + newValue = initCloneObject(srcValue); + } + } + else { + isCommon = false; + } + } + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, newValue); + mergeFunc(newValue, srcValue, srcIndex, customizer, stack); + stack['delete'](srcValue); + } + assignMergeValue(object, key, newValue); + } + + /** + * The base implementation of `_.nth` which doesn't coerce arguments. + * + * @private + * @param {Array} array The array to query. + * @param {number} n The index of the element to return. + * @returns {*} Returns the nth element of `array`. + */ + function baseNth(array, n) { + var length = array.length; + if (!length) { + return; + } + n += n < 0 ? length : 0; + return isIndex(n, length) ? array[n] : undefined; + } + + /** + * The base implementation of `_.orderBy` without param guards. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. + * @param {string[]} orders The sort orders of `iteratees`. + * @returns {Array} Returns the new sorted array. + */ + function baseOrderBy(collection, iteratees, orders) { + var index = -1; + iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee())); + + var result = baseMap(collection, function(value, key, collection) { + var criteria = arrayMap(iteratees, function(iteratee) { + return iteratee(value); + }); + return { 'criteria': criteria, 'index': ++index, 'value': value }; + }); + + return baseSortBy(result, function(object, other) { + return compareMultiple(object, other, orders); + }); + } + + /** + * The base implementation of `_.pick` without support for individual + * property identifiers. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @returns {Object} Returns the new object. + */ + function basePick(object, paths) { + return basePickBy(object, paths, function(value, path) { + return hasIn(object, path); + }); + } + + /** + * The base implementation of `_.pickBy` without support for iteratee shorthands. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @param {Function} predicate The function invoked per property. + * @returns {Object} Returns the new object. + */ + function basePickBy(object, paths, predicate) { + var index = -1, + length = paths.length, + result = {}; + + while (++index < length) { + var path = paths[index], + value = baseGet(object, path); + + if (predicate(value, path)) { + baseSet(result, castPath(path, object), value); + } + } + return result; + } + + /** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyDeep(path) { + return function(object) { + return baseGet(object, path); + }; + } + + /** + * The base implementation of `_.pullAllBy` without support for iteratee + * shorthands. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns `array`. + */ + function basePullAll(array, values, iteratee, comparator) { + var indexOf = comparator ? baseIndexOfWith : baseIndexOf, + index = -1, + length = values.length, + seen = array; + + if (array === values) { + values = copyArray(values); + } + if (iteratee) { + seen = arrayMap(array, baseUnary(iteratee)); + } + while (++index < length) { + var fromIndex = 0, + value = values[index], + computed = iteratee ? iteratee(value) : value; + + while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) { + if (seen !== array) { + splice.call(seen, fromIndex, 1); + } + splice.call(array, fromIndex, 1); + } + } + return array; + } + + /** + * The base implementation of `_.pullAt` without support for individual + * indexes or capturing the removed elements. + * + * @private + * @param {Array} array The array to modify. + * @param {number[]} indexes The indexes of elements to remove. + * @returns {Array} Returns `array`. + */ + function basePullAt(array, indexes) { + var length = array ? indexes.length : 0, + lastIndex = length - 1; + + while (length--) { + var index = indexes[length]; + if (length == lastIndex || index !== previous) { + var previous = index; + if (isIndex(index)) { + splice.call(array, index, 1); + } else { + baseUnset(array, index); + } + } + } + return array; + } + + /** + * The base implementation of `_.random` without support for returning + * floating-point numbers. + * + * @private + * @param {number} lower The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the random number. + */ + function baseRandom(lower, upper) { + return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); + } + + /** + * The base implementation of `_.range` and `_.rangeRight` which doesn't + * coerce arguments. + * + * @private + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @param {number} step The value to increment or decrement by. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the range of numbers. + */ + function baseRange(start, end, step, fromRight) { + var index = -1, + length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), + result = Array(length); + + while (length--) { + result[fromRight ? length : ++index] = start; + start += step; + } + return result; + } + + /** + * The base implementation of `_.repeat` which doesn't coerce arguments. + * + * @private + * @param {string} string The string to repeat. + * @param {number} n The number of times to repeat the string. + * @returns {string} Returns the repeated string. + */ + function baseRepeat(string, n) { + var result = ''; + if (!string || n < 1 || n > MAX_SAFE_INTEGER) { + return result; + } + // Leverage the exponentiation by squaring algorithm for a faster repeat. + // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. + do { + if (n % 2) { + result += string; + } + n = nativeFloor(n / 2); + if (n) { + string += string; + } + } while (n); + + return result; + } + + /** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ + function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); + } + + /** + * The base implementation of `_.sample`. + * + * @private + * @param {Array|Object} collection The collection to sample. + * @returns {*} Returns the random element. + */ + function baseSample(collection) { + return arraySample(values(collection)); + } + + /** + * The base implementation of `_.sampleSize` without param guards. + * + * @private + * @param {Array|Object} collection The collection to sample. + * @param {number} n The number of elements to sample. + * @returns {Array} Returns the random elements. + */ + function baseSampleSize(collection, n) { + var array = values(collection); + return shuffleSelf(array, baseClamp(n, 0, array.length)); + } + + /** + * The base implementation of `_.set`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseSet(object, path, value, customizer) { + if (!isObject(object)) { + return object; + } + path = castPath(path, object); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = toKey(path[index]), + newValue = value; + + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject(objValue) + ? objValue + : (isIndex(path[index + 1]) ? [] : {}); + } + } + assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; + } + + /** + * The base implementation of `setData` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var baseSetData = !metaMap ? identity : function(func, data) { + metaMap.set(func, data); + return func; + }; + + /** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); + }; + + /** + * The base implementation of `_.shuffle`. + * + * @private + * @param {Array|Object} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + */ + function baseShuffle(collection) { + return shuffleSelf(values(collection)); + } + + /** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = end > length ? length : end; + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; + } + + /** + * The base implementation of `_.some` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function baseSome(collection, predicate) { + var result; + + baseEach(collection, function(value, index, collection) { + result = predicate(value, index, collection); + return !result; + }); + return !!result; + } + + /** + * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which + * performs a binary search of `array` to determine the index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function baseSortedIndex(array, value, retHighest) { + var low = 0, + high = array == null ? low : array.length; + + if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { + while (low < high) { + var mid = (low + high) >>> 1, + computed = array[mid]; + + if (computed !== null && !isSymbol(computed) && + (retHighest ? (computed <= value) : (computed < value))) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + return baseSortedIndexBy(array, value, identity, retHighest); + } + + /** + * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` + * which invokes `iteratee` for `value` and each element of `array` to compute + * their sort ranking. The iteratee is invoked with one argument; (value). + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} iteratee The iteratee invoked per element. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function baseSortedIndexBy(array, value, iteratee, retHighest) { + value = iteratee(value); + + var low = 0, + high = array == null ? 0 : array.length, + valIsNaN = value !== value, + valIsNull = value === null, + valIsSymbol = isSymbol(value), + valIsUndefined = value === undefined; + + while (low < high) { + var mid = nativeFloor((low + high) / 2), + computed = iteratee(array[mid]), + othIsDefined = computed !== undefined, + othIsNull = computed === null, + othIsReflexive = computed === computed, + othIsSymbol = isSymbol(computed); + + if (valIsNaN) { + var setLow = retHighest || othIsReflexive; + } else if (valIsUndefined) { + setLow = othIsReflexive && (retHighest || othIsDefined); + } else if (valIsNull) { + setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull); + } else if (valIsSymbol) { + setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol); + } else if (othIsNull || othIsSymbol) { + setLow = false; + } else { + setLow = retHighest ? (computed <= value) : (computed < value); + } + if (setLow) { + low = mid + 1; + } else { + high = mid; + } + } + return nativeMin(high, MAX_ARRAY_INDEX); + } + + /** + * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + */ + function baseSortedUniq(array, iteratee) { + var index = -1, + length = array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + if (!index || !eq(computed, seen)) { + var seen = computed; + result[resIndex++] = value === 0 ? 0 : value; + } + } + return result; + } + + /** + * The base implementation of `_.toNumber` which doesn't ensure correct + * conversions of binary, hexadecimal, or octal string values. + * + * @private + * @param {*} value The value to process. + * @returns {number} Returns the number. + */ + function baseToNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + return +value; + } + + /** + * The base implementation of `_.toString` which doesn't convert nullish + * values to empty strings. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ + function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * The base implementation of `_.uniqBy` without support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + */ + function baseUniq(array, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + length = array.length, + isCommon = true, + result = [], + seen = result; + + if (comparator) { + isCommon = false; + includes = arrayIncludesWith; + } + else if (length >= LARGE_ARRAY_SIZE) { + var set = iteratee ? null : createSet(array); + if (set) { + return setToArray(set); + } + isCommon = false; + includes = cacheHas; + seen = new SetCache; + } + else { + seen = iteratee ? [] : result; + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var seenIndex = seen.length; + while (seenIndex--) { + if (seen[seenIndex] === computed) { + continue outer; + } + } + if (iteratee) { + seen.push(computed); + } + result.push(value); + } + else if (!includes(seen, computed, comparator)) { + if (seen !== result) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.unset`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The property path to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + */ + function baseUnset(object, path) { + path = castPath(path, object); + object = parent(object, path); + return object == null || delete object[toKey(last(path))]; + } + + /** + * The base implementation of `_.update`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to update. + * @param {Function} updater The function to produce the updated value. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseUpdate(object, path, updater, customizer) { + return baseSet(object, path, updater(baseGet(object, path)), customizer); + } + + /** + * The base implementation of methods like `_.dropWhile` and `_.takeWhile` + * without support for iteratee shorthands. + * + * @private + * @param {Array} array The array to query. + * @param {Function} predicate The function invoked per iteration. + * @param {boolean} [isDrop] Specify dropping elements instead of taking them. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the slice of `array`. + */ + function baseWhile(array, predicate, isDrop, fromRight) { + var length = array.length, + index = fromRight ? length : -1; + + while ((fromRight ? index-- : ++index < length) && + predicate(array[index], index, array)) {} + + return isDrop + ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) + : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); + } + + /** + * The base implementation of `wrapperValue` which returns the result of + * performing a sequence of actions on the unwrapped `value`, where each + * successive action is supplied the return value of the previous. + * + * @private + * @param {*} value The unwrapped value. + * @param {Array} actions Actions to perform to resolve the unwrapped value. + * @returns {*} Returns the resolved value. + */ + function baseWrapperValue(value, actions) { + var result = value; + if (result instanceof LazyWrapper) { + result = result.value(); + } + return arrayReduce(actions, function(result, action) { + return action.func.apply(action.thisArg, arrayPush([result], action.args)); + }, result); + } + + /** + * The base implementation of methods like `_.xor`, without support for + * iteratee shorthands, that accepts an array of arrays to inspect. + * + * @private + * @param {Array} arrays The arrays to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of values. + */ + function baseXor(arrays, iteratee, comparator) { + var length = arrays.length; + if (length < 2) { + return length ? baseUniq(arrays[0]) : []; + } + var index = -1, + result = Array(length); + + while (++index < length) { + var array = arrays[index], + othIndex = -1; + + while (++othIndex < length) { + if (othIndex != index) { + result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator); + } + } + } + return baseUniq(baseFlatten(result, 1), iteratee, comparator); + } + + /** + * This base implementation of `_.zipObject` which assigns values using `assignFunc`. + * + * @private + * @param {Array} props The property identifiers. + * @param {Array} values The property values. + * @param {Function} assignFunc The function to assign values. + * @returns {Object} Returns the new object. + */ + function baseZipObject(props, values, assignFunc) { + var index = -1, + length = props.length, + valsLength = values.length, + result = {}; + + while (++index < length) { + var value = index < valsLength ? values[index] : undefined; + assignFunc(result, props[index], value); + } + return result; + } + + /** + * Casts `value` to an empty array if it's not an array like object. + * + * @private + * @param {*} value The value to inspect. + * @returns {Array|Object} Returns the cast array-like object. + */ + function castArrayLikeObject(value) { + return isArrayLikeObject(value) ? value : []; + } + + /** + * Casts `value` to `identity` if it's not a function. + * + * @private + * @param {*} value The value to inspect. + * @returns {Function} Returns cast function. + */ + function castFunction(value) { + return typeof value == 'function' ? value : identity; + } + + /** + * Casts `value` to a path array if it's not one. + * + * @private + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. + */ + function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); + } + + /** + * A `baseRest` alias which can be replaced with `identity` by module + * replacement plugins. + * + * @private + * @type {Function} + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. + */ + var castRest = baseRest; + + /** + * Casts `array` to a slice if it's needed. + * + * @private + * @param {Array} array The array to inspect. + * @param {number} start The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the cast slice. + */ + function castSlice(array, start, end) { + var length = array.length; + end = end === undefined ? length : end; + return (!start && end >= length) ? array : baseSlice(array, start, end); + } + + /** + * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout). + * + * @private + * @param {number|Object} id The timer id or timeout object of the timer to clear. + */ + var clearTimeout = ctxClearTimeout || function(id) { + return root.clearTimeout(id); + }; + + /** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ + function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var length = buffer.length, + result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + + buffer.copy(result); + return result; + } + + /** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ + function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; + } + + /** + * Creates a clone of `dataView`. + * + * @private + * @param {Object} dataView The data view to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned data view. + */ + function cloneDataView(dataView, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; + return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); + } + + /** + * Creates a clone of `map`. + * + * @private + * @param {Object} map The map to clone. + * @param {Function} cloneFunc The function to clone values. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned map. + */ + function cloneMap(map, isDeep, cloneFunc) { + var array = isDeep ? cloneFunc(mapToArray(map), CLONE_DEEP_FLAG) : mapToArray(map); + return arrayReduce(array, addMapEntry, new map.constructor); + } + + /** + * Creates a clone of `regexp`. + * + * @private + * @param {Object} regexp The regexp to clone. + * @returns {Object} Returns the cloned regexp. + */ + function cloneRegExp(regexp) { + var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); + result.lastIndex = regexp.lastIndex; + return result; + } + + /** + * Creates a clone of `set`. + * + * @private + * @param {Object} set The set to clone. + * @param {Function} cloneFunc The function to clone values. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned set. + */ + function cloneSet(set, isDeep, cloneFunc) { + var array = isDeep ? cloneFunc(setToArray(set), CLONE_DEEP_FLAG) : setToArray(set); + return arrayReduce(array, addSetEntry, new set.constructor); + } + + /** + * Creates a clone of the `symbol` object. + * + * @private + * @param {Object} symbol The symbol object to clone. + * @returns {Object} Returns the cloned symbol object. + */ + function cloneSymbol(symbol) { + return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; + } + + /** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ + function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); + } + + /** + * Compares values to sort them in ascending order. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {number} Returns the sort order indicator for `value`. + */ + function compareAscending(value, other) { + if (value !== other) { + var valIsDefined = value !== undefined, + valIsNull = value === null, + valIsReflexive = value === value, + valIsSymbol = isSymbol(value); + + var othIsDefined = other !== undefined, + othIsNull = other === null, + othIsReflexive = other === other, + othIsSymbol = isSymbol(other); + + if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || + (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || + (valIsNull && othIsDefined && othIsReflexive) || + (!valIsDefined && othIsReflexive) || + !valIsReflexive) { + return 1; + } + if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || + (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || + (othIsNull && valIsDefined && valIsReflexive) || + (!othIsDefined && valIsReflexive) || + !othIsReflexive) { + return -1; + } + } + return 0; + } + + /** + * Used by `_.orderBy` to compare multiple properties of a value to another + * and stable sort them. + * + * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, + * specify an order of "desc" for descending or "asc" for ascending sort order + * of corresponding values. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {boolean[]|string[]} orders The order to sort by for each property. + * @returns {number} Returns the sort order indicator for `object`. + */ + function compareMultiple(object, other, orders) { + var index = -1, + objCriteria = object.criteria, + othCriteria = other.criteria, + length = objCriteria.length, + ordersLength = orders.length; + + while (++index < length) { + var result = compareAscending(objCriteria[index], othCriteria[index]); + if (result) { + if (index >= ordersLength) { + return result; + } + var order = orders[index]; + return result * (order == 'desc' ? -1 : 1); + } + } + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to provide the same value for + // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 + // for more details. + // + // This also ensures a stable sort in V8 and other engines. + // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. + return object.index - other.index; + } + + /** + * Creates an array that is the composition of partially applied arguments, + * placeholders, and provided arguments into a single array of arguments. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to prepend to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgs(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersLength = holders.length, + leftIndex = -1, + leftLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(leftLength + rangeLength), + isUncurried = !isCurried; + + while (++leftIndex < leftLength) { + result[leftIndex] = partials[leftIndex]; + } + while (++argsIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[holders[argsIndex]] = args[argsIndex]; + } + } + while (rangeLength--) { + result[leftIndex++] = args[argsIndex++]; + } + return result; + } + + /** + * This function is like `composeArgs` except that the arguments composition + * is tailored for `_.partialRight`. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to append to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgsRight(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersIndex = -1, + holdersLength = holders.length, + rightIndex = -1, + rightLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(rangeLength + rightLength), + isUncurried = !isCurried; + + while (++argsIndex < rangeLength) { + result[argsIndex] = args[argsIndex]; + } + var offset = argsIndex; + while (++rightIndex < rightLength) { + result[offset + rightIndex] = partials[rightIndex]; + } + while (++holdersIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[offset + holders[holdersIndex]] = args[argsIndex++]; + } + } + return result; + } + + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } + + /** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ + function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; + } + + /** + * Copies own symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbols(source, object) { + return copyObject(source, getSymbols(source), object); + } + + /** + * Copies own and inherited symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbolsIn(source, object) { + return copyObject(source, getSymbolsIn(source), object); + } + + /** + * Creates a function like `_.groupBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} [initializer] The accumulator object initializer. + * @returns {Function} Returns the new aggregator function. + */ + function createAggregator(setter, initializer) { + return function(collection, iteratee) { + var func = isArray(collection) ? arrayAggregator : baseAggregator, + accumulator = initializer ? initializer() : {}; + + return func(collection, setter, getIteratee(iteratee, 2), accumulator); + }; + } + + /** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ + function createAssigner(assigner) { + return baseRest(function(object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); + } + + /** + * Creates a `baseEach` or `baseEachRight` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseEach(eachFunc, fromRight) { + return function(collection, iteratee) { + if (collection == null) { + return collection; + } + if (!isArrayLike(collection)) { + return eachFunc(collection, iteratee); + } + var length = collection.length, + index = fromRight ? length : -1, + iterable = Object(collection); + + while ((fromRight ? index-- : ++index < length)) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; + }; + } + + /** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; + } + + /** + * Creates a function that wraps `func` to invoke it with the optional `this` + * binding of `thisArg`. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createBind(func, bitmask, thisArg) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return fn.apply(isBind ? thisArg : this, arguments); + } + return wrapper; + } + + /** + * Creates a function like `_.lowerFirst`. + * + * @private + * @param {string} methodName The name of the `String` case method to use. + * @returns {Function} Returns the new case function. + */ + function createCaseFirst(methodName) { + return function(string) { + string = toString(string); + + var strSymbols = hasUnicode(string) + ? stringToArray(string) + : undefined; + + var chr = strSymbols + ? strSymbols[0] + : string.charAt(0); + + var trailing = strSymbols + ? castSlice(strSymbols, 1).join('') + : string.slice(1); + + return chr[methodName]() + trailing; + }; + } + + /** + * Creates a function like `_.camelCase`. + * + * @private + * @param {Function} callback The function to combine each word. + * @returns {Function} Returns the new compounder function. + */ + function createCompounder(callback) { + return function(string) { + return arrayReduce(words(deburr(string).replace(reApos, '')), callback, ''); + }; + } + + /** + * Creates a function that produces an instance of `Ctor` regardless of + * whether it was invoked as part of a `new` expression or by `call` or `apply`. + * + * @private + * @param {Function} Ctor The constructor to wrap. + * @returns {Function} Returns the new wrapped function. + */ + function createCtor(Ctor) { + return function() { + // Use a `switch` statement to work with class constructors. See + // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist + // for more details. + var args = arguments; + switch (args.length) { + case 0: return new Ctor; + case 1: return new Ctor(args[0]); + case 2: return new Ctor(args[0], args[1]); + case 3: return new Ctor(args[0], args[1], args[2]); + case 4: return new Ctor(args[0], args[1], args[2], args[3]); + case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); + case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + } + var thisBinding = baseCreate(Ctor.prototype), + result = Ctor.apply(thisBinding, args); + + // Mimic the constructor's `return` behavior. + // See https://es5.github.io/#x13.2.2 for more details. + return isObject(result) ? result : thisBinding; + }; + } + + /** + * Creates a function that wraps `func` to enable currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {number} arity The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createCurry(func, bitmask, arity) { + var Ctor = createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length, + placeholder = getHolder(wrapper); + + while (index--) { + args[index] = arguments[index]; + } + var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) + ? [] + : replaceHolders(args, placeholder); + + length -= holders.length; + if (length < arity) { + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, undefined, + args, holders, undefined, undefined, arity - length); + } + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return apply(fn, this, args); + } + return wrapper; + } + + /** + * Creates a `_.find` or `_.findLast` function. + * + * @private + * @param {Function} findIndexFunc The function to find the collection index. + * @returns {Function} Returns the new find function. + */ + function createFind(findIndexFunc) { + return function(collection, predicate, fromIndex) { + var iterable = Object(collection); + if (!isArrayLike(collection)) { + var iteratee = getIteratee(predicate, 3); + collection = keys(collection); + predicate = function(key) { return iteratee(iterable[key], key, iterable); }; + } + var index = findIndexFunc(collection, predicate, fromIndex); + return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; + }; + } + + /** + * Creates a `_.flow` or `_.flowRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new flow function. + */ + function createFlow(fromRight) { + return flatRest(function(funcs) { + var length = funcs.length, + index = length, + prereq = LodashWrapper.prototype.thru; + + if (fromRight) { + funcs.reverse(); + } + while (index--) { + var func = funcs[index]; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (prereq && !wrapper && getFuncName(func) == 'wrapper') { + var wrapper = new LodashWrapper([], true); + } + } + index = wrapper ? index : length; + while (++index < length) { + func = funcs[index]; + + var funcName = getFuncName(func), + data = funcName == 'wrapper' ? getData(func) : undefined; + + if (data && isLaziable(data[0]) && + data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) && + !data[4].length && data[9] == 1 + ) { + wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); + } else { + wrapper = (func.length == 1 && isLaziable(func)) + ? wrapper[funcName]() + : wrapper.thru(func); + } + } + return function() { + var args = arguments, + value = args[0]; + + if (wrapper && args.length == 1 && isArray(value)) { + return wrapper.plant(value).value(); + } + var index = 0, + result = length ? funcs[index].apply(this, args) : value; + + while (++index < length) { + result = funcs[index].call(this, result); + } + return result; + }; + }); + } + + /** + * Creates a function that wraps `func` to invoke it with optional `this` + * binding of `thisArg`, partial application, and currying. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [partialsRight] The arguments to append to those provided + * to the new function. + * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { + var isAry = bitmask & WRAP_ARY_FLAG, + isBind = bitmask & WRAP_BIND_FLAG, + isBindKey = bitmask & WRAP_BIND_KEY_FLAG, + isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), + isFlip = bitmask & WRAP_FLIP_FLAG, + Ctor = isBindKey ? undefined : createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length; + + while (index--) { + args[index] = arguments[index]; + } + if (isCurried) { + var placeholder = getHolder(wrapper), + holdersCount = countHolders(args, placeholder); + } + if (partials) { + args = composeArgs(args, partials, holders, isCurried); + } + if (partialsRight) { + args = composeArgsRight(args, partialsRight, holdersRight, isCurried); + } + length -= holdersCount; + if (isCurried && length < arity) { + var newHolders = replaceHolders(args, placeholder); + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, thisArg, + args, newHolders, argPos, ary, arity - length + ); + } + var thisBinding = isBind ? thisArg : this, + fn = isBindKey ? thisBinding[func] : func; + + length = args.length; + if (argPos) { + args = reorder(args, argPos); + } else if (isFlip && length > 1) { + args.reverse(); + } + if (isAry && ary < length) { + args.length = ary; + } + if (this && this !== root && this instanceof wrapper) { + fn = Ctor || createCtor(fn); + } + return fn.apply(thisBinding, args); + } + return wrapper; + } + + /** + * Creates a function like `_.invertBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} toIteratee The function to resolve iteratees. + * @returns {Function} Returns the new inverter function. + */ + function createInverter(setter, toIteratee) { + return function(object, iteratee) { + return baseInverter(object, setter, toIteratee(iteratee), {}); + }; + } + + /** + * Creates a function that performs a mathematical operation on two values. + * + * @private + * @param {Function} operator The function to perform the operation. + * @param {number} [defaultValue] The value used for `undefined` arguments. + * @returns {Function} Returns the new mathematical operation function. + */ + function createMathOperation(operator, defaultValue) { + return function(value, other) { + var result; + if (value === undefined && other === undefined) { + return defaultValue; + } + if (value !== undefined) { + result = value; + } + if (other !== undefined) { + if (result === undefined) { + return other; + } + if (typeof value == 'string' || typeof other == 'string') { + value = baseToString(value); + other = baseToString(other); + } else { + value = baseToNumber(value); + other = baseToNumber(other); + } + result = operator(value, other); + } + return result; + }; + } + + /** + * Creates a function like `_.over`. + * + * @private + * @param {Function} arrayFunc The function to iterate over iteratees. + * @returns {Function} Returns the new over function. + */ + function createOver(arrayFunc) { + return flatRest(function(iteratees) { + iteratees = arrayMap(iteratees, baseUnary(getIteratee())); + return baseRest(function(args) { + var thisArg = this; + return arrayFunc(iteratees, function(iteratee) { + return apply(iteratee, thisArg, args); + }); + }); + }); + } + + /** + * Creates the padding for `string` based on `length`. The `chars` string + * is truncated if the number of characters exceeds `length`. + * + * @private + * @param {number} length The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padding for `string`. + */ + function createPadding(length, chars) { + chars = chars === undefined ? ' ' : baseToString(chars); + + var charsLength = chars.length; + if (charsLength < 2) { + return charsLength ? baseRepeat(chars, length) : chars; + } + var result = baseRepeat(chars, nativeCeil(length / stringSize(chars))); + return hasUnicode(chars) + ? castSlice(stringToArray(result), 0, length).join('') + : result.slice(0, length); + } + + /** + * Creates a function that wraps `func` to invoke it with the `this` binding + * of `thisArg` and `partials` prepended to the arguments it receives. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} partials The arguments to prepend to those provided to + * the new function. + * @returns {Function} Returns the new wrapped function. + */ + function createPartial(func, bitmask, thisArg, partials) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var argsIndex = -1, + argsLength = arguments.length, + leftIndex = -1, + leftLength = partials.length, + args = Array(leftLength + argsLength), + fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + + while (++leftIndex < leftLength) { + args[leftIndex] = partials[leftIndex]; + } + while (argsLength--) { + args[leftIndex++] = arguments[++argsIndex]; + } + return apply(fn, isBind ? thisArg : this, args); + } + return wrapper; + } + + /** + * Creates a `_.range` or `_.rangeRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new range function. + */ + function createRange(fromRight) { + return function(start, end, step) { + if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { + end = step = undefined; + } + // Ensure the sign of `-0` is preserved. + start = toFinite(start); + if (end === undefined) { + end = start; + start = 0; + } else { + end = toFinite(end); + } + step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); + return baseRange(start, end, step, fromRight); + }; + } + + /** + * Creates a function that performs a relational operation on two values. + * + * @private + * @param {Function} operator The function to perform the operation. + * @returns {Function} Returns the new relational operation function. + */ + function createRelationalOperation(operator) { + return function(value, other) { + if (!(typeof value == 'string' && typeof other == 'string')) { + value = toNumber(value); + other = toNumber(other); + } + return operator(value, other); + }; + } + + /** + * Creates a function that wraps `func` to continue currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {Function} wrapFunc The function to create the `func` wrapper. + * @param {*} placeholder The placeholder value. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { + var isCurry = bitmask & WRAP_CURRY_FLAG, + newHolders = isCurry ? holders : undefined, + newHoldersRight = isCurry ? undefined : holders, + newPartials = isCurry ? partials : undefined, + newPartialsRight = isCurry ? undefined : partials; + + bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG); + bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG); + + if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) { + bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG); + } + var newData = [ + func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, + newHoldersRight, argPos, ary, arity + ]; + + var result = wrapFunc.apply(undefined, newData); + if (isLaziable(func)) { + setData(result, newData); + } + result.placeholder = placeholder; + return setWrapToString(result, func, bitmask); + } + + /** + * Creates a function like `_.round`. + * + * @private + * @param {string} methodName The name of the `Math` method to use when rounding. + * @returns {Function} Returns the new round function. + */ + function createRound(methodName) { + var func = Math[methodName]; + return function(number, precision) { + number = toNumber(number); + precision = precision == null ? 0 : nativeMin(toInteger(precision), 292); + if (precision) { + // Shift with exponential notation to avoid floating-point issues. + // See [MDN](https://mdn.io/round#Examples) for more details. + var pair = (toString(number) + 'e').split('e'), + value = func(pair[0] + 'e' + (+pair[1] + precision)); + + pair = (toString(value) + 'e').split('e'); + return +(pair[0] + 'e' + (+pair[1] - precision)); + } + return func(number); + }; + } + + /** + * Creates a set object of `values`. + * + * @private + * @param {Array} values The values to add to the set. + * @returns {Object} Returns the new set. + */ + var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { + return new Set(values); + }; + + /** + * Creates a `_.toPairs` or `_.toPairsIn` function. + * + * @private + * @param {Function} keysFunc The function to get the keys of a given object. + * @returns {Function} Returns the new pairs function. + */ + function createToPairs(keysFunc) { + return function(object) { + var tag = getTag(object); + if (tag == mapTag) { + return mapToArray(object); + } + if (tag == setTag) { + return setToPairs(object); + } + return baseToPairs(object, keysFunc(object)); + }; + } + + /** + * Creates a function that either curries or invokes `func` with optional + * `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` or `_.curryRight` of a bound function + * 8 - `_.curry` + * 16 - `_.curryRight` + * 32 - `_.partial` + * 64 - `_.partialRight` + * 128 - `_.rearg` + * 256 - `_.ary` + * 512 - `_.flip` + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to be partially applied. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { + var isBindKey = bitmask & WRAP_BIND_KEY_FLAG; + if (!isBindKey && typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = partials ? partials.length : 0; + if (!length) { + bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG); + partials = holders = undefined; + } + ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); + arity = arity === undefined ? arity : toInteger(arity); + length -= holders ? holders.length : 0; + + if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) { + var partialsRight = partials, + holdersRight = holders; + + partials = holders = undefined; + } + var data = isBindKey ? undefined : getData(func); + + var newData = [ + func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, + argPos, ary, arity + ]; + + if (data) { + mergeData(newData, data); + } + func = newData[0]; + bitmask = newData[1]; + thisArg = newData[2]; + partials = newData[3]; + holders = newData[4]; + arity = newData[9] = newData[9] === undefined + ? (isBindKey ? 0 : func.length) + : nativeMax(newData[9] - length, 0); + + if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { + bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); + } + if (!bitmask || bitmask == WRAP_BIND_FLAG) { + var result = createBind(func, bitmask, thisArg); + } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { + result = createCurry(func, bitmask, arity); + } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { + result = createPartial(func, bitmask, thisArg, partials); + } else { + result = createHybrid.apply(undefined, newData); + } + var setter = data ? baseSetData : setData; + return setWrapToString(setter(result, newData), func, bitmask); + } + + /** + * Used by `_.defaults` to customize its `_.assignIn` use to assign properties + * of source objects to the destination object for all destination properties + * that resolve to `undefined`. + * + * @private + * @param {*} objValue The destination value. + * @param {*} srcValue The source value. + * @param {string} key The key of the property to assign. + * @param {Object} object The parent object of `objValue`. + * @returns {*} Returns the value to assign. + */ + function customDefaultsAssignIn(objValue, srcValue, key, object) { + if (objValue === undefined || + (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { + return srcValue; + } + return objValue; + } + + /** + * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source + * objects into destination objects that are passed thru. + * + * @private + * @param {*} objValue The destination value. + * @param {*} srcValue The source value. + * @param {string} key The key of the property to merge. + * @param {Object} object The parent object of `objValue`. + * @param {Object} source The parent object of `srcValue`. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + * @returns {*} Returns the value to assign. + */ + function customDefaultsMerge(objValue, srcValue, key, object, source, stack) { + if (isObject(objValue) && isObject(srcValue)) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, objValue); + baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack); + stack['delete'](srcValue); + } + return objValue; + } + + /** + * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain + * objects. + * + * @private + * @param {*} value The value to inspect. + * @param {string} key The key of the property to inspect. + * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`. + */ + function customOmitClone(value) { + return isPlainObject(value) ? undefined : value; + } + + /** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `array` and `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ + function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isPartial && othLength > arrLength)) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(array); + if (stacked && stack.get(other)) { + return stacked == other; + } + var index = -1, + result = true, + seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; + + stack.set(array, other); + stack.set(other, array); + + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, arrValue, index, other, array, stack) + : customizer(arrValue, othValue, index, array, other, stack); + } + if (compared !== undefined) { + if (compared) { + continue; + } + result = false; + break; + } + // Recursively compare arrays (susceptible to call stack limits). + if (seen) { + if (!arraySome(other, function(othValue, othIndex) { + if (!cacheHas(seen, othIndex) && + (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { + return seen.push(othIndex); + } + })) { + result = false; + break; + } + } else if (!( + arrValue === othValue || + equalFunc(arrValue, othValue, bitmask, customizer, stack) + )) { + result = false; + break; + } + } + stack['delete'](array); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { + switch (tag) { + case dataViewTag: + if ((object.byteLength != other.byteLength) || + (object.byteOffset != other.byteOffset)) { + return false; + } + object = object.buffer; + other = other.buffer; + + case arrayBufferTag: + if ((object.byteLength != other.byteLength) || + !equalFunc(new Uint8Array(object), new Uint8Array(other))) { + return false; + } + return true; + + case boolTag: + case dateTag: + case numberTag: + // Coerce booleans to `1` or `0` and dates to milliseconds. + // Invalid dates are coerced to `NaN`. + return eq(+object, +other); + + case errorTag: + return object.name == other.name && object.message == other.message; + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings, primitives and objects, + // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring + // for more details. + return object == (other + ''); + + case mapTag: + var convert = mapToArray; + + case setTag: + var isPartial = bitmask & COMPARE_PARTIAL_FLAG; + convert || (convert = setToArray); + + if (object.size != other.size && !isPartial) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked) { + return stacked == other; + } + bitmask |= COMPARE_UNORDERED_FLAG; + + // Recursively compare objects (susceptible to call stack limits). + stack.set(object, other); + var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); + stack['delete'](object); + return result; + + case symbolTag: + if (symbolValueOf) { + return symbolValueOf.call(object) == symbolValueOf.call(other); + } + } + return false; + } + + /** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + objProps = getAllKeys(object), + objLength = objProps.length, + othProps = getAllKeys(other), + othLength = othProps.length; + + if (objLength != othLength && !isPartial) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { + return false; + } + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked && stack.get(other)) { + return stacked == other; + } + var result = true; + stack.set(object, other); + stack.set(other, object); + + var skipCtor = isPartial; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, objValue, key, other, object, stack) + : customizer(objValue, othValue, key, object, other, stack); + } + // Recursively compare objects (susceptible to call stack limits). + if (!(compared === undefined + ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) + : compared + )) { + result = false; + break; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (result && !skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + result = false; + } + } + stack['delete'](object); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseRest` which flattens the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. + */ + function flatRest(func) { + return setToString(overRest(func, undefined, flatten), func + ''); + } + + /** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); + } + + /** + * Creates an array of own and inherited enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeysIn(object) { + return baseGetAllKeys(object, keysIn, getSymbolsIn); + } + + /** + * Gets metadata for `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {*} Returns the metadata for `func`. + */ + var getData = !metaMap ? noop : function(func) { + return metaMap.get(func); + }; + + /** + * Gets the name of `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {string} Returns the function name. + */ + function getFuncName(func) { + var result = (func.name + ''), + array = realNames[result], + length = hasOwnProperty.call(realNames, result) ? array.length : 0; + + while (length--) { + var data = array[length], + otherFunc = data.func; + if (otherFunc == null || otherFunc == func) { + return data.name; + } + } + return result; + } + + /** + * Gets the argument placeholder value for `func`. + * + * @private + * @param {Function} func The function to inspect. + * @returns {*} Returns the placeholder value. + */ + function getHolder(func) { + var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; + return object.placeholder; + } + + /** + * Gets the appropriate "iteratee" function. If `_.iteratee` is customized, + * this function returns the custom method, otherwise it returns `baseIteratee`. + * If arguments are provided, the chosen function is invoked with them and + * its result is returned. + * + * @private + * @param {*} [value] The value to convert to an iteratee. + * @param {number} [arity] The arity of the created iteratee. + * @returns {Function} Returns the chosen function or its result. + */ + function getIteratee() { + var result = lodash.iteratee || iteratee; + result = result === iteratee ? baseIteratee : result; + return arguments.length ? result(arguments[0], arguments[1]) : result; + } + + /** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ + function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; + } + + /** + * Gets the property names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ + function getMatchData(object) { + var result = keys(object), + length = result.length; + + while (length--) { + var key = result[length], + value = object[key]; + + result[length] = [key, value, isStrictComparable(value)]; + } + return result; + } + + /** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ + function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; + } + + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; + } + + /** + * Creates an array of the own enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbols = !nativeGetSymbols ? stubArray : function(object) { + if (object == null) { + return []; + } + object = Object(object); + return arrayFilter(nativeGetSymbols(object), function(symbol) { + return propertyIsEnumerable.call(object, symbol); + }); + }; + + /** + * Creates an array of the own and inherited enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { + var result = []; + while (object) { + arrayPush(result, getSymbols(object)); + object = getPrototype(object); + } + return result; + }; + + /** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + var getTag = baseGetTag; + + // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. + if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || + (Map && getTag(new Map) != mapTag) || + (Promise && getTag(Promise.resolve()) != promiseTag) || + (Set && getTag(new Set) != setTag) || + (WeakMap && getTag(new WeakMap) != weakMapTag)) { + getTag = function(value) { + var result = baseGetTag(value), + Ctor = result == objectTag ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : ''; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: return dataViewTag; + case mapCtorString: return mapTag; + case promiseCtorString: return promiseTag; + case setCtorString: return setTag; + case weakMapCtorString: return weakMapTag; + } + } + return result; + }; + } + + /** + * Gets the view, applying any `transforms` to the `start` and `end` positions. + * + * @private + * @param {number} start The start of the view. + * @param {number} end The end of the view. + * @param {Array} transforms The transformations to apply to the view. + * @returns {Object} Returns an object containing the `start` and `end` + * positions of the view. + */ + function getView(start, end, transforms) { + var index = -1, + length = transforms.length; + + while (++index < length) { + var data = transforms[index], + size = data.size; + + switch (data.type) { + case 'drop': start += size; break; + case 'dropRight': end -= size; break; + case 'take': end = nativeMin(end, start + size); break; + case 'takeRight': start = nativeMax(start, end - size); break; + } + } + return { 'start': start, 'end': end }; + } + + /** + * Extracts wrapper details from the `source` body comment. + * + * @private + * @param {string} source The source to inspect. + * @returns {Array} Returns the wrapper details. + */ + function getWrapDetails(source) { + var match = source.match(reWrapDetails); + return match ? match[1].split(reSplitDetails) : []; + } + + /** + * Checks if `path` exists on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @param {Function} hasFunc The function to check properties. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + */ + function hasPath(object, path, hasFunc) { + path = castPath(path, object); + + var index = -1, + length = path.length, + result = false; + + while (++index < length) { + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); + } + + /** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ + function initCloneArray(array) { + var length = array.length, + result = array.constructor(length); + + // Add properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; + } + return result; + } + + /** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; + } + + /** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {Function} cloneFunc The function to clone values. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneByTag(object, tag, cloneFunc, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return cloneArrayBuffer(object); + + case boolTag: + case dateTag: + return new Ctor(+object); + + case dataViewTag: + return cloneDataView(object, isDeep); + + case float32Tag: case float64Tag: + case int8Tag: case int16Tag: case int32Tag: + case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: + return cloneTypedArray(object, isDeep); + + case mapTag: + return cloneMap(object, isDeep, cloneFunc); + + case numberTag: + case stringTag: + return new Ctor(object); + + case regexpTag: + return cloneRegExp(object); + + case setTag: + return cloneSet(object, isDeep, cloneFunc); + + case symbolTag: + return cloneSymbol(object); + } + } + + /** + * Inserts wrapper `details` in a comment at the top of the `source` body. + * + * @private + * @param {string} source The source to modify. + * @returns {Array} details The details to insert. + * @returns {string} Returns the modified source. + */ + function insertWrapDetails(source, details) { + var length = details.length; + if (!length) { + return source; + } + var lastIndex = length - 1; + details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; + details = details.join(length > 2 ? ', ' : ' '); + return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); + } + + /** + * Checks if `value` is a flattenable `arguments` object or array. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. + */ + function isFlattenable(value) { + return isArray(value) || isArguments(value) || + !!(spreadableSymbol && value && value[spreadableSymbol]); + } + + /** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ + function isIndex(value, length) { + length = length == null ? MAX_SAFE_INTEGER : length; + return !!length && + (typeof value == 'number' || reIsUint.test(value)) && + (value > -1 && value % 1 == 0 && value < length); + } + + /** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ + function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; + } + + /** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ + function isKey(value, object) { + if (isArray(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); + } + + /** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ + function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); + } + + /** + * Checks if `func` has a lazy counterpart. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` has a lazy counterpart, + * else `false`. + */ + function isLaziable(func) { + var funcName = getFuncName(func), + other = lodash[funcName]; + + if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { + return false; + } + if (func === other) { + return true; + } + var data = getData(other); + return !!data && func === data[0]; + } + + /** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ + function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); + } + + /** + * Checks if `func` is capable of being masked. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `func` is maskable, else `false`. + */ + var isMaskable = coreJsData ? isFunction : stubFalse; + + /** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ + function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; + + return value === proto; + } + + /** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ + function isStrictComparable(value) { + return value === value && !isObject(value); + } + + /** + * A specialized version of `matchesProperty` for source values suitable + * for strict equality comparisons, i.e. `===`. + * + * @private + * @param {string} key The key of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function matchesStrictComparable(key, srcValue) { + return function(object) { + if (object == null) { + return false; + } + return object[key] === srcValue && + (srcValue !== undefined || (key in Object(object))); + }; + } + + /** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ + function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); + + var cache = result.cache; + return result; + } + + /** + * Merges the function metadata of `source` into `data`. + * + * Merging metadata reduces the number of wrappers used to invoke a function. + * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` + * may be applied regardless of execution order. Methods like `_.ary` and + * `_.rearg` modify function arguments, making the order in which they are + * executed important, preventing the merging of metadata. However, we make + * an exception for a safe combined case where curried functions have `_.ary` + * and or `_.rearg` applied. + * + * @private + * @param {Array} data The destination metadata. + * @param {Array} source The source metadata. + * @returns {Array} Returns `data`. + */ + function mergeData(data, source) { + var bitmask = data[1], + srcBitmask = source[1], + newBitmask = bitmask | srcBitmask, + isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG); + + var isCombo = + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) || + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) || + ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG)); + + // Exit early if metadata can't be merged. + if (!(isCommon || isCombo)) { + return data; + } + // Use source `thisArg` if available. + if (srcBitmask & WRAP_BIND_FLAG) { + data[2] = source[2]; + // Set when currying a bound function. + newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG; + } + // Compose partial arguments. + var value = source[3]; + if (value) { + var partials = data[3]; + data[3] = partials ? composeArgs(partials, value, source[4]) : value; + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; + } + // Compose partial right arguments. + value = source[5]; + if (value) { + partials = data[5]; + data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; + } + // Use source `argPos` if available. + value = source[7]; + if (value) { + data[7] = value; + } + // Use source `ary` if it's smaller. + if (srcBitmask & WRAP_ARY_FLAG) { + data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); + } + // Use source `arity` if one is not provided. + if (data[9] == null) { + data[9] = source[9]; + } + // Use source `func` and merge bitmasks. + data[0] = source[0]; + data[1] = newBitmask; + + return data; + } + + /** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; + } + + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString(value) { + return nativeObjectToString.call(value); + } + + /** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ + function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; + } + + /** + * Gets the parent value at `path` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} path The path to get the parent value of. + * @returns {*} Returns the parent value. + */ + function parent(object, path) { + return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1)); + } + + /** + * Reorder `array` according to the specified indexes where the element at + * the first index is assigned as the first element, the element at + * the second index is assigned as the second element, and so on. + * + * @private + * @param {Array} array The array to reorder. + * @param {Array} indexes The arranged array indexes. + * @returns {Array} Returns `array`. + */ + function reorder(array, indexes) { + var arrLength = array.length, + length = nativeMin(indexes.length, arrLength), + oldArray = copyArray(array); + + while (length--) { + var index = indexes[length]; + array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; + } + return array; + } + + /** + * Sets metadata for `func`. + * + * **Note:** If this function becomes hot, i.e. is invoked a lot in a short + * period of time, it will trip its breaker and transition to an identity + * function to avoid garbage collection pauses in V8. See + * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) + * for more details. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var setData = shortOut(baseSetData); + + /** + * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout). + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @returns {number|Object} Returns the timer id or timeout object. + */ + var setTimeout = ctxSetTimeout || function(func, wait) { + return root.setTimeout(func, wait); + }; + + /** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var setToString = shortOut(baseSetToString); + + /** + * Sets the `toString` method of `wrapper` to mimic the source of `reference` + * with wrapper details in a comment at the top of the source body. + * + * @private + * @param {Function} wrapper The function to modify. + * @param {Function} reference The reference function. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Function} Returns `wrapper`. + */ + function setWrapToString(wrapper, reference, bitmask) { + var source = (reference + ''); + return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))); + } + + /** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ + function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; + } + + /** + * A specialized version of `_.shuffle` which mutates and sets the size of `array`. + * + * @private + * @param {Array} array The array to shuffle. + * @param {number} [size=array.length] The size of `array`. + * @returns {Array} Returns `array`. + */ + function shuffleSelf(array, size) { + var index = -1, + length = array.length, + lastIndex = length - 1; + + size = size === undefined ? length : size; + while (++index < size) { + var rand = baseRandom(index, lastIndex), + value = array[rand]; + + array[rand] = array[index]; + array[index] = value; + } + array.length = size; + return array; + } + + /** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ + var stringToPath = memoizeCapped(function(string) { + var result = []; + if (reLeadingDot.test(string)) { + result.push(''); + } + string.replace(rePropName, function(match, number, quote, string) { + result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; + }); + + /** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ + function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ + function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; + } + + /** + * Updates wrapper `details` based on `bitmask` flags. + * + * @private + * @returns {Array} details The details to modify. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Array} Returns `details`. + */ + function updateWrapDetails(details, bitmask) { + arrayEach(wrapFlags, function(pair) { + var value = '_.' + pair[0]; + if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { + details.push(value); + } + }); + return details.sort(); + } + + /** + * Creates a clone of `wrapper`. + * + * @private + * @param {Object} wrapper The wrapper to clone. + * @returns {Object} Returns the cloned wrapper. + */ + function wrapperClone(wrapper) { + if (wrapper instanceof LazyWrapper) { + return wrapper.clone(); + } + var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); + result.__actions__ = copyArray(wrapper.__actions__); + result.__index__ = wrapper.__index__; + result.__values__ = wrapper.__values__; + return result; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of elements split into groups the length of `size`. + * If `array` can't be split evenly, the final chunk will be the remaining + * elements. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to process. + * @param {number} [size=1] The length of each chunk + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the new array of chunks. + * @example + * + * _.chunk(['a', 'b', 'c', 'd'], 2); + * // => [['a', 'b'], ['c', 'd']] + * + * _.chunk(['a', 'b', 'c', 'd'], 3); + * // => [['a', 'b', 'c'], ['d']] + */ + function chunk(array, size, guard) { + if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { + size = 1; + } else { + size = nativeMax(toInteger(size), 0); + } + var length = array == null ? 0 : array.length; + if (!length || size < 1) { + return []; + } + var index = 0, + resIndex = 0, + result = Array(nativeCeil(length / size)); + + while (index < length) { + result[resIndex++] = baseSlice(array, index, (index += size)); + } + return result; + } + + /** + * Creates an array with all falsey values removed. The values `false`, `null`, + * `0`, `""`, `undefined`, and `NaN` are falsey. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to compact. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.compact([0, 1, false, 2, '', 3]); + * // => [1, 2, 3] + */ + function compact(array) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * Creates a new array concatenating `array` with any additional arrays + * and/or values. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to concatenate. + * @param {...*} [values] The values to concatenate. + * @returns {Array} Returns the new concatenated array. + * @example + * + * var array = [1]; + * var other = _.concat(array, 2, [3], [[4]]); + * + * console.log(other); + * // => [1, 2, 3, [4]] + * + * console.log(array); + * // => [1] + */ + function concat() { + var length = arguments.length; + if (!length) { + return []; + } + var args = Array(length - 1), + array = arguments[0], + index = length; + + while (index--) { + args[index - 1] = arguments[index]; + } + return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); + } + + /** + * Creates an array of `array` values not included in the other given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * **Note:** Unlike `_.pullAll`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.without, _.xor + * @example + * + * _.difference([2, 1], [2, 3]); + * // => [1] + */ + var difference = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) + : []; + }); + + /** + * This method is like `_.difference` except that it accepts `iteratee` which + * is invoked for each element of `array` and `values` to generate the criterion + * by which they're compared. The order and references of result values are + * determined by the first array. The iteratee is invoked with one argument: + * (value). + * + * **Note:** Unlike `_.pullAllBy`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2] + * + * // The `_.property` iteratee shorthand. + * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); + * // => [{ 'x': 2 }] + */ + var differenceBy = baseRest(function(array, values) { + var iteratee = last(values); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)) + : []; + }); + + /** + * This method is like `_.difference` except that it accepts `comparator` + * which is invoked to compare elements of `array` to `values`. The order and + * references of result values are determined by the first array. The comparator + * is invoked with two arguments: (arrVal, othVal). + * + * **Note:** Unlike `_.pullAllWith`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * + * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); + * // => [{ 'x': 2, 'y': 1 }] + */ + var differenceWith = baseRest(function(array, values) { + var comparator = last(values); + if (isArrayLikeObject(comparator)) { + comparator = undefined; + } + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) + : []; + }); + + /** + * Creates a slice of `array` with `n` elements dropped from the beginning. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.drop([1, 2, 3]); + * // => [2, 3] + * + * _.drop([1, 2, 3], 2); + * // => [3] + * + * _.drop([1, 2, 3], 5); + * // => [] + * + * _.drop([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function drop(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * Creates a slice of `array` with `n` elements dropped from the end. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropRight([1, 2, 3]); + * // => [1, 2] + * + * _.dropRight([1, 2, 3], 2); + * // => [1] + * + * _.dropRight([1, 2, 3], 5); + * // => [] + * + * _.dropRight([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function dropRight(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + n = length - n; + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` excluding elements dropped from the end. + * Elements are dropped until `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.dropRightWhile(users, function(o) { return !o.active; }); + * // => objects for ['barney'] + * + * // The `_.matches` iteratee shorthand. + * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }); + * // => objects for ['barney', 'fred'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.dropRightWhile(users, ['active', false]); + * // => objects for ['barney'] + * + * // The `_.property` iteratee shorthand. + * _.dropRightWhile(users, 'active'); + * // => objects for ['barney', 'fred', 'pebbles'] + */ + function dropRightWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), true, true) + : []; + } + + /** + * Creates a slice of `array` excluding elements dropped from the beginning. + * Elements are dropped until `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.dropWhile(users, function(o) { return !o.active; }); + * // => objects for ['pebbles'] + * + * // The `_.matches` iteratee shorthand. + * _.dropWhile(users, { 'user': 'barney', 'active': false }); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.dropWhile(users, ['active', false]); + * // => objects for ['pebbles'] + * + * // The `_.property` iteratee shorthand. + * _.dropWhile(users, 'active'); + * // => objects for ['barney', 'fred', 'pebbles'] + */ + function dropWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), true) + : []; + } + + /** + * Fills elements of `array` with `value` from `start` up to, but not + * including, `end`. + * + * **Note:** This method mutates `array`. + * + * @static + * @memberOf _ + * @since 3.2.0 + * @category Array + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.fill(array, 'a'); + * console.log(array); + * // => ['a', 'a', 'a'] + * + * _.fill(Array(3), 2); + * // => [2, 2, 2] + * + * _.fill([4, 6, 8, 10], '*', 1, 3); + * // => [4, '*', '*', 10] + */ + function fill(array, value, start, end) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { + start = 0; + end = length; + } + return baseFill(array, value, start, end); + } + + /** + * This method is like `_.find` except that it returns the index of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.findIndex(users, function(o) { return o.user == 'barney'; }); + * // => 0 + * + * // The `_.matches` iteratee shorthand. + * _.findIndex(users, { 'user': 'fred', 'active': false }); + * // => 1 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findIndex(users, ['active', false]); + * // => 0 + * + * // The `_.property` iteratee shorthand. + * _.findIndex(users, 'active'); + * // => 2 + */ + function findIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseFindIndex(array, getIteratee(predicate, 3), index); + } + + /** + * This method is like `_.findIndex` except that it iterates over elements + * of `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); + * // => 2 + * + * // The `_.matches` iteratee shorthand. + * _.findLastIndex(users, { 'user': 'barney', 'active': true }); + * // => 0 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastIndex(users, ['active', false]); + * // => 2 + * + * // The `_.property` iteratee shorthand. + * _.findLastIndex(users, 'active'); + * // => 0 + */ + function findLastIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = length - 1; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = fromIndex < 0 + ? nativeMax(length + index, 0) + : nativeMin(index, length - 1); + } + return baseFindIndex(array, getIteratee(predicate, 3), index, true); + } + + /** + * Flattens `array` a single level deep. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flatten([1, [2, [3, [4]], 5]]); + * // => [1, 2, [3, [4]], 5] + */ + function flatten(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, 1) : []; + } + + /** + * Recursively flattens `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flattenDeep([1, [2, [3, [4]], 5]]); + * // => [1, 2, 3, 4, 5] + */ + function flattenDeep(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, INFINITY) : []; + } + + /** + * Recursively flatten `array` up to `depth` times. + * + * @static + * @memberOf _ + * @since 4.4.0 + * @category Array + * @param {Array} array The array to flatten. + * @param {number} [depth=1] The maximum recursion depth. + * @returns {Array} Returns the new flattened array. + * @example + * + * var array = [1, [2, [3, [4]], 5]]; + * + * _.flattenDepth(array, 1); + * // => [1, 2, [3, [4]], 5] + * + * _.flattenDepth(array, 2); + * // => [1, 2, 3, [4], 5] + */ + function flattenDepth(array, depth) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + depth = depth === undefined ? 1 : toInteger(depth); + return baseFlatten(array, depth); + } + + /** + * The inverse of `_.toPairs`; this method returns an object composed + * from key-value `pairs`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} pairs The key-value pairs. + * @returns {Object} Returns the new object. + * @example + * + * _.fromPairs([['a', 1], ['b', 2]]); + * // => { 'a': 1, 'b': 2 } + */ + function fromPairs(pairs) { + var index = -1, + length = pairs == null ? 0 : pairs.length, + result = {}; + + while (++index < length) { + var pair = pairs[index]; + result[pair[0]] = pair[1]; + } + return result; + } + + /** + * Gets the first element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias first + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the first element of `array`. + * @example + * + * _.head([1, 2, 3]); + * // => 1 + * + * _.head([]); + * // => undefined + */ + function head(array) { + return (array && array.length) ? array[0] : undefined; + } + + /** + * Gets the index at which the first occurrence of `value` is found in `array` + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it's used as the + * offset from the end of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 1, 2], 2); + * // => 1 + * + * // Search from the `fromIndex`. + * _.indexOf([1, 2, 1, 2], 2, 2); + * // => 3 + */ + function indexOf(array, value, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseIndexOf(array, value, index); + } + + /** + * Gets all but the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.initial([1, 2, 3]); + * // => [1, 2] + */ + function initial(array) { + var length = array == null ? 0 : array.length; + return length ? baseSlice(array, 0, -1) : []; + } + + /** + * Creates an array of unique values that are included in all given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * _.intersection([2, 1], [2, 3]); + * // => [2] + */ + var intersection = baseRest(function(arrays) { + var mapped = arrayMap(arrays, castArrayLikeObject); + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped) + : []; + }); + + /** + * This method is like `_.intersection` except that it accepts `iteratee` + * which is invoked for each element of each `arrays` to generate the criterion + * by which they're compared. The order and references of result values are + * determined by the first array. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [2.1] + * + * // The `_.property` iteratee shorthand. + * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }] + */ + var intersectionBy = baseRest(function(arrays) { + var iteratee = last(arrays), + mapped = arrayMap(arrays, castArrayLikeObject); + + if (iteratee === last(mapped)) { + iteratee = undefined; + } else { + mapped.pop(); + } + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped, getIteratee(iteratee, 2)) + : []; + }); + + /** + * This method is like `_.intersection` except that it accepts `comparator` + * which is invoked to compare elements of `arrays`. The order and references + * of result values are determined by the first array. The comparator is + * invoked with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.intersectionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }] + */ + var intersectionWith = baseRest(function(arrays) { + var comparator = last(arrays), + mapped = arrayMap(arrays, castArrayLikeObject); + + comparator = typeof comparator == 'function' ? comparator : undefined; + if (comparator) { + mapped.pop(); + } + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped, undefined, comparator) + : []; + }); + + /** + * Converts all elements in `array` into a string separated by `separator`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to convert. + * @param {string} [separator=','] The element separator. + * @returns {string} Returns the joined string. + * @example + * + * _.join(['a', 'b', 'c'], '~'); + * // => 'a~b~c' + */ + function join(array, separator) { + return array == null ? '' : nativeJoin.call(array, separator); + } + + /** + * Gets the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the last element of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + */ + function last(array) { + var length = array == null ? 0 : array.length; + return length ? array[length - 1] : undefined; + } + + /** + * This method is like `_.indexOf` except that it iterates over elements of + * `array` from right to left. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.lastIndexOf([1, 2, 1, 2], 2); + * // => 3 + * + * // Search from the `fromIndex`. + * _.lastIndexOf([1, 2, 1, 2], 2, 2); + * // => 1 + */ + function lastIndexOf(array, value, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = length; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1); + } + return value === value + ? strictLastIndexOf(array, value, index) + : baseFindIndex(array, baseIsNaN, index, true); + } + + /** + * Gets the element at index `n` of `array`. If `n` is negative, the nth + * element from the end is returned. + * + * @static + * @memberOf _ + * @since 4.11.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=0] The index of the element to return. + * @returns {*} Returns the nth element of `array`. + * @example + * + * var array = ['a', 'b', 'c', 'd']; + * + * _.nth(array, 1); + * // => 'b' + * + * _.nth(array, -2); + * // => 'c'; + */ + function nth(array, n) { + return (array && array.length) ? baseNth(array, toInteger(n)) : undefined; + } + + /** + * Removes all given values from `array` using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove` + * to remove elements from an array by predicate. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {...*} [values] The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; + * + * _.pull(array, 'a', 'c'); + * console.log(array); + * // => ['b', 'b'] + */ + var pull = baseRest(pullAll); + + /** + * This method is like `_.pull` except that it accepts an array of values to remove. + * + * **Note:** Unlike `_.difference`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; + * + * _.pullAll(array, ['a', 'c']); + * console.log(array); + * // => ['b', 'b'] + */ + function pullAll(array, values) { + return (array && array.length && values && values.length) + ? basePullAll(array, values) + : array; + } + + /** + * This method is like `_.pullAll` except that it accepts `iteratee` which is + * invoked for each element of `array` and `values` to generate the criterion + * by which they're compared. The iteratee is invoked with one argument: (value). + * + * **Note:** Unlike `_.differenceBy`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns `array`. + * @example + * + * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; + * + * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); + * console.log(array); + * // => [{ 'x': 2 }] + */ + function pullAllBy(array, values, iteratee) { + return (array && array.length && values && values.length) + ? basePullAll(array, values, getIteratee(iteratee, 2)) + : array; + } + + /** + * This method is like `_.pullAll` except that it accepts `comparator` which + * is invoked to compare elements of `array` to `values`. The comparator is + * invoked with two arguments: (arrVal, othVal). + * + * **Note:** Unlike `_.differenceWith`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns `array`. + * @example + * + * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }]; + * + * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual); + * console.log(array); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] + */ + function pullAllWith(array, values, comparator) { + return (array && array.length && values && values.length) + ? basePullAll(array, values, undefined, comparator) + : array; + } + + /** + * Removes elements from `array` corresponding to `indexes` and returns an + * array of removed elements. + * + * **Note:** Unlike `_.at`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {...(number|number[])} [indexes] The indexes of elements to remove. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = ['a', 'b', 'c', 'd']; + * var pulled = _.pullAt(array, [1, 3]); + * + * console.log(array); + * // => ['a', 'c'] + * + * console.log(pulled); + * // => ['b', 'd'] + */ + var pullAt = flatRest(function(array, indexes) { + var length = array == null ? 0 : array.length, + result = baseAt(array, indexes); + + basePullAt(array, arrayMap(indexes, function(index) { + return isIndex(index, length) ? +index : index; + }).sort(compareAscending)); + + return result; + }); + + /** + * Removes all elements from `array` that `predicate` returns truthy for + * and returns an array of the removed elements. The predicate is invoked + * with three arguments: (value, index, array). + * + * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull` + * to pull elements from an array by value. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = [1, 2, 3, 4]; + * var evens = _.remove(array, function(n) { + * return n % 2 == 0; + * }); + * + * console.log(array); + * // => [1, 3] + * + * console.log(evens); + * // => [2, 4] + */ + function remove(array, predicate) { + var result = []; + if (!(array && array.length)) { + return result; + } + var index = -1, + indexes = [], + length = array.length; + + predicate = getIteratee(predicate, 3); + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result.push(value); + indexes.push(index); + } + } + basePullAt(array, indexes); + return result; + } + + /** + * Reverses `array` so that the first element becomes the last, the second + * element becomes the second to last, and so on. + * + * **Note:** This method mutates `array` and is based on + * [`Array#reverse`](https://mdn.io/Array/reverse). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.reverse(array); + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function reverse(array) { + return array == null ? array : nativeReverse.call(array); + } + + /** + * Creates a slice of `array` from `start` up to, but not including, `end`. + * + * **Note:** This method is used instead of + * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are + * returned. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function slice(array, start, end) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { + start = 0; + end = length; + } + else { + start = start == null ? 0 : toInteger(start); + end = end === undefined ? length : toInteger(end); + } + return baseSlice(array, start, end); + } + + /** + * Uses a binary search to determine the lowest index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedIndex([30, 50], 40); + * // => 1 + */ + function sortedIndex(array, value) { + return baseSortedIndex(array, value); + } + + /** + * This method is like `_.sortedIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * + * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 0 + * + * // The `_.property` iteratee shorthand. + * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); + * // => 0 + */ + function sortedIndexBy(array, value, iteratee) { + return baseSortedIndexBy(array, value, getIteratee(iteratee, 2)); + } + + /** + * This method is like `_.indexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedIndexOf([4, 5, 5, 5, 6], 5); + * // => 1 + */ + function sortedIndexOf(array, value) { + var length = array == null ? 0 : array.length; + if (length) { + var index = baseSortedIndex(array, value); + if (index < length && eq(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.sortedIndex` except that it returns the highest + * index at which `value` should be inserted into `array` in order to + * maintain its sort order. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedLastIndex([4, 5, 5, 5, 6], 5); + * // => 4 + */ + function sortedLastIndex(array, value) { + return baseSortedIndex(array, value, true); + } + + /** + * This method is like `_.sortedLastIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * + * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 1 + * + * // The `_.property` iteratee shorthand. + * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); + * // => 1 + */ + function sortedLastIndexBy(array, value, iteratee) { + return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true); + } + + /** + * This method is like `_.lastIndexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); + * // => 3 + */ + function sortedLastIndexOf(array, value) { + var length = array == null ? 0 : array.length; + if (length) { + var index = baseSortedIndex(array, value, true) - 1; + if (eq(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.uniq` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniq([1, 1, 2]); + * // => [1, 2] + */ + function sortedUniq(array) { + return (array && array.length) + ? baseSortedUniq(array) + : []; + } + + /** + * This method is like `_.uniqBy` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); + * // => [1.1, 2.3] + */ + function sortedUniqBy(array, iteratee) { + return (array && array.length) + ? baseSortedUniq(array, getIteratee(iteratee, 2)) + : []; + } + + /** + * Gets all but the first element of `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.tail([1, 2, 3]); + * // => [2, 3] + */ + function tail(array) { + var length = array == null ? 0 : array.length; + return length ? baseSlice(array, 1, length) : []; + } + + /** + * Creates a slice of `array` with `n` elements taken from the beginning. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.take([1, 2, 3]); + * // => [1] + * + * _.take([1, 2, 3], 2); + * // => [1, 2] + * + * _.take([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.take([1, 2, 3], 0); + * // => [] + */ + function take(array, n, guard) { + if (!(array && array.length)) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` with `n` elements taken from the end. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRight([1, 2, 3]); + * // => [3] + * + * _.takeRight([1, 2, 3], 2); + * // => [2, 3] + * + * _.takeRight([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.takeRight([1, 2, 3], 0); + * // => [] + */ + function takeRight(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + n = length - n; + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * Creates a slice of `array` with elements taken from the end. Elements are + * taken until `predicate` returns falsey. The predicate is invoked with + * three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.takeRightWhile(users, function(o) { return !o.active; }); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.matches` iteratee shorthand. + * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }); + * // => objects for ['pebbles'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.takeRightWhile(users, ['active', false]); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.property` iteratee shorthand. + * _.takeRightWhile(users, 'active'); + * // => [] + */ + function takeRightWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), false, true) + : []; + } + + /** + * Creates a slice of `array` with elements taken from the beginning. Elements + * are taken until `predicate` returns falsey. The predicate is invoked with + * three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.takeWhile(users, function(o) { return !o.active; }); + * // => objects for ['barney', 'fred'] + * + * // The `_.matches` iteratee shorthand. + * _.takeWhile(users, { 'user': 'barney', 'active': false }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.takeWhile(users, ['active', false]); + * // => objects for ['barney', 'fred'] + * + * // The `_.property` iteratee shorthand. + * _.takeWhile(users, 'active'); + * // => [] + */ + function takeWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3)) + : []; + } + + /** + * Creates an array of unique values, in order, from all given arrays using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.union([2], [1, 2]); + * // => [2, 1] + */ + var union = baseRest(function(arrays) { + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); + }); + + /** + * This method is like `_.union` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by + * which uniqueness is computed. Result values are chosen from the first + * array in which the value occurs. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.unionBy([2.1], [1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // The `_.property` iteratee shorthand. + * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + var unionBy = baseRest(function(arrays) { + var iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)); + }); + + /** + * This method is like `_.union` except that it accepts `comparator` which + * is invoked to compare elements of `arrays`. Result values are chosen from + * the first array in which the value occurs. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of combined values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.unionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + var unionWith = baseRest(function(arrays) { + var comparator = last(arrays); + comparator = typeof comparator == 'function' ? comparator : undefined; + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); + }); + + /** + * Creates a duplicate-free version of an array, using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons, in which only the first occurrence of each element + * is kept. The order of result values is determined by the order they occur + * in the array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniq([2, 1, 2]); + * // => [2, 1] + */ + function uniq(array) { + return (array && array.length) ? baseUniq(array) : []; + } + + /** + * This method is like `_.uniq` except that it accepts `iteratee` which is + * invoked for each element in `array` to generate the criterion by which + * uniqueness is computed. The order of result values is determined by the + * order they occur in the array. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniqBy([2.1, 1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // The `_.property` iteratee shorthand. + * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + function uniqBy(array, iteratee) { + return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : []; + } + + /** + * This method is like `_.uniq` except that it accepts `comparator` which + * is invoked to compare elements of `array`. The order of result values is + * determined by the order they occur in the array.The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.uniqWith(objects, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] + */ + function uniqWith(array, comparator) { + comparator = typeof comparator == 'function' ? comparator : undefined; + return (array && array.length) ? baseUniq(array, undefined, comparator) : []; + } + + /** + * This method is like `_.zip` except that it accepts an array of grouped + * elements and creates an array regrouping the elements to their pre-zip + * configuration. + * + * @static + * @memberOf _ + * @since 1.2.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + * + * _.unzip(zipped); + * // => [['a', 'b'], [1, 2], [true, false]] + */ + function unzip(array) { + if (!(array && array.length)) { + return []; + } + var length = 0; + array = arrayFilter(array, function(group) { + if (isArrayLikeObject(group)) { + length = nativeMax(group.length, length); + return true; + } + }); + return baseTimes(length, function(index) { + return arrayMap(array, baseProperty(index)); + }); + } + + /** + * This method is like `_.unzip` except that it accepts `iteratee` to specify + * how regrouped values should be combined. The iteratee is invoked with the + * elements of each group: (...group). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @param {Function} [iteratee=_.identity] The function to combine + * regrouped values. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip([1, 2], [10, 20], [100, 200]); + * // => [[1, 10, 100], [2, 20, 200]] + * + * _.unzipWith(zipped, _.add); + * // => [3, 30, 300] + */ + function unzipWith(array, iteratee) { + if (!(array && array.length)) { + return []; + } + var result = unzip(array); + if (iteratee == null) { + return result; + } + return arrayMap(result, function(group) { + return apply(iteratee, undefined, group); + }); + } + + /** + * Creates an array excluding all given values using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.pull`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...*} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.difference, _.xor + * @example + * + * _.without([2, 1, 2, 3], 1, 2); + * // => [3] + */ + var without = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, values) + : []; + }); + + /** + * Creates an array of unique values that is the + * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) + * of the given arrays. The order of result values is determined by the order + * they occur in the arrays. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of filtered values. + * @see _.difference, _.without + * @example + * + * _.xor([2, 1], [2, 3]); + * // => [1, 3] + */ + var xor = baseRest(function(arrays) { + return baseXor(arrayFilter(arrays, isArrayLikeObject)); + }); + + /** + * This method is like `_.xor` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by + * which by which they're compared. The order of result values is determined + * by the order they occur in the arrays. The iteratee is invoked with one + * argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2, 3.4] + * + * // The `_.property` iteratee shorthand. + * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 2 }] + */ + var xorBy = baseRest(function(arrays) { + var iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2)); + }); + + /** + * This method is like `_.xor` except that it accepts `comparator` which is + * invoked to compare elements of `arrays`. The order of result values is + * determined by the order they occur in the arrays. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.xorWith(objects, others, _.isEqual); + * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + var xorWith = baseRest(function(arrays) { + var comparator = last(arrays); + comparator = typeof comparator == 'function' ? comparator : undefined; + return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator); + }); + + /** + * Creates an array of grouped elements, the first of which contains the + * first elements of the given arrays, the second of which contains the + * second elements of the given arrays, and so on. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + */ + var zip = baseRest(unzip); + + /** + * This method is like `_.fromPairs` except that it accepts two arrays, + * one of property identifiers and one of corresponding values. + * + * @static + * @memberOf _ + * @since 0.4.0 + * @category Array + * @param {Array} [props=[]] The property identifiers. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObject(['a', 'b'], [1, 2]); + * // => { 'a': 1, 'b': 2 } + */ + function zipObject(props, values) { + return baseZipObject(props || [], values || [], assignValue); + } + + /** + * This method is like `_.zipObject` except that it supports property paths. + * + * @static + * @memberOf _ + * @since 4.1.0 + * @category Array + * @param {Array} [props=[]] The property identifiers. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); + * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } + */ + function zipObjectDeep(props, values) { + return baseZipObject(props || [], values || [], baseSet); + } + + /** + * This method is like `_.zip` except that it accepts `iteratee` to specify + * how grouped values should be combined. The iteratee is invoked with the + * elements of each group: (...group). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @param {Function} [iteratee=_.identity] The function to combine + * grouped values. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { + * return a + b + c; + * }); + * // => [111, 222] + */ + var zipWith = baseRest(function(arrays) { + var length = arrays.length, + iteratee = length > 1 ? arrays[length - 1] : undefined; + + iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined; + return unzipWith(arrays, iteratee); + }); + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` wrapper instance that wraps `value` with explicit method + * chain sequences enabled. The result of such sequences must be unwrapped + * with `_#value`. + * + * @static + * @memberOf _ + * @since 1.3.0 + * @category Seq + * @param {*} value The value to wrap. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'pebbles', 'age': 1 } + * ]; + * + * var youngest = _ + * .chain(users) + * .sortBy('age') + * .map(function(o) { + * return o.user + ' is ' + o.age; + * }) + * .head() + * .value(); + * // => 'pebbles is 1' + */ + function chain(value) { + var result = lodash(value); + result.__chain__ = true; + return result; + } + + /** + * This method invokes `interceptor` and returns `value`. The interceptor + * is invoked with one argument; (value). The purpose of this method is to + * "tap into" a method chain sequence in order to modify intermediate results. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns `value`. + * @example + * + * _([1, 2, 3]) + * .tap(function(array) { + * // Mutate input array. + * array.pop(); + * }) + * .reverse() + * .value(); + * // => [2, 1] + */ + function tap(value, interceptor) { + interceptor(value); + return value; + } + + /** + * This method is like `_.tap` except that it returns the result of `interceptor`. + * The purpose of this method is to "pass thru" values replacing intermediate + * results in a method chain sequence. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns the result of `interceptor`. + * @example + * + * _(' abc ') + * .chain() + * .trim() + * .thru(function(value) { + * return [value]; + * }) + * .value(); + * // => ['abc'] + */ + function thru(value, interceptor) { + return interceptor(value); + } + + /** + * This method is the wrapper version of `_.at`. + * + * @name at + * @memberOf _ + * @since 1.0.0 + * @category Seq + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _(object).at(['a[0].b.c', 'a[1]']).value(); + * // => [3, 4] + */ + var wrapperAt = flatRest(function(paths) { + var length = paths.length, + start = length ? paths[0] : 0, + value = this.__wrapped__, + interceptor = function(object) { return baseAt(object, paths); }; + + if (length > 1 || this.__actions__.length || + !(value instanceof LazyWrapper) || !isIndex(start)) { + return this.thru(interceptor); + } + value = value.slice(start, +start + (length ? 1 : 0)); + value.__actions__.push({ + 'func': thru, + 'args': [interceptor], + 'thisArg': undefined + }); + return new LodashWrapper(value, this.__chain__).thru(function(array) { + if (length && !array.length) { + array.push(undefined); + } + return array; + }); + }); + + /** + * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. + * + * @name chain + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // A sequence without explicit chaining. + * _(users).head(); + * // => { 'user': 'barney', 'age': 36 } + * + * // A sequence with explicit chaining. + * _(users) + * .chain() + * .head() + * .pick('user') + * .value(); + * // => { 'user': 'barney' } + */ + function wrapperChain() { + return chain(this); + } + + /** + * Executes the chain sequence and returns the wrapped result. + * + * @name commit + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2]; + * var wrapped = _(array).push(3); + * + * console.log(array); + * // => [1, 2] + * + * wrapped = wrapped.commit(); + * console.log(array); + * // => [1, 2, 3] + * + * wrapped.last(); + * // => 3 + * + * console.log(array); + * // => [1, 2, 3] + */ + function wrapperCommit() { + return new LodashWrapper(this.value(), this.__chain__); + } + + /** + * Gets the next value on a wrapped object following the + * [iterator protocol](https://mdn.io/iteration_protocols#iterator). + * + * @name next + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the next iterator value. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped.next(); + * // => { 'done': false, 'value': 1 } + * + * wrapped.next(); + * // => { 'done': false, 'value': 2 } + * + * wrapped.next(); + * // => { 'done': true, 'value': undefined } + */ + function wrapperNext() { + if (this.__values__ === undefined) { + this.__values__ = toArray(this.value()); + } + var done = this.__index__ >= this.__values__.length, + value = done ? undefined : this.__values__[this.__index__++]; + + return { 'done': done, 'value': value }; + } + + /** + * Enables the wrapper to be iterable. + * + * @name Symbol.iterator + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the wrapper object. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped[Symbol.iterator]() === wrapped; + * // => true + * + * Array.from(wrapped); + * // => [1, 2] + */ + function wrapperToIterator() { + return this; + } + + /** + * Creates a clone of the chain sequence planting `value` as the wrapped value. + * + * @name plant + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @param {*} value The value to plant. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2]).map(square); + * var other = wrapped.plant([3, 4]); + * + * other.value(); + * // => [9, 16] + * + * wrapped.value(); + * // => [1, 4] + */ + function wrapperPlant(value) { + var result, + parent = this; + + while (parent instanceof baseLodash) { + var clone = wrapperClone(parent); + clone.__index__ = 0; + clone.__values__ = undefined; + if (result) { + previous.__wrapped__ = clone; + } else { + result = clone; + } + var previous = clone; + parent = parent.__wrapped__; + } + previous.__wrapped__ = value; + return result; + } + + /** + * This method is the wrapper version of `_.reverse`. + * + * **Note:** This method mutates the wrapped array. + * + * @name reverse + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2, 3]; + * + * _(array).reverse().value() + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function wrapperReverse() { + var value = this.__wrapped__; + if (value instanceof LazyWrapper) { + var wrapped = value; + if (this.__actions__.length) { + wrapped = new LazyWrapper(this); + } + wrapped = wrapped.reverse(); + wrapped.__actions__.push({ + 'func': thru, + 'args': [reverse], + 'thisArg': undefined + }); + return new LodashWrapper(wrapped, this.__chain__); + } + return this.thru(reverse); + } + + /** + * Executes the chain sequence to resolve the unwrapped value. + * + * @name value + * @memberOf _ + * @since 0.1.0 + * @alias toJSON, valueOf + * @category Seq + * @returns {*} Returns the resolved unwrapped value. + * @example + * + * _([1, 2, 3]).value(); + * // => [1, 2, 3] + */ + function wrapperValue() { + return baseWrapperValue(this.__wrapped__, this.__actions__); + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The corresponding value of + * each key is the number of times the key was returned by `iteratee`. The + * iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.countBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': 1, '6': 2 } + * + * // The `_.property` iteratee shorthand. + * _.countBy(['one', 'two', 'three'], 'length'); + * // => { '3': 2, '5': 1 } + */ + var countBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + ++result[key]; + } else { + baseAssignValue(result, key, 1); + } + }); + + /** + * Checks if `predicate` returns truthy for **all** elements of `collection`. + * Iteration is stopped once `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * **Note:** This method returns `true` for + * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because + * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of + * elements of empty collections. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes'], Boolean); + * // => false + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.every(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.every(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.every(users, 'active'); + * // => false + */ + function every(collection, predicate, guard) { + var func = isArray(collection) ? arrayEvery : baseEvery; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning an array of all elements + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * **Note:** Unlike `_.remove`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.reject + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * _.filter(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.filter(users, { 'age': 36, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.filter(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.filter(users, 'active'); + * // => objects for ['barney'] + */ + function filter(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning the first element + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false }, + * { 'user': 'pebbles', 'age': 1, 'active': true } + * ]; + * + * _.find(users, function(o) { return o.age < 40; }); + * // => object for 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.find(users, { 'age': 1, 'active': true }); + * // => object for 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.find(users, ['active', false]); + * // => object for 'fred' + * + * // The `_.property` iteratee shorthand. + * _.find(users, 'active'); + * // => object for 'barney' + */ + var find = createFind(findIndex); + + /** + * This method is like `_.find` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Collection + * @param {Array|Object} collection The collection to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=collection.length-1] The index to search from. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * _.findLast([1, 2, 3, 4], function(n) { + * return n % 2 == 1; + * }); + * // => 3 + */ + var findLast = createFind(findLastIndex); + + /** + * Creates a flattened array of values by running each element in `collection` + * thru `iteratee` and flattening the mapped results. The iteratee is invoked + * with three arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [n, n]; + * } + * + * _.flatMap([1, 2], duplicate); + * // => [1, 1, 2, 2] + */ + function flatMap(collection, iteratee) { + return baseFlatten(map(collection, iteratee), 1); + } + + /** + * This method is like `_.flatMap` except that it recursively flattens the + * mapped results. + * + * @static + * @memberOf _ + * @since 4.7.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [[[n, n]]]; + * } + * + * _.flatMapDeep([1, 2], duplicate); + * // => [1, 1, 2, 2] + */ + function flatMapDeep(collection, iteratee) { + return baseFlatten(map(collection, iteratee), INFINITY); + } + + /** + * This method is like `_.flatMap` except that it recursively flattens the + * mapped results up to `depth` times. + * + * @static + * @memberOf _ + * @since 4.7.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {number} [depth=1] The maximum recursion depth. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [[[n, n]]]; + * } + * + * _.flatMapDepth([1, 2], duplicate, 2); + * // => [[1, 1], [2, 2]] + */ + function flatMapDepth(collection, iteratee, depth) { + depth = depth === undefined ? 1 : toInteger(depth); + return baseFlatten(map(collection, iteratee), depth); + } + + /** + * Iterates over elements of `collection` and invokes `iteratee` for each element. + * The iteratee is invoked with three arguments: (value, index|key, collection). + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a "length" + * property are iterated like arrays. To avoid this behavior use `_.forIn` + * or `_.forOwn` for object iteration. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias each + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @see _.forEachRight + * @example + * + * _.forEach([1, 2], function(value) { + * console.log(value); + * }); + * // => Logs `1` then `2`. + * + * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a' then 'b' (iteration order is not guaranteed). + */ + function forEach(collection, iteratee) { + var func = isArray(collection) ? arrayEach : baseEach; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.forEach` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @alias eachRight + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @see _.forEach + * @example + * + * _.forEachRight([1, 2], function(value) { + * console.log(value); + * }); + * // => Logs `2` then `1`. + */ + function forEachRight(collection, iteratee) { + var func = isArray(collection) ? arrayEachRight : baseEachRight; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The order of grouped values + * is determined by the order they occur in `collection`. The corresponding + * value of each key is an array of elements responsible for generating the + * key. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.groupBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': [4.2], '6': [6.1, 6.3] } + * + * // The `_.property` iteratee shorthand. + * _.groupBy(['one', 'two', 'three'], 'length'); + * // => { '3': ['one', 'two'], '5': ['three'] } + */ + var groupBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + result[key].push(value); + } else { + baseAssignValue(result, key, [value]); + } + }); + + /** + * Checks if `value` is in `collection`. If `collection` is a string, it's + * checked for a substring of `value`, otherwise + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * is used for equality comparisons. If `fromIndex` is negative, it's used as + * the offset from the end of `collection`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. + * @returns {boolean} Returns `true` if `value` is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes([1, 2, 3], 1, 2); + * // => false + * + * _.includes({ 'a': 1, 'b': 2 }, 1); + * // => true + * + * _.includes('abcd', 'bc'); + * // => true + */ + function includes(collection, value, fromIndex, guard) { + collection = isArrayLike(collection) ? collection : values(collection); + fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; + + var length = collection.length; + if (fromIndex < 0) { + fromIndex = nativeMax(length + fromIndex, 0); + } + return isString(collection) + ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) + : (!!length && baseIndexOf(collection, value, fromIndex) > -1); + } + + /** + * Invokes the method at `path` of each element in `collection`, returning + * an array of the results of each invoked method. Any additional arguments + * are provided to each invoked method. If `path` is a function, it's invoked + * for, and `this` bound to, each element in `collection`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Function|string} path The path of the method to invoke or + * the function invoked per iteration. + * @param {...*} [args] The arguments to invoke each method with. + * @returns {Array} Returns the array of results. + * @example + * + * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); + * // => [[1, 5, 7], [1, 2, 3]] + * + * _.invokeMap([123, 456], String.prototype.split, ''); + * // => [['1', '2', '3'], ['4', '5', '6']] + */ + var invokeMap = baseRest(function(collection, path, args) { + var index = -1, + isFunc = typeof path == 'function', + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value) { + result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args); + }); + return result; + }); + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The corresponding value of + * each key is the last element responsible for generating the key. The + * iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * var array = [ + * { 'dir': 'left', 'code': 97 }, + * { 'dir': 'right', 'code': 100 } + * ]; + * + * _.keyBy(array, function(o) { + * return String.fromCharCode(o.code); + * }); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + * + * _.keyBy(array, 'dir'); + * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } + */ + var keyBy = createAggregator(function(result, value, key) { + baseAssignValue(result, key, value); + }); + + /** + * Creates an array of values by running each element in `collection` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. + * + * The guarded methods are: + * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, + * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, + * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, + * `template`, `trim`, `trimEnd`, `trimStart`, and `words` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + * @example + * + * function square(n) { + * return n * n; + * } + * + * _.map([4, 8], square); + * // => [16, 64] + * + * _.map({ 'a': 4, 'b': 8 }, square); + * // => [16, 64] (iteration order is not guaranteed) + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * // The `_.property` iteratee shorthand. + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ + function map(collection, iteratee) { + var func = isArray(collection) ? arrayMap : baseMap; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.sortBy` except that it allows specifying the sort + * orders of the iteratees to sort by. If `orders` is unspecified, all values + * are sorted in ascending order. Otherwise, specify an order of "desc" for + * descending or "asc" for ascending sort order of corresponding values. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]] + * The iteratees to sort by. + * @param {string[]} [orders] The sort orders of `iteratees`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 34 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 36 } + * ]; + * + * // Sort by `user` in ascending order and by `age` in descending order. + * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + */ + function orderBy(collection, iteratees, orders, guard) { + if (collection == null) { + return []; + } + if (!isArray(iteratees)) { + iteratees = iteratees == null ? [] : [iteratees]; + } + orders = guard ? undefined : orders; + if (!isArray(orders)) { + orders = orders == null ? [] : [orders]; + } + return baseOrderBy(collection, iteratees, orders); + } + + /** + * Creates an array of elements split into two groups, the first of which + * contains elements `predicate` returns truthy for, the second of which + * contains elements `predicate` returns falsey for. The predicate is + * invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the array of grouped elements. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * _.partition(users, function(o) { return o.active; }); + * // => objects for [['fred'], ['barney', 'pebbles']] + * + * // The `_.matches` iteratee shorthand. + * _.partition(users, { 'age': 1, 'active': false }); + * // => objects for [['pebbles'], ['barney', 'fred']] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.partition(users, ['active', false]); + * // => objects for [['barney', 'pebbles'], ['fred']] + * + * // The `_.property` iteratee shorthand. + * _.partition(users, 'active'); + * // => objects for [['fred'], ['barney', 'pebbles']] + */ + var partition = createAggregator(function(result, value, key) { + result[key ? 0 : 1].push(value); + }, function() { return [[], []]; }); + + /** + * Reduces `collection` to a value which is the accumulated result of running + * each element in `collection` thru `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not given, the first element of `collection` is used as the initial + * value. The iteratee is invoked with four arguments: + * (accumulator, value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.reduce`, `_.reduceRight`, and `_.transform`. + * + * The guarded methods are: + * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, + * and `sortBy` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @see _.reduceRight + * @example + * + * _.reduce([1, 2], function(sum, n) { + * return sum + n; + * }, 0); + * // => 3 + * + * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { + * (result[value] || (result[value] = [])).push(key); + * return result; + * }, {}); + * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) + */ + function reduce(collection, iteratee, accumulator) { + var func = isArray(collection) ? arrayReduce : baseReduce, + initAccum = arguments.length < 3; + + return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach); + } + + /** + * This method is like `_.reduce` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @see _.reduce + * @example + * + * var array = [[0, 1], [2, 3], [4, 5]]; + * + * _.reduceRight(array, function(flattened, other) { + * return flattened.concat(other); + * }, []); + * // => [4, 5, 2, 3, 0, 1] + */ + function reduceRight(collection, iteratee, accumulator) { + var func = isArray(collection) ? arrayReduceRight : baseReduce, + initAccum = arguments.length < 3; + + return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight); + } + + /** + * The opposite of `_.filter`; this method returns the elements of `collection` + * that `predicate` does **not** return truthy for. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.filter + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * _.reject(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.reject(users, { 'age': 40, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.reject(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.reject(users, 'active'); + * // => objects for ['barney'] + */ + function reject(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, negate(getIteratee(predicate, 3))); + } + + /** + * Gets a random element from `collection`. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @returns {*} Returns the random element. + * @example + * + * _.sample([1, 2, 3, 4]); + * // => 2 + */ + function sample(collection) { + var func = isArray(collection) ? arraySample : baseSample; + return func(collection); + } + + /** + * Gets `n` random elements at unique keys from `collection` up to the + * size of `collection`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @param {number} [n=1] The number of elements to sample. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the random elements. + * @example + * + * _.sampleSize([1, 2, 3], 2); + * // => [3, 1] + * + * _.sampleSize([1, 2, 3], 4); + * // => [2, 3, 1] + */ + function sampleSize(collection, n, guard) { + if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) { + n = 1; + } else { + n = toInteger(n); + } + var func = isArray(collection) ? arraySampleSize : baseSampleSize; + return func(collection, n); + } + + /** + * Creates an array of shuffled values, using a version of the + * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + * @example + * + * _.shuffle([1, 2, 3, 4]); + * // => [4, 1, 3, 2] + */ + function shuffle(collection) { + var func = isArray(collection) ? arrayShuffle : baseShuffle; + return func(collection); + } + + /** + * Gets the size of `collection` by returning its length for array-like + * values or the number of own enumerable string keyed properties for objects. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the collection size. + * @example + * + * _.size([1, 2, 3]); + * // => 3 + * + * _.size({ 'a': 1, 'b': 2 }); + * // => 2 + * + * _.size('pebbles'); + * // => 7 + */ + function size(collection) { + if (collection == null) { + return 0; + } + if (isArrayLike(collection)) { + return isString(collection) ? stringSize(collection) : collection.length; + } + var tag = getTag(collection); + if (tag == mapTag || tag == setTag) { + return collection.size; + } + return baseKeys(collection).length; + } + + /** + * Checks if `predicate` returns truthy for **any** element of `collection`. + * Iteration is stopped once `predicate` returns truthy. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + * @example + * + * _.some([null, 0, 'yes', false], Boolean); + * // => true + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.some(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.some(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.some(users, 'active'); + * // => true + */ + function some(collection, predicate, guard) { + var func = isArray(collection) ? arraySome : baseSome; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Creates an array of elements, sorted in ascending order by the results of + * running each element in a collection thru each iteratee. This method + * performs a stable sort, that is, it preserves the original sort order of + * equal elements. The iteratees are invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {...(Function|Function[])} [iteratees=[_.identity]] + * The iteratees to sort by. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 34 } + * ]; + * + * _.sortBy(users, [function(o) { return o.user; }]); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + * + * _.sortBy(users, ['user', 'age']); + * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] + */ + var sortBy = baseRest(function(collection, iteratees) { + if (collection == null) { + return []; + } + var length = iteratees.length; + if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { + iteratees = []; + } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { + iteratees = [iteratees[0]]; + } + return baseOrderBy(collection, baseFlatten(iteratees, 1), []); + }); + + /*------------------------------------------------------------------------*/ + + /** + * Gets the timestamp of the number of milliseconds that have elapsed since + * the Unix epoch (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Date + * @returns {number} Returns the timestamp. + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => Logs the number of milliseconds it took for the deferred invocation. + */ + var now = ctxNow || function() { + return root.Date.now(); + }; + + /*------------------------------------------------------------------------*/ + + /** + * The opposite of `_.before`; this method creates a function that invokes + * `func` once it's called `n` or more times. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {number} n The number of calls before `func` is invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var saves = ['profile', 'settings']; + * + * var done = _.after(saves.length, function() { + * console.log('done saving!'); + * }); + * + * _.forEach(saves, function(type) { + * asyncSave({ 'type': type, 'complete': done }); + * }); + * // => Logs 'done saving!' after the two async saves have completed. + */ + function after(n, func) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function() { + if (--n < 1) { + return func.apply(this, arguments); + } + }; + } + + /** + * Creates a function that invokes `func`, with up to `n` arguments, + * ignoring any additional arguments. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to cap arguments for. + * @param {number} [n=func.length] The arity cap. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new capped function. + * @example + * + * _.map(['6', '8', '10'], _.ary(parseInt, 1)); + * // => [6, 8, 10] + */ + function ary(func, n, guard) { + n = guard ? undefined : n; + n = (func && n == null) ? func.length : n; + return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n); + } + + /** + * Creates a function that invokes `func`, with the `this` binding and arguments + * of the created function, while it's called less than `n` times. Subsequent + * calls to the created function return the result of the last `func` invocation. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {number} n The number of calls at which `func` is no longer invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * jQuery(element).on('click', _.before(5, addContactToList)); + * // => Allows adding up to 4 contacts to the list. + */ + function before(n, func) { + var result; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function() { + if (--n > 0) { + result = func.apply(this, arguments); + } + if (n <= 1) { + func = undefined; + } + return result; + }; + } + + /** + * Creates a function that invokes `func` with the `this` binding of `thisArg` + * and `partials` prepended to the arguments it receives. + * + * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for partially applied arguments. + * + * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" + * property of bound functions. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * function greet(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * + * var object = { 'user': 'fred' }; + * + * var bound = _.bind(greet, object, 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * // Bound with placeholders. + * var bound = _.bind(greet, object, _, '!'); + * bound('hi'); + * // => 'hi fred!' + */ + var bind = baseRest(function(func, thisArg, partials) { + var bitmask = WRAP_BIND_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, getHolder(bind)); + bitmask |= WRAP_PARTIAL_FLAG; + } + return createWrap(func, bitmask, thisArg, partials, holders); + }); + + /** + * Creates a function that invokes the method at `object[key]` with `partials` + * prepended to the arguments it receives. + * + * This method differs from `_.bind` by allowing bound functions to reference + * methods that may be redefined or don't yet exist. See + * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) + * for more details. + * + * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * @static + * @memberOf _ + * @since 0.10.0 + * @category Function + * @param {Object} object The object to invoke the method on. + * @param {string} key The key of the method. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var object = { + * 'user': 'fred', + * 'greet': function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * }; + * + * var bound = _.bindKey(object, 'greet', 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * object.greet = function(greeting, punctuation) { + * return greeting + 'ya ' + this.user + punctuation; + * }; + * + * bound('!'); + * // => 'hiya fred!' + * + * // Bound with placeholders. + * var bound = _.bindKey(object, 'greet', _, '!'); + * bound('hi'); + * // => 'hiya fred!' + */ + var bindKey = baseRest(function(object, key, partials) { + var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, getHolder(bindKey)); + bitmask |= WRAP_PARTIAL_FLAG; + } + return createWrap(key, bitmask, object, partials, holders); + }); + + /** + * Creates a function that accepts arguments of `func` and either invokes + * `func` returning its result, if at least `arity` number of arguments have + * been provided, or returns a function that accepts the remaining `func` + * arguments, and so on. The arity of `func` may be specified if `func.length` + * is not sufficient. + * + * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for provided arguments. + * + * **Note:** This method doesn't set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curry(abc); + * + * curried(1)(2)(3); + * // => [1, 2, 3] + * + * curried(1, 2)(3); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // Curried with placeholders. + * curried(1)(_, 3)(2); + * // => [1, 2, 3] + */ + function curry(func, arity, guard) { + arity = guard ? undefined : arity; + var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curry.placeholder; + return result; + } + + /** + * This method is like `_.curry` except that arguments are applied to `func` + * in the manner of `_.partialRight` instead of `_.partial`. + * + * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for provided arguments. + * + * **Note:** This method doesn't set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curryRight(abc); + * + * curried(3)(2)(1); + * // => [1, 2, 3] + * + * curried(2, 3)(1); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // Curried with placeholders. + * curried(3)(1, _)(2); + * // => [1, 2, 3] + */ + function curryRight(func, arity, guard) { + arity = guard ? undefined : arity; + var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curryRight.placeholder; + return result; + } + + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed `func` invocations and a `flush` method to immediately invoke them. + * Provide `options` to indicate whether `func` should be invoked on the + * leading and/or trailing edge of the `wait` timeout. The `func` is invoked + * with the last arguments provided to the debounced function. Subsequent + * calls to the debounced function return the result of the last `func` + * invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the debounced function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=false] + * Specify invoking on the leading edge of the timeout. + * @param {number} [options.maxWait] + * The maximum time `func` is allowed to be delayed before it's invoked. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // Avoid costly calculations while the window size is in flux. + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // Invoke `sendMail` when clicked, debouncing subsequent calls. + * jQuery(element).on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // Ensure `batchLog` is invoked once after 1 second of debounced calls. + * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); + * var source = new EventSource('/stream'); + * jQuery(source).on('message', debounced); + * + * // Cancel the trailing debounced invocation. + * jQuery(window).on('popstate', debounced.cancel); + */ + function debounce(func, wait, options) { + var lastArgs, + lastThis, + maxWait, + result, + timerId, + lastCallTime, + lastInvokeTime = 0, + leading = false, + maxing = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = toNumber(wait) || 0; + if (isObject(options)) { + leading = !!options.leading; + maxing = 'maxWait' in options; + maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function invokeFunc(time) { + var args = lastArgs, + thisArg = lastThis; + + lastArgs = lastThis = undefined; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } + + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time; + // Start the timer for the trailing edge. + timerId = setTimeout(timerExpired, wait); + // Invoke the leading edge. + return leading ? invokeFunc(time) : result; + } + + function remainingWait(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime, + result = wait - timeSinceLastCall; + + return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; + } + + function shouldInvoke(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime; + + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return (lastCallTime === undefined || (timeSinceLastCall >= wait) || + (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); + } + + function timerExpired() { + var time = now(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + // Restart the timer. + timerId = setTimeout(timerExpired, remainingWait(time)); + } + + function trailingEdge(time) { + timerId = undefined; + + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = undefined; + return result; + } + + function cancel() { + if (timerId !== undefined) { + clearTimeout(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; + } + + function flush() { + return timerId === undefined ? result : trailingEdge(now()); + } + + function debounced() { + var time = now(), + isInvoking = shouldInvoke(time); + + lastArgs = arguments; + lastThis = this; + lastCallTime = time; + + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime); + } + if (maxing) { + // Handle invocations in a tight loop. + timerId = setTimeout(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === undefined) { + timerId = setTimeout(timerExpired, wait); + } + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + return debounced; + } + + /** + * Defers invoking the `func` until the current call stack has cleared. Any + * additional arguments are provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to defer. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.defer(function(text) { + * console.log(text); + * }, 'deferred'); + * // => Logs 'deferred' after one millisecond. + */ + var defer = baseRest(function(func, args) { + return baseDelay(func, 1, args); + }); + + /** + * Invokes `func` after `wait` milliseconds. Any additional arguments are + * provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.delay(function(text) { + * console.log(text); + * }, 1000, 'later'); + * // => Logs 'later' after one second. + */ + var delay = baseRest(function(func, wait, args) { + return baseDelay(func, toNumber(wait) || 0, args); + }); + + /** + * Creates a function that invokes `func` with arguments reversed. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to flip arguments for. + * @returns {Function} Returns the new flipped function. + * @example + * + * var flipped = _.flip(function() { + * return _.toArray(arguments); + * }); + * + * flipped('a', 'b', 'c', 'd'); + * // => ['d', 'c', 'b', 'a'] + */ + function flip(func) { + return createWrap(func, WRAP_FLIP_FLAG); + } + + /** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ + function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; + } + + // Expose `MapCache`. + memoize.Cache = MapCache; + + /** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new negated function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ + function negate(predicate) { + if (typeof predicate != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + var args = arguments; + switch (args.length) { + case 0: return !predicate.call(this); + case 1: return !predicate.call(this, args[0]); + case 2: return !predicate.call(this, args[0], args[1]); + case 3: return !predicate.call(this, args[0], args[1], args[2]); + } + return !predicate.apply(this, args); + }; + } + + /** + * Creates a function that is restricted to invoking `func` once. Repeat calls + * to the function return the value of the first invocation. The `func` is + * invoked with the `this` binding and arguments of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // => `createApplication` is invoked once + */ + function once(func) { + return before(2, func); + } + + /** + * Creates a function that invokes `func` with its arguments transformed. + * + * @static + * @since 4.0.0 + * @memberOf _ + * @category Function + * @param {Function} func The function to wrap. + * @param {...(Function|Function[])} [transforms=[_.identity]] + * The argument transforms. + * @returns {Function} Returns the new function. + * @example + * + * function doubled(n) { + * return n * 2; + * } + * + * function square(n) { + * return n * n; + * } + * + * var func = _.overArgs(function(x, y) { + * return [x, y]; + * }, [square, doubled]); + * + * func(9, 3); + * // => [81, 6] + * + * func(10, 5); + * // => [100, 10] + */ + var overArgs = castRest(function(func, transforms) { + transforms = (transforms.length == 1 && isArray(transforms[0])) + ? arrayMap(transforms[0], baseUnary(getIteratee())) + : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee())); + + var funcsLength = transforms.length; + return baseRest(function(args) { + var index = -1, + length = nativeMin(args.length, funcsLength); + + while (++index < length) { + args[index] = transforms[index].call(this, args[index]); + } + return apply(func, this, args); + }); + }); + + /** + * Creates a function that invokes `func` with `partials` prepended to the + * arguments it receives. This method is like `_.bind` except it does **not** + * alter the `this` binding. + * + * The `_.partial.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method doesn't set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @since 0.2.0 + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * function greet(greeting, name) { + * return greeting + ' ' + name; + * } + * + * var sayHelloTo = _.partial(greet, 'hello'); + * sayHelloTo('fred'); + * // => 'hello fred' + * + * // Partially applied with placeholders. + * var greetFred = _.partial(greet, _, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + */ + var partial = baseRest(function(func, partials) { + var holders = replaceHolders(partials, getHolder(partial)); + return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders); + }); + + /** + * This method is like `_.partial` except that partially applied arguments + * are appended to the arguments it receives. + * + * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method doesn't set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * function greet(greeting, name) { + * return greeting + ' ' + name; + * } + * + * var greetFred = _.partialRight(greet, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + * + * // Partially applied with placeholders. + * var sayHelloTo = _.partialRight(greet, 'hello', _); + * sayHelloTo('fred'); + * // => 'hello fred' + */ + var partialRight = baseRest(function(func, partials) { + var holders = replaceHolders(partials, getHolder(partialRight)); + return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders); + }); + + /** + * Creates a function that invokes `func` with arguments arranged according + * to the specified `indexes` where the argument value at the first index is + * provided as the first argument, the argument value at the second index is + * provided as the second argument, and so on. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to rearrange arguments for. + * @param {...(number|number[])} indexes The arranged argument indexes. + * @returns {Function} Returns the new function. + * @example + * + * var rearged = _.rearg(function(a, b, c) { + * return [a, b, c]; + * }, [2, 0, 1]); + * + * rearged('b', 'c', 'a') + * // => ['a', 'b', 'c'] + */ + var rearg = flatRest(function(func, indexes) { + return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes); + }); + + /** + * Creates a function that invokes `func` with the `this` binding of the + * created function and arguments from `start` and beyond provided as + * an array. + * + * **Note:** This method is based on the + * [rest parameter](https://mdn.io/rest_parameters). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.rest(function(what, names) { + * return what + ' ' + _.initial(names).join(', ') + + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); + * }); + * + * say('hello', 'fred', 'barney', 'pebbles'); + * // => 'hello fred, barney, & pebbles' + */ + function rest(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = start === undefined ? start : toInteger(start); + return baseRest(func, start); + } + + /** + * Creates a function that invokes `func` with the `this` binding of the + * create function and an array of arguments much like + * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). + * + * **Note:** This method is based on the + * [spread operator](https://mdn.io/spread_operator). + * + * @static + * @memberOf _ + * @since 3.2.0 + * @category Function + * @param {Function} func The function to spread arguments over. + * @param {number} [start=0] The start position of the spread. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.spread(function(who, what) { + * return who + ' says ' + what; + * }); + * + * say(['fred', 'hello']); + * // => 'fred says hello' + * + * var numbers = Promise.all([ + * Promise.resolve(40), + * Promise.resolve(36) + * ]); + * + * numbers.then(_.spread(function(x, y) { + * return x + y; + * })); + * // => a Promise of 76 + */ + function spread(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = start == null ? 0 : nativeMax(toInteger(start), 0); + return baseRest(function(args) { + var array = args[start], + otherArgs = castSlice(args, 0, start); + + if (array) { + arrayPush(otherArgs, array); + } + return apply(func, this, otherArgs); + }); + } + + /** + * Creates a throttled function that only invokes `func` at most once per + * every `wait` milliseconds. The throttled function comes with a `cancel` + * method to cancel delayed `func` invocations and a `flush` method to + * immediately invoke them. Provide `options` to indicate whether `func` + * should be invoked on the leading and/or trailing edge of the `wait` + * timeout. The `func` is invoked with the last arguments provided to the + * throttled function. Subsequent calls to the throttled function return the + * result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the throttled function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.throttle` and `_.debounce`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to throttle. + * @param {number} [wait=0] The number of milliseconds to throttle invocations to. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=true] + * Specify invoking on the leading edge of the timeout. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // Avoid excessively updating the position while scrolling. + * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); + * + * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. + * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); + * jQuery(element).on('click', throttled); + * + * // Cancel the trailing throttled invocation. + * jQuery(window).on('popstate', throttled.cancel); + */ + function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + return debounce(func, wait, { + 'leading': leading, + 'maxWait': wait, + 'trailing': trailing + }); + } + + /** + * Creates a function that accepts up to one argument, ignoring any + * additional arguments. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + * @example + * + * _.map(['6', '8', '10'], _.unary(parseInt)); + * // => [6, 8, 10] + */ + function unary(func) { + return ary(func, 1); + } + + /** + * Creates a function that provides `value` to `wrapper` as its first + * argument. Any additional arguments provided to the function are appended + * to those provided to the `wrapper`. The wrapper is invoked with the `this` + * binding of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {*} value The value to wrap. + * @param {Function} [wrapper=identity] The wrapper function. + * @returns {Function} Returns the new function. + * @example + * + * var p = _.wrap(_.escape, function(func, text) { + * return '

' + func(text) + '

'; + * }); + * + * p('fred, barney, & pebbles'); + * // => '

fred, barney, & pebbles

' + */ + function wrap(value, wrapper) { + return partial(castFunction(wrapper), value); + } + + /*------------------------------------------------------------------------*/ + + /** + * Casts `value` as an array if it's not one. + * + * @static + * @memberOf _ + * @since 4.4.0 + * @category Lang + * @param {*} value The value to inspect. + * @returns {Array} Returns the cast array. + * @example + * + * _.castArray(1); + * // => [1] + * + * _.castArray({ 'a': 1 }); + * // => [{ 'a': 1 }] + * + * _.castArray('abc'); + * // => ['abc'] + * + * _.castArray(null); + * // => [null] + * + * _.castArray(undefined); + * // => [undefined] + * + * _.castArray(); + * // => [] + * + * var array = [1, 2, 3]; + * console.log(_.castArray(array) === array); + * // => true + */ + function castArray() { + if (!arguments.length) { + return []; + } + var value = arguments[0]; + return isArray(value) ? value : [value]; + } + + /** + * Creates a shallow clone of `value`. + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) + * and supports cloning arrays, array buffers, booleans, date objects, maps, + * numbers, `Object` objects, regexes, sets, strings, symbols, and typed + * arrays. The own enumerable properties of `arguments` objects are cloned + * as plain objects. An empty object is returned for uncloneable values such + * as error objects, functions, DOM nodes, and WeakMaps. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to clone. + * @returns {*} Returns the cloned value. + * @see _.cloneDeep + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var shallow = _.clone(objects); + * console.log(shallow[0] === objects[0]); + * // => true + */ + function clone(value) { + return baseClone(value, CLONE_SYMBOLS_FLAG); + } + + /** + * This method is like `_.clone` except that it accepts `customizer` which + * is invoked to produce the cloned value. If `customizer` returns `undefined`, + * cloning is handled by the method instead. The `customizer` is invoked with + * up to four arguments; (value [, index|key, object, stack]). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the cloned value. + * @see _.cloneDeepWith + * @example + * + * function customizer(value) { + * if (_.isElement(value)) { + * return value.cloneNode(false); + * } + * } + * + * var el = _.cloneWith(document.body, customizer); + * + * console.log(el === document.body); + * // => false + * console.log(el.nodeName); + * // => 'BODY' + * console.log(el.childNodes.length); + * // => 0 + */ + function cloneWith(value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseClone(value, CLONE_SYMBOLS_FLAG, customizer); + } + + /** + * This method is like `_.clone` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @returns {*} Returns the deep cloned value. + * @see _.clone + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var deep = _.cloneDeep(objects); + * console.log(deep[0] === objects[0]); + * // => false + */ + function cloneDeep(value) { + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); + } + + /** + * This method is like `_.cloneWith` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the deep cloned value. + * @see _.cloneWith + * @example + * + * function customizer(value) { + * if (_.isElement(value)) { + * return value.cloneNode(true); + * } + * } + * + * var el = _.cloneDeepWith(document.body, customizer); + * + * console.log(el === document.body); + * // => false + * console.log(el.nodeName); + * // => 'BODY' + * console.log(el.childNodes.length); + * // => 20 + */ + function cloneDeepWith(value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer); + } + + /** + * Checks if `object` conforms to `source` by invoking the predicate + * properties of `source` with the corresponding property values of `object`. + * + * **Note:** This method is equivalent to `_.conforms` when `source` is + * partially applied. + * + * @static + * @memberOf _ + * @since 4.14.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property predicates to conform to. + * @returns {boolean} Returns `true` if `object` conforms, else `false`. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * + * _.conformsTo(object, { 'b': function(n) { return n > 1; } }); + * // => true + * + * _.conformsTo(object, { 'b': function(n) { return n > 2; } }); + * // => false + */ + function conformsTo(object, source) { + return source == null || baseConformsTo(object, source, keys(source)); + } + + /** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ + function eq(value, other) { + return value === other || (value !== value && other !== other); + } + + /** + * Checks if `value` is greater than `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, + * else `false`. + * @see _.lt + * @example + * + * _.gt(3, 1); + * // => true + * + * _.gt(3, 3); + * // => false + * + * _.gt(1, 3); + * // => false + */ + var gt = createRelationalOperation(baseGt); + + /** + * Checks if `value` is greater than or equal to `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than or equal to + * `other`, else `false`. + * @see _.lte + * @example + * + * _.gte(3, 1); + * // => true + * + * _.gte(3, 3); + * // => true + * + * _.gte(1, 3); + * // => false + */ + var gte = createRelationalOperation(function(value, other) { + return value >= other; + }); + + /** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); + }; + + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ + var isArray = Array.isArray; + + /** + * Checks if `value` is classified as an `ArrayBuffer` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. + * @example + * + * _.isArrayBuffer(new ArrayBuffer(2)); + * // => true + * + * _.isArrayBuffer(new Array(2)); + * // => false + */ + var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer; + + /** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ + function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); + } + + /** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ + function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); + } + + /** + * Checks if `value` is classified as a boolean primitive or object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. + * @example + * + * _.isBoolean(false); + * // => true + * + * _.isBoolean(null); + * // => false + */ + function isBoolean(value) { + return value === true || value === false || + (isObjectLike(value) && baseGetTag(value) == boolTag); + } + + /** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ + var isBuffer = nativeIsBuffer || stubFalse; + + /** + * Checks if `value` is classified as a `Date` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + * @example + * + * _.isDate(new Date); + * // => true + * + * _.isDate('Mon April 23 2012'); + * // => false + */ + var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; + + /** + * Checks if `value` is likely a DOM element. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. + * @example + * + * _.isElement(document.body); + * // => true + * + * _.isElement(''); + * // => false + */ + function isElement(value) { + return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value); + } + + /** + * Checks if `value` is an empty object, collection, map, or set. + * + * Objects are considered empty if they have no own enumerable string keyed + * properties. + * + * Array-like values such as `arguments` objects, arrays, buffers, strings, or + * jQuery-like collections are considered empty if they have a `length` of `0`. + * Similarly, maps and sets are considered empty if they have a `size` of `0`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * _.isEmpty(null); + * // => true + * + * _.isEmpty(true); + * // => true + * + * _.isEmpty(1); + * // => true + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({ 'a': 1 }); + * // => false + */ + function isEmpty(value) { + if (value == null) { + return true; + } + if (isArrayLike(value) && + (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || + isBuffer(value) || isTypedArray(value) || isArguments(value))) { + return !value.length; + } + var tag = getTag(value); + if (tag == mapTag || tag == setTag) { + return !value.size; + } + if (isPrototype(value)) { + return !baseKeys(value).length; + } + for (var key in value) { + if (hasOwnProperty.call(value, key)) { + return false; + } + } + return true; + } + + /** + * Performs a deep comparison between two values to determine if they are + * equivalent. + * + * **Note:** This method supports comparing arrays, array buffers, booleans, + * date objects, error objects, maps, numbers, `Object` objects, regexes, + * sets, strings, symbols, and typed arrays. `Object` objects are compared + * by their own, not inherited, enumerable properties. Functions and DOM + * nodes are compared by strict equality, i.e. `===`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.isEqual(object, other); + * // => true + * + * object === other; + * // => false + */ + function isEqual(value, other) { + return baseIsEqual(value, other); + } + + /** + * This method is like `_.isEqual` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined`, comparisons + * are handled by the method instead. The `customizer` is invoked with up to + * six arguments: (objValue, othValue [, index|key, object, other, stack]). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, othValue) { + * if (isGreeting(objValue) && isGreeting(othValue)) { + * return true; + * } + * } + * + * var array = ['hello', 'goodbye']; + * var other = ['hi', 'goodbye']; + * + * _.isEqualWith(array, other, customizer); + * // => true + */ + function isEqualWith(value, other, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + var result = customizer ? customizer(value, other) : undefined; + return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result; + } + + /** + * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, + * `SyntaxError`, `TypeError`, or `URIError` object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an error object, else `false`. + * @example + * + * _.isError(new Error); + * // => true + * + * _.isError(Error); + * // => false + */ + function isError(value) { + if (!isObjectLike(value)) { + return false; + } + var tag = baseGetTag(value); + return tag == errorTag || tag == domExcTag || + (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value)); + } + + /** + * Checks if `value` is a finite primitive number. + * + * **Note:** This method is based on + * [`Number.isFinite`](https://mdn.io/Number/isFinite). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. + * @example + * + * _.isFinite(3); + * // => true + * + * _.isFinite(Number.MIN_VALUE); + * // => true + * + * _.isFinite(Infinity); + * // => false + * + * _.isFinite('3'); + * // => false + */ + function isFinite(value) { + return typeof value == 'number' && nativeIsFinite(value); + } + + /** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; + } + + /** + * Checks if `value` is an integer. + * + * **Note:** This method is based on + * [`Number.isInteger`](https://mdn.io/Number/isInteger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an integer, else `false`. + * @example + * + * _.isInteger(3); + * // => true + * + * _.isInteger(Number.MIN_VALUE); + * // => false + * + * _.isInteger(Infinity); + * // => false + * + * _.isInteger('3'); + * // => false + */ + function isInteger(value) { + return typeof value == 'number' && value == toInteger(value); + } + + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ + function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ + function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); + } + + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + function isObjectLike(value) { + return value != null && typeof value == 'object'; + } + + /** + * Checks if `value` is classified as a `Map` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + * @example + * + * _.isMap(new Map); + * // => true + * + * _.isMap(new WeakMap); + * // => false + */ + var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; + + /** + * Performs a partial deep comparison between `object` and `source` to + * determine if `object` contains equivalent property values. + * + * **Note:** This method is equivalent to `_.matches` when `source` is + * partially applied. + * + * Partial comparisons will match empty array and empty object `source` + * values against any array or object value, respectively. See `_.isEqual` + * for a list of supported value comparisons. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * + * _.isMatch(object, { 'b': 2 }); + * // => true + * + * _.isMatch(object, { 'b': 1 }); + * // => false + */ + function isMatch(object, source) { + return object === source || baseIsMatch(object, source, getMatchData(source)); + } + + /** + * This method is like `_.isMatch` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined`, comparisons + * are handled by the method instead. The `customizer` is invoked with five + * arguments: (objValue, srcValue, index|key, object, source). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, srcValue) { + * if (isGreeting(objValue) && isGreeting(srcValue)) { + * return true; + * } + * } + * + * var object = { 'greeting': 'hello' }; + * var source = { 'greeting': 'hi' }; + * + * _.isMatchWith(object, source, customizer); + * // => true + */ + function isMatchWith(object, source, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseIsMatch(object, source, getMatchData(source), customizer); + } + + /** + * Checks if `value` is `NaN`. + * + * **Note:** This method is based on + * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as + * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for + * `undefined` and other non-number values. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ + function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some + // ActiveX objects in IE. + return isNumber(value) && value != +value; + } + + /** + * Checks if `value` is a pristine native function. + * + * **Note:** This method can't reliably detect native functions in the presence + * of the core-js package because core-js circumvents this kind of detection. + * Despite multiple requests, the core-js maintainer has made it clear: any + * attempt to fix the detection will be obstructed. As a result, we're left + * with little choice but to throw an error. Unfortunately, this also affects + * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill), + * which rely on core-js. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ + function isNative(value) { + if (isMaskable(value)) { + throw new Error(CORE_ERROR_TEXT); + } + return baseIsNative(value); + } + + /** + * Checks if `value` is `null`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `null`, else `false`. + * @example + * + * _.isNull(null); + * // => true + * + * _.isNull(void 0); + * // => false + */ + function isNull(value) { + return value === null; + } + + /** + * Checks if `value` is `null` or `undefined`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is nullish, else `false`. + * @example + * + * _.isNil(null); + * // => true + * + * _.isNil(void 0); + * // => true + * + * _.isNil(NaN); + * // => false + */ + function isNil(value) { + return value == null; + } + + /** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are + * classified as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a number, else `false`. + * @example + * + * _.isNumber(3); + * // => true + * + * _.isNumber(Number.MIN_VALUE); + * // => true + * + * _.isNumber(Infinity); + * // => true + * + * _.isNumber('3'); + * // => false + */ + function isNumber(value) { + return typeof value == 'number' || + (isObjectLike(value) && baseGetTag(value) == numberTag); + } + + /** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ + function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; + } + + /** + * Checks if `value` is classified as a `RegExp` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + * @example + * + * _.isRegExp(/abc/); + * // => true + * + * _.isRegExp('/abc/'); + * // => false + */ + var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; + + /** + * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 + * double precision number which isn't the result of a rounded unsafe integer. + * + * **Note:** This method is based on + * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. + * @example + * + * _.isSafeInteger(3); + * // => true + * + * _.isSafeInteger(Number.MIN_VALUE); + * // => false + * + * _.isSafeInteger(Infinity); + * // => false + * + * _.isSafeInteger('3'); + * // => false + */ + function isSafeInteger(value) { + return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is classified as a `Set` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + * @example + * + * _.isSet(new Set); + * // => true + * + * _.isSet(new WeakSet); + * // => false + */ + var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; + + /** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ + function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); + } + + /** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ + function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); + } + + /** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ + var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + + /** + * Checks if `value` is `undefined`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * _.isUndefined(void 0); + * // => true + * + * _.isUndefined(null); + * // => false + */ + function isUndefined(value) { + return value === undefined; + } + + /** + * Checks if `value` is classified as a `WeakMap` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a weak map, else `false`. + * @example + * + * _.isWeakMap(new WeakMap); + * // => true + * + * _.isWeakMap(new Map); + * // => false + */ + function isWeakMap(value) { + return isObjectLike(value) && getTag(value) == weakMapTag; + } + + /** + * Checks if `value` is classified as a `WeakSet` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a weak set, else `false`. + * @example + * + * _.isWeakSet(new WeakSet); + * // => true + * + * _.isWeakSet(new Set); + * // => false + */ + function isWeakSet(value) { + return isObjectLike(value) && baseGetTag(value) == weakSetTag; + } + + /** + * Checks if `value` is less than `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, + * else `false`. + * @see _.gt + * @example + * + * _.lt(1, 3); + * // => true + * + * _.lt(3, 3); + * // => false + * + * _.lt(3, 1); + * // => false + */ + var lt = createRelationalOperation(baseLt); + + /** + * Checks if `value` is less than or equal to `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than or equal to + * `other`, else `false`. + * @see _.gte + * @example + * + * _.lte(1, 3); + * // => true + * + * _.lte(3, 3); + * // => true + * + * _.lte(3, 1); + * // => false + */ + var lte = createRelationalOperation(function(value, other) { + return value <= other; + }); + + /** + * Converts `value` to an array. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Array} Returns the converted array. + * @example + * + * _.toArray({ 'a': 1, 'b': 2 }); + * // => [1, 2] + * + * _.toArray('abc'); + * // => ['a', 'b', 'c'] + * + * _.toArray(1); + * // => [] + * + * _.toArray(null); + * // => [] + */ + function toArray(value) { + if (!value) { + return []; + } + if (isArrayLike(value)) { + return isString(value) ? stringToArray(value) : copyArray(value); + } + if (symIterator && value[symIterator]) { + return iteratorToArray(value[symIterator]()); + } + var tag = getTag(value), + func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); + + return func(value); + } + + /** + * Converts `value` to a finite number. + * + * @static + * @memberOf _ + * @since 4.12.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted number. + * @example + * + * _.toFinite(3.2); + * // => 3.2 + * + * _.toFinite(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toFinite(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toFinite('3.2'); + * // => 3.2 + */ + function toFinite(value) { + if (!value) { + return value === 0 ? value : 0; + } + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + var sign = (value < 0 ? -1 : 1); + return sign * MAX_INTEGER; + } + return value === value ? value : 0; + } + + /** + * Converts `value` to an integer. + * + * **Note:** This method is loosely based on + * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger(3.2); + * // => 3 + * + * _.toInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toInteger(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toInteger('3.2'); + * // => 3 + */ + function toInteger(value) { + var result = toFinite(value), + remainder = result % 1; + + return result === result ? (remainder ? result - remainder : result) : 0; + } + + /** + * Converts `value` to an integer suitable for use as the length of an + * array-like object. + * + * **Note:** This method is based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toLength(3.2); + * // => 3 + * + * _.toLength(Number.MIN_VALUE); + * // => 0 + * + * _.toLength(Infinity); + * // => 4294967295 + * + * _.toLength('3.2'); + * // => 3 + */ + function toLength(value) { + return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0; + } + + /** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ + function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); + } + + /** + * Converts `value` to a plain object flattening inherited enumerable string + * keyed properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ + function toPlainObject(value) { + return copyObject(value, keysIn(value)); + } + + /** + * Converts `value` to a safe integer. A safe integer can be compared and + * represented correctly. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toSafeInteger(3.2); + * // => 3 + * + * _.toSafeInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toSafeInteger(Infinity); + * // => 9007199254740991 + * + * _.toSafeInteger('3.2'); + * // => 3 + */ + function toSafeInteger(value) { + return value + ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER) + : (value === 0 ? value : 0); + } + + /** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ + function toString(value) { + return value == null ? '' : baseToString(value); + } + + /*------------------------------------------------------------------------*/ + + /** + * Assigns own enumerable string keyed properties of source objects to the + * destination object. Source objects are applied from left to right. + * Subsequent sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object` and is loosely based on + * [`Object.assign`](https://mdn.io/Object/assign). + * + * @static + * @memberOf _ + * @since 0.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assignIn + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assign({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'c': 3 } + */ + var assign = createAssigner(function(object, source) { + if (isPrototype(source) || isArrayLike(source)) { + copyObject(source, keys(source), object); + return; + } + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + assignValue(object, key, source[key]); + } + } + }); + + /** + * This method is like `_.assign` except that it iterates over own and + * inherited source properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extend + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assign + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assignIn({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } + */ + var assignIn = createAssigner(function(object, source) { + copyObject(source, keysIn(source), object); + }); + + /** + * This method is like `_.assignIn` except that it accepts `customizer` + * which is invoked to produce the assigned values. If `customizer` returns + * `undefined`, assignment is handled by the method instead. The `customizer` + * is invoked with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extendWith + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @see _.assignWith + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignInWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { + copyObject(source, keysIn(source), object, customizer); + }); + + /** + * This method is like `_.assign` except that it accepts `customizer` + * which is invoked to produce the assigned values. If `customizer` returns + * `undefined`, assignment is handled by the method instead. The `customizer` + * is invoked with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @see _.assignInWith + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var assignWith = createAssigner(function(object, source, srcIndex, customizer) { + copyObject(source, keys(source), object, customizer); + }); + + /** + * Creates an array of values corresponding to `paths` of `object`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Array} Returns the picked values. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _.at(object, ['a[0].b.c', 'a[1]']); + * // => [3, 4] + */ + var at = flatRest(baseAt); + + /** + * Creates an object that inherits from the `prototype` object. If a + * `properties` object is given, its own enumerable string keyed properties + * are assigned to the created object. + * + * @static + * @memberOf _ + * @since 2.3.0 + * @category Object + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { + * 'constructor': Circle + * }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ + function create(prototype, properties) { + var result = baseCreate(prototype); + return properties == null ? result : baseAssign(result, properties); + } + + /** + * Assigns own and inherited enumerable string keyed properties of source + * objects to the destination object for all destination properties that + * resolve to `undefined`. Source objects are applied from left to right. + * Once a property is set, additional values of the same property are ignored. + * + * **Note:** This method mutates `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaultsDeep + * @example + * + * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var defaults = baseRest(function(args) { + args.push(undefined, customDefaultsAssignIn); + return apply(assignInWith, undefined, args); + }); + + /** + * This method is like `_.defaults` except that it recursively assigns + * default properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaults + * @example + * + * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); + * // => { 'a': { 'b': 2, 'c': 3 } } + */ + var defaultsDeep = baseRest(function(args) { + args.push(undefined, customDefaultsMerge); + return apply(mergeWith, undefined, args); + }); + + /** + * This method is like `_.find` except that it returns the key of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(o) { return o.age < 40; }); + * // => 'barney' (iteration order is not guaranteed) + * + * // The `_.matches` iteratee shorthand. + * _.findKey(users, { 'age': 1, 'active': true }); + * // => 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findKey(users, 'active'); + * // => 'barney' + */ + function findKey(object, predicate) { + return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); + } + + /** + * This method is like `_.findKey` except that it iterates over elements of + * a collection in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findLastKey(users, function(o) { return o.age < 40; }); + * // => returns 'pebbles' assuming `_.findKey` returns 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.findLastKey(users, { 'age': 36, 'active': true }); + * // => 'barney' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findLastKey(users, 'active'); + * // => 'pebbles' + */ + function findLastKey(object, predicate) { + return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); + } + + /** + * Iterates over own and inherited enumerable string keyed properties of an + * object and invokes `iteratee` for each property. The iteratee is invoked + * with three arguments: (value, key, object). Iteratee functions may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 0.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forInRight + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forIn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed). + */ + function forIn(object, iteratee) { + return object == null + ? object + : baseFor(object, getIteratee(iteratee, 3), keysIn); + } + + /** + * This method is like `_.forIn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forIn + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forInRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'. + */ + function forInRight(object, iteratee) { + return object == null + ? object + : baseForRight(object, getIteratee(iteratee, 3), keysIn); + } + + /** + * Iterates over own enumerable string keyed properties of an object and + * invokes `iteratee` for each property. The iteratee is invoked with three + * arguments: (value, key, object). Iteratee functions may exit iteration + * early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 0.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forOwnRight + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a' then 'b' (iteration order is not guaranteed). + */ + function forOwn(object, iteratee) { + return object && baseForOwn(object, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.forOwn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forOwn + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwnRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. + */ + function forOwnRight(object, iteratee) { + return object && baseForOwnRight(object, getIteratee(iteratee, 3)); + } + + /** + * Creates an array of function property names from own enumerable properties + * of `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the function names. + * @see _.functionsIn + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functions(new Foo); + * // => ['a', 'b'] + */ + function functions(object) { + return object == null ? [] : baseFunctions(object, keys(object)); + } + + /** + * Creates an array of function property names from own and inherited + * enumerable properties of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the function names. + * @see _.functions + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functionsIn(new Foo); + * // => ['a', 'b', 'c'] + */ + function functionsIn(object) { + return object == null ? [] : baseFunctions(object, keysIn(object)); + } + + /** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ + function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; + } + + /** + * Checks if `path` is a direct property of `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = { 'a': { 'b': 2 } }; + * var other = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.has(object, 'a'); + * // => true + * + * _.has(object, 'a.b'); + * // => true + * + * _.has(object, ['a', 'b']); + * // => true + * + * _.has(other, 'a'); + * // => false + */ + function has(object, path) { + return object != null && hasPath(object, path, baseHas); + } + + /** + * Checks if `path` is a direct or inherited property of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.hasIn(object, 'a'); + * // => true + * + * _.hasIn(object, 'a.b'); + * // => true + * + * _.hasIn(object, ['a', 'b']); + * // => true + * + * _.hasIn(object, 'b'); + * // => false + */ + function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); + } + + /** + * Creates an object composed of the inverted keys and values of `object`. + * If `object` contains duplicate values, subsequent values overwrite + * property assignments of previous values. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Object + * @param {Object} object The object to invert. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invert(object); + * // => { '1': 'c', '2': 'b' } + */ + var invert = createInverter(function(result, value, key) { + result[value] = key; + }, constant(identity)); + + /** + * This method is like `_.invert` except that the inverted object is generated + * from the results of running each element of `object` thru `iteratee`. The + * corresponding inverted value of each inverted key is an array of keys + * responsible for generating the inverted value. The iteratee is invoked + * with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.1.0 + * @category Object + * @param {Object} object The object to invert. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invertBy(object); + * // => { '1': ['a', 'c'], '2': ['b'] } + * + * _.invertBy(object, function(value) { + * return 'group' + value; + * }); + * // => { 'group1': ['a', 'c'], 'group2': ['b'] } + */ + var invertBy = createInverter(function(result, value, key) { + if (hasOwnProperty.call(result, value)) { + result[value].push(key); + } else { + result[value] = [key]; + } + }, getIteratee); + + /** + * Invokes the method at `path` of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {...*} [args] The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + * @example + * + * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] }; + * + * _.invoke(object, 'a[0].b.c.slice', 1, 3); + * // => [2, 3] + */ + var invoke = baseRest(baseInvoke); + + /** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ + function keys(object) { + return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); + } + + /** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ + function keysIn(object) { + return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); + } + + /** + * The opposite of `_.mapValues`; this method creates an object with the + * same values as `object` and keys generated by running each own enumerable + * string keyed property of `object` thru `iteratee`. The iteratee is invoked + * with three arguments: (value, key, object). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapValues + * @example + * + * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { + * return key + value; + * }); + * // => { 'a1': 1, 'b2': 2 } + */ + function mapKeys(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee, 3); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, iteratee(value, key, object), value); + }); + return result; + } + + /** + * Creates an object with the same keys as `object` and values generated + * by running each own enumerable string keyed property of `object` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, key, object). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapKeys + * @example + * + * var users = { + * 'fred': { 'user': 'fred', 'age': 40 }, + * 'pebbles': { 'user': 'pebbles', 'age': 1 } + * }; + * + * _.mapValues(users, function(o) { return o.age; }); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + * + * // The `_.property` iteratee shorthand. + * _.mapValues(users, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + */ + function mapValues(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee, 3); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, key, iteratee(value, key, object)); + }); + return result; + } + + /** + * This method is like `_.assign` except that it recursively merges own and + * inherited enumerable string keyed properties of source objects into the + * destination object. Source properties that resolve to `undefined` are + * skipped if a destination value exists. Array and plain object properties + * are merged recursively. Other objects and value types are overridden by + * assignment. Source objects are applied from left to right. Subsequent + * sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'a': [{ 'b': 2 }, { 'd': 4 }] + * }; + * + * var other = { + * 'a': [{ 'c': 3 }, { 'e': 5 }] + * }; + * + * _.merge(object, other); + * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } + */ + var merge = createAssigner(function(object, source, srcIndex) { + baseMerge(object, source, srcIndex); + }); + + /** + * This method is like `_.merge` except that it accepts `customizer` which + * is invoked to produce the merged values of the destination and source + * properties. If `customizer` returns `undefined`, merging is handled by the + * method instead. The `customizer` is invoked with six arguments: + * (objValue, srcValue, key, object, source, stack). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} customizer The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * function customizer(objValue, srcValue) { + * if (_.isArray(objValue)) { + * return objValue.concat(srcValue); + * } + * } + * + * var object = { 'a': [1], 'b': [2] }; + * var other = { 'a': [3], 'b': [4] }; + * + * _.mergeWith(object, other, customizer); + * // => { 'a': [1, 3], 'b': [2, 4] } + */ + var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { + baseMerge(object, source, srcIndex, customizer); + }); + + /** + * The opposite of `_.pick`; this method creates an object composed of the + * own and inherited enumerable property paths of `object` that are not omitted. + * + * **Note:** This method is considerably slower than `_.pick`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to omit. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omit(object, ['a', 'c']); + * // => { 'b': '2' } + */ + var omit = flatRest(function(object, paths) { + var result = {}; + if (object == null) { + return result; + } + var isDeep = false; + paths = arrayMap(paths, function(path) { + path = castPath(path, object); + isDeep || (isDeep = path.length > 1); + return path; + }); + copyObject(object, getAllKeysIn(object), result); + if (isDeep) { + result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone); + } + var length = paths.length; + while (length--) { + baseUnset(result, paths[length]); + } + return result; + }); + + /** + * The opposite of `_.pickBy`; this method creates an object composed of + * the own and inherited enumerable string keyed properties of `object` that + * `predicate` doesn't return truthy for. The predicate is invoked with two + * arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omitBy(object, _.isNumber); + * // => { 'b': '2' } + */ + function omitBy(object, predicate) { + return pickBy(object, negate(getIteratee(predicate))); + } + + /** + * Creates an object composed of the picked `object` properties. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pick(object, ['a', 'c']); + * // => { 'a': 1, 'c': 3 } + */ + var pick = flatRest(function(object, paths) { + return object == null ? {} : basePick(object, paths); + }); + + /** + * Creates an object composed of the `object` properties `predicate` returns + * truthy for. The predicate is invoked with two arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pickBy(object, _.isNumber); + * // => { 'a': 1, 'c': 3 } + */ + function pickBy(object, predicate) { + if (object == null) { + return {}; + } + var props = arrayMap(getAllKeysIn(object), function(prop) { + return [prop]; + }); + predicate = getIteratee(predicate); + return basePickBy(object, props, function(value, path) { + return predicate(value, path[0]); + }); + } + + /** + * This method is like `_.get` except that if the resolved value is a + * function it's invoked with the `this` binding of its parent object and + * its result is returned. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to resolve. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; + * + * _.result(object, 'a[0].b.c1'); + * // => 3 + * + * _.result(object, 'a[0].b.c2'); + * // => 4 + * + * _.result(object, 'a[0].b.c3', 'default'); + * // => 'default' + * + * _.result(object, 'a[0].b.c3', _.constant('default')); + * // => 'default' + */ + function result(object, path, defaultValue) { + path = castPath(path, object); + + var index = -1, + length = path.length; + + // Ensure the loop is entered when path is empty. + if (!length) { + length = 1; + object = undefined; + } + while (++index < length) { + var value = object == null ? undefined : object[toKey(path[index])]; + if (value === undefined) { + index = length; + value = defaultValue; + } + object = isFunction(value) ? value.call(object) : value; + } + return object; + } + + /** + * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, + * it's created. Arrays are created for missing index properties while objects + * are created for all other missing properties. Use `_.setWith` to customize + * `path` creation. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.set(object, 'a[0].b.c', 4); + * console.log(object.a[0].b.c); + * // => 4 + * + * _.set(object, ['x', '0', 'y', 'z'], 5); + * console.log(object.x[0].y.z); + * // => 5 + */ + function set(object, path, value) { + return object == null ? object : baseSet(object, path, value); + } + + /** + * This method is like `_.set` except that it accepts `customizer` which is + * invoked to produce the objects of `path`. If `customizer` returns `undefined` + * path creation is handled by the method instead. The `customizer` is invoked + * with three arguments: (nsValue, key, nsObject). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var object = {}; + * + * _.setWith(object, '[0][1]', 'a', Object); + * // => { '0': { '1': 'a' } } + */ + function setWith(object, path, value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return object == null ? object : baseSet(object, path, value, customizer); + } + + /** + * Creates an array of own enumerable string keyed-value pairs for `object` + * which can be consumed by `_.fromPairs`. If `object` is a map or set, its + * entries are returned. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias entries + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairs(new Foo); + * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) + */ + var toPairs = createToPairs(keys); + + /** + * Creates an array of own and inherited enumerable string keyed-value pairs + * for `object` which can be consumed by `_.fromPairs`. If `object` is a map + * or set, its entries are returned. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias entriesIn + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairsIn(new Foo); + * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) + */ + var toPairsIn = createToPairs(keysIn); + + /** + * An alternative to `_.reduce`; this method transforms `object` to a new + * `accumulator` object which is the result of running each of its own + * enumerable string keyed properties thru `iteratee`, with each invocation + * potentially mutating the `accumulator` object. If `accumulator` is not + * provided, a new object with the same `[[Prototype]]` will be used. The + * iteratee is invoked with four arguments: (accumulator, value, key, object). + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 1.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The custom accumulator value. + * @returns {*} Returns the accumulated value. + * @example + * + * _.transform([2, 3, 4], function(result, n) { + * result.push(n *= n); + * return n % 2 == 0; + * }, []); + * // => [4, 9] + * + * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { + * (result[value] || (result[value] = [])).push(key); + * }, {}); + * // => { '1': ['a', 'c'], '2': ['b'] } + */ + function transform(object, iteratee, accumulator) { + var isArr = isArray(object), + isArrLike = isArr || isBuffer(object) || isTypedArray(object); + + iteratee = getIteratee(iteratee, 4); + if (accumulator == null) { + var Ctor = object && object.constructor; + if (isArrLike) { + accumulator = isArr ? new Ctor : []; + } + else if (isObject(object)) { + accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; + } + else { + accumulator = {}; + } + } + (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) { + return iteratee(accumulator, value, index, object); + }); + return accumulator; + } + + /** + * Removes the property at `path` of `object`. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 7 } }] }; + * _.unset(object, 'a[0].b.c'); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + * + * _.unset(object, ['a', '0', 'b', 'c']); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + */ + function unset(object, path) { + return object == null ? true : baseUnset(object, path); + } + + /** + * This method is like `_.set` except that accepts `updater` to produce the + * value to set. Use `_.updateWith` to customize `path` creation. The `updater` + * is invoked with one argument: (value). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {Function} updater The function to produce the updated value. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.update(object, 'a[0].b.c', function(n) { return n * n; }); + * console.log(object.a[0].b.c); + * // => 9 + * + * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; }); + * console.log(object.x[0].y.z); + * // => 0 + */ + function update(object, path, updater) { + return object == null ? object : baseUpdate(object, path, castFunction(updater)); + } + + /** + * This method is like `_.update` except that it accepts `customizer` which is + * invoked to produce the objects of `path`. If `customizer` returns `undefined` + * path creation is handled by the method instead. The `customizer` is invoked + * with three arguments: (nsValue, key, nsObject). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {Function} updater The function to produce the updated value. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var object = {}; + * + * _.updateWith(object, '[0][1]', _.constant('a'), Object); + * // => { '0': { '1': 'a' } } + */ + function updateWith(object, path, updater, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer); + } + + /** + * Creates an array of the own enumerable string keyed property values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.values(new Foo); + * // => [1, 2] (iteration order is not guaranteed) + * + * _.values('hi'); + * // => ['h', 'i'] + */ + function values(object) { + return object == null ? [] : baseValues(object, keys(object)); + } + + /** + * Creates an array of the own and inherited enumerable string keyed property + * values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.valuesIn(new Foo); + * // => [1, 2, 3] (iteration order is not guaranteed) + */ + function valuesIn(object) { + return object == null ? [] : baseValues(object, keysIn(object)); + } + + /*------------------------------------------------------------------------*/ + + /** + * Clamps `number` within the inclusive `lower` and `upper` bounds. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Number + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + * @example + * + * _.clamp(-10, -5, 5); + * // => -5 + * + * _.clamp(10, -5, 5); + * // => 5 + */ + function clamp(number, lower, upper) { + if (upper === undefined) { + upper = lower; + lower = undefined; + } + if (upper !== undefined) { + upper = toNumber(upper); + upper = upper === upper ? upper : 0; + } + if (lower !== undefined) { + lower = toNumber(lower); + lower = lower === lower ? lower : 0; + } + return baseClamp(toNumber(number), lower, upper); + } + + /** + * Checks if `n` is between `start` and up to, but not including, `end`. If + * `end` is not specified, it's set to `start` with `start` then set to `0`. + * If `start` is greater than `end` the params are swapped to support + * negative ranges. + * + * @static + * @memberOf _ + * @since 3.3.0 + * @category Number + * @param {number} number The number to check. + * @param {number} [start=0] The start of the range. + * @param {number} end The end of the range. + * @returns {boolean} Returns `true` if `number` is in the range, else `false`. + * @see _.range, _.rangeRight + * @example + * + * _.inRange(3, 2, 4); + * // => true + * + * _.inRange(4, 8); + * // => true + * + * _.inRange(4, 2); + * // => false + * + * _.inRange(2, 2); + * // => false + * + * _.inRange(1.2, 2); + * // => true + * + * _.inRange(5.2, 4); + * // => false + * + * _.inRange(-3, -2, -6); + * // => true + */ + function inRange(number, start, end) { + start = toFinite(start); + if (end === undefined) { + end = start; + start = 0; + } else { + end = toFinite(end); + } + number = toNumber(number); + return baseInRange(number, start, end); + } + + /** + * Produces a random number between the inclusive `lower` and `upper` bounds. + * If only one argument is provided a number between `0` and the given number + * is returned. If `floating` is `true`, or either `lower` or `upper` are + * floats, a floating-point number is returned instead of an integer. + * + * **Note:** JavaScript follows the IEEE-754 standard for resolving + * floating-point values which can produce unexpected results. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Number + * @param {number} [lower=0] The lower bound. + * @param {number} [upper=1] The upper bound. + * @param {boolean} [floating] Specify returning a floating-point number. + * @returns {number} Returns the random number. + * @example + * + * _.random(0, 5); + * // => an integer between 0 and 5 + * + * _.random(5); + * // => also an integer between 0 and 5 + * + * _.random(5, true); + * // => a floating-point number between 0 and 5 + * + * _.random(1.2, 5.2); + * // => a floating-point number between 1.2 and 5.2 + */ + function random(lower, upper, floating) { + if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { + upper = floating = undefined; + } + if (floating === undefined) { + if (typeof upper == 'boolean') { + floating = upper; + upper = undefined; + } + else if (typeof lower == 'boolean') { + floating = lower; + lower = undefined; + } + } + if (lower === undefined && upper === undefined) { + lower = 0; + upper = 1; + } + else { + lower = toFinite(lower); + if (upper === undefined) { + upper = lower; + lower = 0; + } else { + upper = toFinite(upper); + } + } + if (lower > upper) { + var temp = lower; + lower = upper; + upper = temp; + } + if (floating || lower % 1 || upper % 1) { + var rand = nativeRandom(); + return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); + } + return baseRandom(lower, upper); + } + + /*------------------------------------------------------------------------*/ + + /** + * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the camel cased string. + * @example + * + * _.camelCase('Foo Bar'); + * // => 'fooBar' + * + * _.camelCase('--foo-bar--'); + * // => 'fooBar' + * + * _.camelCase('__FOO_BAR__'); + * // => 'fooBar' + */ + var camelCase = createCompounder(function(result, word, index) { + word = word.toLowerCase(); + return result + (index ? capitalize(word) : word); + }); + + /** + * Converts the first character of `string` to upper case and the remaining + * to lower case. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to capitalize. + * @returns {string} Returns the capitalized string. + * @example + * + * _.capitalize('FRED'); + * // => 'Fred' + */ + function capitalize(string) { + return upperFirst(toString(string).toLowerCase()); + } + + /** + * Deburrs `string` by converting + * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) + * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A) + * letters to basic Latin letters and removing + * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to deburr. + * @returns {string} Returns the deburred string. + * @example + * + * _.deburr('déjà vu'); + * // => 'deja vu' + */ + function deburr(string) { + string = toString(string); + return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); + } + + /** + * Checks if `string` ends with the given target string. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to inspect. + * @param {string} [target] The string to search for. + * @param {number} [position=string.length] The position to search up to. + * @returns {boolean} Returns `true` if `string` ends with `target`, + * else `false`. + * @example + * + * _.endsWith('abc', 'c'); + * // => true + * + * _.endsWith('abc', 'b'); + * // => false + * + * _.endsWith('abc', 'b', 2); + * // => true + */ + function endsWith(string, target, position) { + string = toString(string); + target = baseToString(target); + + var length = string.length; + position = position === undefined + ? length + : baseClamp(toInteger(position), 0, length); + + var end = position; + position -= target.length; + return position >= 0 && string.slice(position, end) == target; + } + + /** + * Converts the characters "&", "<", ">", '"', and "'" in `string` to their + * corresponding HTML entities. + * + * **Note:** No other characters are escaped. To escape additional + * characters use a third-party library like [_he_](https://mths.be/he). + * + * Though the ">" character is escaped for symmetry, characters like + * ">" and "/" don't need escaping in HTML and have no special meaning + * unless they're part of a tag or unquoted attribute value. See + * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) + * (under "semi-related fun fact") for more details. + * + * When working with HTML you should always + * [quote attribute values](http://wonko.com/post/html-escaping) to reduce + * XSS vectors. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escape('fred, barney, & pebbles'); + * // => 'fred, barney, & pebbles' + */ + function escape(string) { + string = toString(string); + return (string && reHasUnescapedHtml.test(string)) + ? string.replace(reUnescapedHtml, escapeHtmlChar) + : string; + } + + /** + * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", + * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https://lodash\.com/\)' + */ + function escapeRegExp(string) { + string = toString(string); + return (string && reHasRegExpChar.test(string)) + ? string.replace(reRegExpChar, '\\$&') + : string; + } + + /** + * Converts `string` to + * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the kebab cased string. + * @example + * + * _.kebabCase('Foo Bar'); + * // => 'foo-bar' + * + * _.kebabCase('fooBar'); + * // => 'foo-bar' + * + * _.kebabCase('__FOO_BAR__'); + * // => 'foo-bar' + */ + var kebabCase = createCompounder(function(result, word, index) { + return result + (index ? '-' : '') + word.toLowerCase(); + }); + + /** + * Converts `string`, as space separated words, to lower case. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the lower cased string. + * @example + * + * _.lowerCase('--Foo-Bar--'); + * // => 'foo bar' + * + * _.lowerCase('fooBar'); + * // => 'foo bar' + * + * _.lowerCase('__FOO_BAR__'); + * // => 'foo bar' + */ + var lowerCase = createCompounder(function(result, word, index) { + return result + (index ? ' ' : '') + word.toLowerCase(); + }); + + /** + * Converts the first character of `string` to lower case. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.lowerFirst('Fred'); + * // => 'fred' + * + * _.lowerFirst('FRED'); + * // => 'fRED' + */ + var lowerFirst = createCaseFirst('toLowerCase'); + + /** + * Pads `string` on the left and right sides if it's shorter than `length`. + * Padding characters are truncated if they can't be evenly divided by `length`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.pad('abc', 8); + * // => ' abc ' + * + * _.pad('abc', 8, '_-'); + * // => '_-abc_-_' + * + * _.pad('abc', 3); + * // => 'abc' + */ + function pad(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + if (!length || strLength >= length) { + return string; + } + var mid = (length - strLength) / 2; + return ( + createPadding(nativeFloor(mid), chars) + + string + + createPadding(nativeCeil(mid), chars) + ); + } + + /** + * Pads `string` on the right side if it's shorter than `length`. Padding + * characters are truncated if they exceed `length`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padEnd('abc', 6); + * // => 'abc ' + * + * _.padEnd('abc', 6, '_-'); + * // => 'abc_-_' + * + * _.padEnd('abc', 3); + * // => 'abc' + */ + function padEnd(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + return (length && strLength < length) + ? (string + createPadding(length - strLength, chars)) + : string; + } + + /** + * Pads `string` on the left side if it's shorter than `length`. Padding + * characters are truncated if they exceed `length`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padStart('abc', 6); + * // => ' abc' + * + * _.padStart('abc', 6, '_-'); + * // => '_-_abc' + * + * _.padStart('abc', 3); + * // => 'abc' + */ + function padStart(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + return (length && strLength < length) + ? (createPadding(length - strLength, chars) + string) + : string; + } + + /** + * Converts `string` to an integer of the specified radix. If `radix` is + * `undefined` or `0`, a `radix` of `10` is used unless `value` is a + * hexadecimal, in which case a `radix` of `16` is used. + * + * **Note:** This method aligns with the + * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category String + * @param {string} string The string to convert. + * @param {number} [radix=10] The radix to interpret `value` by. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {number} Returns the converted integer. + * @example + * + * _.parseInt('08'); + * // => 8 + * + * _.map(['6', '08', '10'], _.parseInt); + * // => [6, 8, 10] + */ + function parseInt(string, radix, guard) { + if (guard || radix == null) { + radix = 0; + } else if (radix) { + radix = +radix; + } + return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0); + } + + /** + * Repeats the given string `n` times. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to repeat. + * @param {number} [n=1] The number of times to repeat the string. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {string} Returns the repeated string. + * @example + * + * _.repeat('*', 3); + * // => '***' + * + * _.repeat('abc', 2); + * // => 'abcabc' + * + * _.repeat('abc', 0); + * // => '' + */ + function repeat(string, n, guard) { + if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { + n = 1; + } else { + n = toInteger(n); + } + return baseRepeat(toString(string), n); + } + + /** + * Replaces matches for `pattern` in `string` with `replacement`. + * + * **Note:** This method is based on + * [`String#replace`](https://mdn.io/String/replace). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to modify. + * @param {RegExp|string} pattern The pattern to replace. + * @param {Function|string} replacement The match replacement. + * @returns {string} Returns the modified string. + * @example + * + * _.replace('Hi Fred', 'Fred', 'Barney'); + * // => 'Hi Barney' + */ + function replace() { + var args = arguments, + string = toString(args[0]); + + return args.length < 3 ? string : string.replace(args[1], args[2]); + } + + /** + * Converts `string` to + * [snake case](https://en.wikipedia.org/wiki/Snake_case). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the snake cased string. + * @example + * + * _.snakeCase('Foo Bar'); + * // => 'foo_bar' + * + * _.snakeCase('fooBar'); + * // => 'foo_bar' + * + * _.snakeCase('--FOO-BAR--'); + * // => 'foo_bar' + */ + var snakeCase = createCompounder(function(result, word, index) { + return result + (index ? '_' : '') + word.toLowerCase(); + }); + + /** + * Splits `string` by `separator`. + * + * **Note:** This method is based on + * [`String#split`](https://mdn.io/String/split). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to split. + * @param {RegExp|string} separator The separator pattern to split by. + * @param {number} [limit] The length to truncate results to. + * @returns {Array} Returns the string segments. + * @example + * + * _.split('a-b-c', '-', 2); + * // => ['a', 'b'] + */ + function split(string, separator, limit) { + if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) { + separator = limit = undefined; + } + limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; + if (!limit) { + return []; + } + string = toString(string); + if (string && ( + typeof separator == 'string' || + (separator != null && !isRegExp(separator)) + )) { + separator = baseToString(separator); + if (!separator && hasUnicode(string)) { + return castSlice(stringToArray(string), 0, limit); + } + } + return string.split(separator, limit); + } + + /** + * Converts `string` to + * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). + * + * @static + * @memberOf _ + * @since 3.1.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the start cased string. + * @example + * + * _.startCase('--foo-bar--'); + * // => 'Foo Bar' + * + * _.startCase('fooBar'); + * // => 'Foo Bar' + * + * _.startCase('__FOO_BAR__'); + * // => 'FOO BAR' + */ + var startCase = createCompounder(function(result, word, index) { + return result + (index ? ' ' : '') + upperFirst(word); + }); + + /** + * Checks if `string` starts with the given target string. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to inspect. + * @param {string} [target] The string to search for. + * @param {number} [position=0] The position to search from. + * @returns {boolean} Returns `true` if `string` starts with `target`, + * else `false`. + * @example + * + * _.startsWith('abc', 'a'); + * // => true + * + * _.startsWith('abc', 'b'); + * // => false + * + * _.startsWith('abc', 'b', 1); + * // => true + */ + function startsWith(string, target, position) { + string = toString(string); + position = position == null + ? 0 + : baseClamp(toInteger(position), 0, string.length); + + target = baseToString(target); + return string.slice(position, position + target.length) == target; + } + + /** + * Creates a compiled template function that can interpolate data properties + * in "interpolate" delimiters, HTML-escape interpolated data properties in + * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data + * properties may be accessed as free variables in the template. If a setting + * object is given, it takes precedence over `_.templateSettings` values. + * + * **Note:** In the development build `_.template` utilizes + * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) + * for easier debugging. + * + * For more information on precompiling templates see + * [lodash's custom builds documentation](https://lodash.com/custom-builds). + * + * For more information on Chrome extension sandboxes see + * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category String + * @param {string} [string=''] The template string. + * @param {Object} [options={}] The options object. + * @param {RegExp} [options.escape=_.templateSettings.escape] + * The HTML "escape" delimiter. + * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] + * The "evaluate" delimiter. + * @param {Object} [options.imports=_.templateSettings.imports] + * An object to import into the template as free variables. + * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] + * The "interpolate" delimiter. + * @param {string} [options.sourceURL='lodash.templateSources[n]'] + * The sourceURL of the compiled template. + * @param {string} [options.variable='obj'] + * The data object variable name. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the compiled template function. + * @example + * + * // Use the "interpolate" delimiter to create a compiled template. + * var compiled = _.template('hello <%= user %>!'); + * compiled({ 'user': 'fred' }); + * // => 'hello fred!' + * + * // Use the HTML "escape" delimiter to escape data property values. + * var compiled = _.template('<%- value %>'); + * compiled({ 'value': ' + + + + + + + + + + + diff --git a/hw6/Claudio_Maggioni/public/test.js b/hw6/Claudio_Maggioni/public/test.js new file mode 100644 index 0000000..1fd4c10 --- /dev/null +++ b/hw6/Claudio_Maggioni/public/test.js @@ -0,0 +1,103 @@ +function tests() { + + test("App class constructors and methods", function(assert) { + // The App class must be defined + equal(typeof App === 'function', true, "The App class must be defined"); + equal(/^\s*class\s+/.test(App.toString()), true, "App is a function but it is not defined using the class keyword") + + + // The App class constructor should throw an error if its argument is undefined + assert.throws(function() { + new App(undefined) + }, "The App class constructor should throw an error if its argument is undefined") + // The App class constructor should throw an error if its argument is not a canvas + assert.throws(function() { + new App(""); + }, "The App class constructor should throw an error if its argument is not an object") + assert.throws(function() { + new App(1); + }, "The App class constructor should throw an error if its argument is a number") + assert.throws(function() { + new App([]); + }, "The App class constructor should throw an error if its argument is an array") + assert.throws(function() { + new App(true); + }, "The App class constructor should throw an error if its argument is a boolean") + + // The default Stroke Style should be accessible in a static way, and should be equal to "black" + equal(App.defaultStrokeStyle === 'black', true, 'The default Stroke Style should be accessible in a static way, and should be equal to "black"') + + assert.throws(function() { + new App({}); + }, "The App class constructor should throw an error if its argument options object is not pointing to a canvas element under the 'canvas' property") + + const app = new App({canvas: 'test-canvas'}) + equal(app.strokeStyle, "black", "Getter for strokeStyle is not defined") + + // The draw method must be defined + equal(typeof app.draw === 'function', true, "The draw method must be defined") + }); + + + test("History and Stroke object literals fields and methods", function(assert) { + // The Stroke class must be defined + equal(typeof Stroke === 'function', true, "The Stroke class must be defined"); + equal(/^\s*class\s+/.test(Stroke.toString()), true, "Stroke is a function but it is not defined using the class keyword") + + equal(function(){ + try { + const stroke = new Stroke('square') + } catch (err) { + return false + } + + return true + }(), true, "Stroke can be instantiated") + + const stroke = new Stroke('square'); + const stroke1 = new Stroke('circle'); + const stroke2 = new Stroke('triangle'); + history.initializeNewPath() + + assert.throws(function() { + history.push() + }, "Must pass a Stroke instance when you push in the history") + + equal(function() { + try { + history.push(stroke); + } catch (err) { + return false; + } + return true; + }(), true, "History push accepts Stroke instances as a parameter"); + + equal(history.pop()[0] === stroke, true, "Pop returns an array containing the pushed Stroke instance") + + history.initializeNewPath(); + + history.push(stroke); + history.push(stroke1); + history.push(stroke2); + + equal(history.pop().length, 3, "Pop returns an array containing the pushed Stroke instances") + + history.initializeNewPath(); + + equal(history.pop().length, 0, "Pop on an empty history should return an empty array") + + history.initializeNewPath(); //simulate mouse down + + history.push(stroke); //simulate mouse move + history.push(stroke1); //simulate mouse move + + history.initializeNewPath(); //simulate mouse up and down again + + history.push(stroke2); //simulate mouse move + + equal(history.pop().length, 1, "Pop returns an array containing the most recent path (Expected path with 1 Stroke)") + + equal(history.pop().length, 2, "Pop returns an array containing the most recent path (Expected path with 2 Strokes)") + + }); +} diff --git a/hw6/Claudio_Maggioni/routes/bookmarked/router.js b/hw6/Claudio_Maggioni/routes/bookmarked/router.js new file mode 100644 index 0000000..69556fa --- /dev/null +++ b/hw6/Claudio_Maggioni/routes/bookmarked/router.js @@ -0,0 +1,24 @@ +/** @module root/router */ +'use strict'; +// vim: set ts=2 sw=2 et tw=80: + +const express = require('express'); +const router = express.Router(); + +const mongoose = require('mongoose'); +const Favorite = mongoose.model('Favorite'); + +const { error, renderFav } = require('../utils'); + +router.get('/', (req, res) => { + Favorite.find({ bookmarked: true }, (err, favs) => { + if (err) { + return error(err, res); + } + + renderFav(req, res, favs); + }); +}); + +/** router for /root */ +module.exports = router; diff --git a/hw6/Claudio_Maggioni/routes/favourites_db/router.js b/hw6/Claudio_Maggioni/routes/favourites_db/router.js new file mode 100644 index 0000000..efc3cd9 --- /dev/null +++ b/hw6/Claudio_Maggioni/routes/favourites_db/router.js @@ -0,0 +1,158 @@ +/** @module root/router */ +'use strict'; +// vim: set ts=2 sw=2 et tw=80: + +const fs = require('fs'); +const express = require('express'); +const router = express.Router(); +const mongoose = require('mongoose'); +const Favorite = mongoose.model('Favorite'); +const { error, renderFav } = require('../utils'); + +router.post('/', (req, res) => { + if (!req.body.name || !req.body.dataURL) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad create form parameters'); + return; + } + + const data = { + name: req.body.name, + dataURL: req.body.dataURL, + bookmarked: req.body.bookmarked, + }; + const favourite = new Favorite(data); + + if (req.body._id) { + favourite._id = req.body._id; + } + + favourite.save((err, fav) => { + if (err) { + return error(err, res); + } + + res.status = 201; + const _id = fav._id; + renderFav(req, res, Object.assign({ _id }, data), false); + }); +}); + +router.get('/', (req, res) => { + Favorite.find({}, (err, favs) => { + if (err) { + return error(err, res); + } + + renderFav(req, res, favs); + }); +}); + +router.get('/search', (req, res) => { + const filter = Object.assign({}, req.query); + delete filter['dataURL']; + delete filter['_method']; + + Favorite.find(filter, (err, favs) => { + if (err) { + return error(err, res); + } + + renderFav(req, res, favs); + }); +}); + +router.get('/:id', (req, res) => { + Favorite.findById(req.params.id, (err, fav) => { + if (err) { + return error(err, res); + } else if (!fav) { + res.writeHead(404, {'Content-Type': 'text/plain'}); + res.end('Not found'); + } else { + renderFav(req, res, fav, false); + } + }); +}); + +function handleUpdate(partial = false) { + return (req, res) => { + + const edit = {}; + for (const key of ['dataURL', 'name']) { + if (req.body[key]) { + edit[key] = req.body[key]; + } else if (!partial) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad PUT form parameters'); + return; + } + } + + if (req.body.bookmarked !== undefined) { + edit.bookmarked = !!req.body.bookmarked; + } + + Favorite.findByIdAndUpdate(req.params.id, { $set: edit }, { + new: true, + upsert: true, + setDefaultsOnInsert: true, + }, (err, fav) => { + if (err) { + return error(err, res); + } + + console.log(arguments); + + // FIXME: return 201 on creation + res.status = 200; + renderFav(req, res, fav, false); + }); + }; +} + +router.put('/:id', handleUpdate()); +router.patch('/:id', handleUpdate(true)); + + +router.delete('/:id', (req, res) => { + Favorite.findByIdAndDelete(req.params.id, (err, fav) => { + if (err) { + return error(err, res); + } + + if (fav == null) { + res.writeHead(404, { 'Content-Type': 'text/plain' }); + res.end('Favourite not found'); + return; + } + + res.format({ + json: () => res.writeHead(204), + html: () => res.writeHead(302, { 'Location': '/favorites' }) + }); + res.end(); + }); +}); + +router.put('/:id/bookmarked', (req, res) => { + Favorite.findByIdAndUpdate(req.params.id, { + $set: { bookmarked: !!req.body.bookmarked } + }, { new: true }, (err, fav) => { + if (false) { + res.writeHead(404, { 'Content-Type': 'text/plain' }); + res.end('Favourite to bookmark not found'); + } else if (!req.body.bookmarked) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad PUT bookmark form parameters'); + } else { + res.format({ + html: () => renderFav(req, res, fav, false), + json: () => res.json(fav) + }); + } + }); +}); + +/** router for /root */ +module.exports = router; diff --git a/hw6/Claudio_Maggioni/routes/root/router.js b/hw6/Claudio_Maggioni/routes/root/router.js new file mode 100644 index 0000000..170bcc4 --- /dev/null +++ b/hw6/Claudio_Maggioni/routes/root/router.js @@ -0,0 +1,24 @@ +/** @module root/router */ +'use strict'; +// vim: set ts=2 sw=2 et tw=80: + +const express = require('express'); +const router = express.Router(); + +const mongoose = require('mongoose'); +const Favorite = mongoose.model('Favorite'); + +const { error } = require('../utils'); + +router.get('/', (req, res) => { + Favorite.find({}, (err, favs) => { + if (err) { + return error(err, res); + } + + res.render('index.dust', { favs }); + }); +}); + +/** router for /root */ +module.exports = router; diff --git a/hw6/Claudio_Maggioni/routes/routers.js b/hw6/Claudio_Maggioni/routes/routers.js new file mode 100644 index 0000000..f6a885d --- /dev/null +++ b/hw6/Claudio_Maggioni/routes/routers.js @@ -0,0 +1,35 @@ +/** @module routes/routers +* Exposes all routers +*/ +'use strict'; + +const fs = require('fs'); + +const dirEntries = fs.readdirSync(__dirname); +const base = __dirname + '/'; +const routers = {}; + +try{ + dirEntries.forEach(function(dirEntry){ + const stats = fs.statSync(base + dirEntry); + //try to load router of dir + if(stats.isDirectory()){ + try{ + const router = require(base + dirEntry + '/router'); + //add router to our list of routers; + routers[dirEntry] = router; + }catch(err){ + console.log('Could not get router for ' + dirEntry); + console.log(err.toString() + err.stack); + } + } + }); +}catch(err){ + console.log('Error while loading routers'); + console.log(err.stack); + //We don't know what happened, export empty object + routers = {} +}finally{ + module.exports = routers; +} + diff --git a/hw6/Claudio_Maggioni/routes/utils.js b/hw6/Claudio_Maggioni/routes/utils.js new file mode 100644 index 0000000..f62be29 --- /dev/null +++ b/hw6/Claudio_Maggioni/routes/utils.js @@ -0,0 +1,39 @@ +function error(err, res) { + console.error(err); + res.status = 500; + res.format({ + json: () => res.json({error: err}), + html: () => res.render('500.dust', { err: JSON.stringify(err, null, 2) }), + }); + res.end(); +} + +function renderFav(req, res, favs, list = true) { + const makeTestsPass = e => { + return { + _id: e._id, + name: e.name, + dataURL: e.dataURL, + bookmarked: '' + e.bookmarked + } + }; + + if (list) { + favs = favs.map(makeTestsPass); + } else { + favs = makeTestsPass(favs); + } + + if (req.accepts('html')) { + res.render(favs ? 'favourites.dust' : 'favourite.dust', list ? { favs } : favs); + } else if (req.accepts('json')) { + res.json(favs); + } else { + res.writeHead(406); + res.end(); + } +} + +module.exports = { error, renderFav }; + + diff --git a/hw6/Claudio_Maggioni/seed.js b/hw6/Claudio_Maggioni/seed.js new file mode 100644 index 0000000..37f6f53 --- /dev/null +++ b/hw6/Claudio_Maggioni/seed.js @@ -0,0 +1,9 @@ +/** +* Standalond db seed +*/ +var seed = require('./test/seed').seed; + +seed(function(seedData){ + console.log("Seeding complete!") + process.exit(); +}) diff --git a/hw6/Claudio_Maggioni/test/routes/2.favorite.create.js b/hw6/Claudio_Maggioni/test/routes/2.favorite.create.js new file mode 100644 index 0000000..eba15eb --- /dev/null +++ b/hw6/Claudio_Maggioni/test/routes/2.favorite.create.js @@ -0,0 +1,56 @@ +'use strict'; + +var config = require('../../config'); +var should = require('should'); +var seedDb = require('../seed'); +var request = require('supertest'); + +describe('Task 2: Testing Create /favorites routes', function(){ + describe('POST /favorites', function(){ + it('should create a new favorite if the request data is valid', function(done){ + var newFavData = {} + newFavData[config.form._id] = "tt1", + newFavData[config.form.name] = "NicePicture", + newFavData[config.form.dataURL] = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBkPSJNMTgwLDQxLjdoLTUxLjFWMzEuMWg0Mi4yQzE1My4xLDEyLjUsMTI3LjgsMSw5OS45LDFDNDUuMiwxLjEsMC45LDQ1LjQsMSwxMDAuMWMwLDI2LjgsMTAuNyw1MS4xLDI4LjEsNjguOQ0KCQljLTEuNC0yLTIuNC00LjEtMy02LjFjLTEtMy41LTEtNS45LTEuMS0xNS44di00Ny4xaDE0Ljh2NDguNWMwLDMuNC0wLjEsNi42LDEsOS42YzMsNy42LDExLjMsOC41LDE2LDguNWMyLjMsMCw4LjMtMC4xLDEyLjYtMy45DQoJCWM0LjQtMy45LDQuNC04LjQsNC40LTE1di00Ny43aDE0Ljl2NDkuN2MtMC4xLDguOS0wLjEsMTYuMy04LjUsMjMuNWMtOCw3LTE4LjQsNy43LTIzLjgsNy43Yy00LjgsMC05LjUtMC42LTE0LTIuMQ0KCQljLTEuOC0wLjYtMy41LTEuNC01LTIuM2MxNy4xLDE0LDM5LDIyLjQsNjIuOCwyMi40YzU0LjctMC4xLDk5LTQ0LjQsOTguOS05OS4xQzE5OSw3OC4xLDE5MS45LDU4LDE4MCw0MS43eiBNMTc1LjMsOTQuNGwtNi4zLTkNCgkJYzIuMS0xLjQsOC43LTUuNyw4LjctMTcuN2MwLTItMC4yLTQuMS0xLTYuMmMtMS43LTQuMS00LjYtNC45LTYuNi00LjljLTMuNiwwLTQuOSwyLjUtNS43LDQuM2MtMC41LDEuMy0wLjYsMS41LTEuOCw2LjZsLTEuNSw2LjkNCgkJYy0wLjksMy42LTEuMyw1LjQtMiw3LjJjLTEuMSwyLjYtNC41LDkuNi0xNCw5LjZjLTEwLjksMC0xNy44LTkuMi0xNy44LTIyLjZjMC0xMi4zLDYuMS0xOSwxMS42LTIzbDYuNiw4LjgNCgkJYy0yLjgsMS45LTguNSw1LjctOC41LDE0LjhjMCw1LjgsMi42LDEwLjgsNywxMC44YzQuOSwwLDUuOC01LjMsNi44LTEwLjVsMS4zLTUuOWMxLjYtNy43LDQuOC0xOC42LDE3LTE4LjYNCgkJYzEzLjEsMCwxOC40LDEyLjIsMTguNCwyNC4zYzAsMy4yLTAuMyw2LjctMS4zLDEwLjJDMTg1LjEsODMuNCwxODIuMyw5MC4xLDE3NS4zLDk0LjR6Ii8+DQo8L2c+DQo8L3N2Zz4NCg==", + newFavData[config.form.bookmarked] = "true" + + request(config.url) + .post('/favorites') + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .send(newFavData) + .expect('Content-Type', /json/, 'it should respond with Content-Type: application/json' ) + .expect(201) + .end(function(err, res){ + var resFav = JSON.parse(res.text); + should.equal(resFav[config.form._id], newFavData[config.form._id]); + should.equal(resFav[config.form.dataURL], newFavData[config.form.dataURL]); + should.equal(resFav[config.form.bookmarked], newFavData[config.form.bookmarked]); + should.equal(resFav[config.form.name], newFavData[config.form.name]); + done(); + }); + }); + + it('should get a 400 Bad Request if data is invalid #1', function(done){ + var newFavData = { + "invalid": "this object does not have the correct structure", + }; + + request(config.url) + .post('/favorites') + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .send(newFavData) + .expect(400, done); + }); + + it('should get a 400 Bad Request if data is not in json', function(done){ + request(config.url) + .post('/favorites') + .set('Content-Type', 'text/plain') + .set('Accept', 'application/json') + .send("This is a plain text request, it should result in a 400 bad request") + .expect(400, done); + }); + }); +}); diff --git a/hw6/Claudio_Maggioni/test/routes/3.favorite.read.js b/hw6/Claudio_Maggioni/test/routes/3.favorite.read.js new file mode 100644 index 0000000..90b03bb --- /dev/null +++ b/hw6/Claudio_Maggioni/test/routes/3.favorite.read.js @@ -0,0 +1,127 @@ +'use strict'; + +var config = require('../../config'); +var should = require('should'); +var seedDb = require('../seed'); +var request = require('supertest'); +var favsOriginal = require('../seedData'); +var favs = [] +for (let i = 0; i < favsOriginal.length; i++) { + let o = {} + o[config.form._id] = favsOriginal[i]._id + o[config.form.name] = favsOriginal[i].name + o[config.form.dataURL] = favsOriginal[i].dataURL + o[config.form.bookmarked] = favsOriginal[i].bookmarked + favs.push(o) +} + +describe('Task 3: Testing Read for /favorites routes', function(){ + before(seed) + + describe('GET /favorites', function(){ + it('should list all the favs with correct data', function(done){ + request(config.url) + .get('/favorites') + .set('Accept', 'application/json') + .expect('Content-Type', /json/, 'it should respond with json' ) + .expect(200) + .end(function(err, res){ + var resFavs = JSON.parse(res.text); + console.log(resFavs); + resFavs.forEach(function(fav) { + for (let i = 0; i < favs.length; i++) { + if(favs[i][config.form._id] == fav[config.form._id]) { + should.equal(fav[config.form.dataURL], favs[i][config.form.dataURL]); + should.equal(fav[config.form.bookmarked], favs[i][config.form.bookmarked]); + should.equal(fav[config.form.name], favs[i][config.form.name]); + } + } + }) + done(); + }); + }); + }); + + describe('GET /favorites/:favoriteid', function(){ + + it('should get the favorite with correct data', function(done){ + request(config.url) + .get('/favorites/' + favs[1][config.form._id]) + .set('Accept', 'application/json') + .expect('Content-Type', /json/, 'it should respond with json' ) + .expect(200) + .end(function(err, res){ + var resFav = JSON.parse(res.text); + should.equal(resFav[config.form._id], favs[1][config.form._id]); + should.equal(resFav[config.form.dataURL], favs[1][config.form.dataURL]); + should.equal(resFav[config.form.bookmarked], favs[1][config.form.bookmarked]); + should.equal(resFav[config.form.name], favs[1][config.form.name]); + done(); + }); + }); + + it('should respond with a 404 if the favorite does not exist', function(done){ + request(config.url) + .get('/favorites/notValidId') + .set('Accept', 'application/json') + .expect(404, done); + }); + }); + + describe(`GET /favorites/search`, function(){ + it(`should get the favorite with correct data: GET /favorites/search?${config.form._id}`, function(done){ + request(config.url) + .get(`/favorites/search?${config.form._id}=${favs[1][config.form._id]}`) + .set('Accept', 'application/json') + .expect('Content-Type', /json/, 'it should respond with json' ) + .expect(200) + .end(function(err, res){ + var resFavArray = JSON.parse(res.text); + should.equal(resFavArray.length, 1) + var resFav = resFavArray[0] + should.equal(resFav[config.form._id], favs[1][config.form._id]); + should.equal(resFav[config.form.dataURL], favs[1][config.form.dataURL]); + should.equal(resFav[config.form.bookmarked], favs[1][config.form.bookmarked]); + should.equal(resFav[config.form.name], favs[1][config.form.name]); + done(); + }); + }); + + it(`should get the favorite with correct data: GET /favorites/search?${config.form._id}&${config.form.name}`, function(done){ + request(config.url) + .get(`/favorites/search?${config.form._id}=${favs[5][config.form._id]}&${config.form.name}=${favs[5][config.form.name]}`) + .set('Accept', 'application/json') + .expect('Content-Type', /json/, 'it should respond with json' ) + .expect(200) + .end(function(err, res){ + var resFav = JSON.parse(res.text)[0]; + should.equal(resFav[config.form._id], favs[5][config.form._id]); + should.equal(resFav[config.form.dataURL], favs[5][config.form.dataURL]); + should.equal(resFav[config.form.bookmarked], favs[5][config.form.bookmarked]); + should.equal(resFav[config.form.name], favs[5][config.form.name]); + done(); + }); + }); + + it(`should get empty array if there is no match: GET /favorites/search?${config.form.name}`, function(done){ + request(config.url) + .get(`/favorites/search?&${config.form.name}=NoName`) + .set('Accept', 'application/json') + .expect('Content-Type', /json/, 'it should respond with json' ) + .expect(200) + .end(function(err, res){ + var resFavArray = JSON.parse(res.text); + should.equal(resFavArray.length, 0) + done(); + }); + }); + }); + +}); + +function seed(done){ + //seed the db + seedDb.seed(function(seedData){ + done(); + }, favs); +} diff --git a/hw6/Claudio_Maggioni/test/routes/4.favorite.update.js b/hw6/Claudio_Maggioni/test/routes/4.favorite.update.js new file mode 100644 index 0000000..81983f2 --- /dev/null +++ b/hw6/Claudio_Maggioni/test/routes/4.favorite.update.js @@ -0,0 +1,44 @@ +'use strict'; + +var config = require('../../config'); +var should = require('should'); +var seedDb = require('../seed'); +var request = require('supertest'); +var favs = require('../seedData'); + +describe('Task 4: Testing Update on /favorites routes', function(){ + describe('PUT /favorites/:favoriteid', function(){ + it('should change the name of an existing favorite', function(done){ + let reqBody = {} + reqBody[config.form.name] = 'newName' + reqBody[config.form.dataURL] = favs[3][config.form.dataURL] // maggicl: added to comply with assignment + + request(config.url) + .put('/favorites/' + favs[3]._id) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .send(reqBody) + .expect(201) + .end(function(err, res){ + let resPutFav = JSON.parse(res.text) + should(resPutFav[config.form.name], 'newName') + done() + }); + }); + }) + + describe('GET /favorites/:favoriteid', function(){ + it('the name should be changed', function(done){ + request(config.url) + .get('/favorites/' + favs[3]._id) + .set('Accept', 'application/json') + .expect('Content-Type', /json/, 'it should respond with Content-Type: application/json' ) + .expect(200) + .end(function(err, res){ + var favGetFav = JSON.parse(res.text); + should.equal(favGetFav[config.form.name], 'newName'); + done(); + }); + }); + }); +}); diff --git a/hw6/Claudio_Maggioni/test/routes/5.favorite.delete.js b/hw6/Claudio_Maggioni/test/routes/5.favorite.delete.js new file mode 100644 index 0000000..4985765 --- /dev/null +++ b/hw6/Claudio_Maggioni/test/routes/5.favorite.delete.js @@ -0,0 +1,60 @@ +'use strict'; + +var config = require('../../config'); +var should = require('should'); +var seedDb = require('../seed'); +var request = require('supertest'); +var favs = require('../seedData') + +describe('Task 5: Testing Delete for /favorites routes', function(){ + describe('DELETE /favorites/:favoriteid', function(){ + it('should delete an existing favorite', function(done){ + request(config.url) + .del('/favorites/' + favs[1]._id) + .set('Accept', 'application/json') + .expect('Content-Type', /json/, 'it should respond with json' ) + .expect(204) + .end(function(err, res){ + res.text.should.be.empty; + res.body.should.be.empty; + done(); + }); + }); + + it('should not list the previously deleted resource', function(done){ + request(config.url) + .del('/favorites/' + favs[2]._id) + .expect(200) + .end(function(err, res){ + + request(config.url) + .get('/favorites') + .set('Accept', 'application/json') + .expect('Content-Type', /json/, 'it should respond with json' ) + .expect(200) + .end(function(err, res){ + var resFavs = JSON.parse(res.text); + resFavs.forEach(function(fav){ + should.notEqual(fav[config.form._id], favs[2]._id); + }); + done(); + }); + }); + }); + + it('should respond with a 404 for a previously deleted resource', function(done){ + request(config.url) + .delete('/favorites/' + favs[1]._id) + .set('Accept', 'application/json') + .expect(404, done); + }); + + it('should respond with a 404 deleting a resource which does not exist', function(done){ + request(config.url) + .delete('/favorites/invalidId') + .set('Accept', 'application/json') + .expect(404, done); + }); + }); + +}); diff --git a/hw6/Claudio_Maggioni/test/routes/6.bookmarked.read.js b/hw6/Claudio_Maggioni/test/routes/6.bookmarked.read.js new file mode 100644 index 0000000..442772f --- /dev/null +++ b/hw6/Claudio_Maggioni/test/routes/6.bookmarked.read.js @@ -0,0 +1,91 @@ +'use strict'; + +var config = require('../../config'); +var should = require('should'); +var seedDb = require('../seed'); +var request = require('supertest'); +var favs = require('../seedData') + +describe('Task 6: Testing /bookmarked routes and /favorites/:favoriteid/bookmarked', function(){ + + describe('GET /bookmarked', function(){ + it('should list only the bookmarked favs', function(done){ + request(config.url) + .get('/bookmarked') + .set('Accept', 'application/json') + .expect('Content-Type', /json/, 'it should respond with json' ) + .expect(200) + .end(function(err, res){ + var resFavs = JSON.parse(res.text); + resFavs.forEach(function(fav){ + should.equal(fav[config.form.bookmarked], "true"); + }); + done(); + }); + }); + }); + + describe('PUT /favorites/:favoriteid/bookmarked', function(){ + after(drop) + + it('initial bookmarked value should be false', function(done){ + request(config.url) + .get(`/favorites/${favs[0]._id}`) + .set('Accept', 'application/json') + .expect('Content-Type', /json/, 'it should respond with json' ) + .expect(200) + .end(function(err, res){ + var resFav = JSON.parse(res.text); + should(resFav[config.form.bookmarked], "false") + done(); + }); + }); + + it('should change the bookmarked value', function(done){ + const reqBody = {} + reqBody[config.form.bookmarked] = "true" + + request(config.url) + .put(`/favorites/${favs[0]._id}/bookmarked`) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .send(reqBody) + .expect('Content-Type', /json/, 'it should respond with json' ) + .expect(200) + .end(function(err, res){ + var resFav = JSON.parse(res.text); + should(resFav[config.form.bookmarked], "true") + done(); + }); + }); + + it('bookmarked value should be changed', function(done){ + request(config.url) + .get(`/favorites/${favs[0]._id}`) + .set('Accept', 'application/json') + .expect('Content-Type', /json/, 'it should respond with json' ) + .expect(200) + .end(function(err, res){ + var resFav = JSON.parse(res.text); + should(resFav[config.form.bookmarked], "true") + done(); + }); + }); + }); +}); + +function drop(done){ + let deleteIds = ['t0','t3','t4','t5', 'tt1'] + let count = 0 + + for (let i = 0; i < deleteIds.length; i++) { + request(config.url) + .delete(`/favorites/${deleteIds[i]}`) + .end(function() { + count++ + if(count == deleteIds.length) { + done() + } + }) + } +} diff --git a/hw6/Claudio_Maggioni/test/seed.js b/hw6/Claudio_Maggioni/test/seed.js new file mode 100644 index 0000000..87f235a --- /dev/null +++ b/hw6/Claudio_Maggioni/test/seed.js @@ -0,0 +1,46 @@ +'use strict'; + +var config = require('../config'); +var request = require('request'); + +//seedData +var seedData = require('./seedData') + +//total callbacks (one for each model) +var totalCbs = 0; +var cbCnt = 0; + +/** +* Recursive function that goes through +* seedData populating each item of it +*/ +var seedModel = function(done, s){ + if(s != undefined) { + seedData = s + } + totalCbs = seedData.length + + for (let i = 0; i < seedData.length; i++) { + const form = {} + form[config.form._id] = seedData[i]._id + form[config.form.name] = seedData[i].name + form[config.form.dataURL] = seedData[i].dataURL + form[config.form.bookmarked] = seedData[i].bookmarked + + request.post(`${config.url}/favorites`, { + form: form + }, function(error, response, body){ + cbCnt++ + if(cbCnt == totalCbs) { + done(seedData) + } + }) + } +} + +/** +* This is where everything starts +*/ +module.exports.seed = function (done, s){ + seedModel(done, s) +} diff --git a/hw6/Claudio_Maggioni/test/seedData.js b/hw6/Claudio_Maggioni/test/seedData.js new file mode 100644 index 0000000..fe4e0c3 --- /dev/null +++ b/hw6/Claudio_Maggioni/test/seedData.js @@ -0,0 +1,47 @@ +'use strict'; + +var favorites = [ + { + "_id" : "t0", + "name" : "My Nice Image", + "dataURL" : "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBkPSJNMTgwLDQxLjdoLTUxLjFWMzEuMWg0Mi4yQzE1My4xLDEyLjUsMTI3LjgsMSw5OS45LDFDNDUuMiwxLjEsMC45LDQ1LjQsMSwxMDAuMWMwLDI2LjgsMTAuNyw1MS4xLDI4LjEsNjguOQ0KCQljLTEuNC0yLTIuNC00LjEtMy02LjFjLTEtMy41LTEtNS45LTEuMS0xNS44di00Ny4xaDE0Ljh2NDguNWMwLDMuNC0wLjEsNi42LDEsOS42YzMsNy42LDExLjMsOC41LDE2LDguNWMyLjMsMCw4LjMtMC4xLDEyLjYtMy45DQoJCWM0LjQtMy45LDQuNC04LjQsNC40LTE1di00Ny43aDE0Ljl2NDkuN2MtMC4xLDguOS0wLjEsMTYuMy04LjUsMjMuNWMtOCw3LTE4LjQsNy43LTIzLjgsNy43Yy00LjgsMC05LjUtMC42LTE0LTIuMQ0KCQljLTEuOC0wLjYtMy41LTEuNC01LTIuM2MxNy4xLDE0LDM5LDIyLjQsNjIuOCwyMi40YzU0LjctMC4xLDk5LTQ0LjQsOTguOS05OS4xQzE5OSw3OC4xLDE5MS45LDU4LDE4MCw0MS43eiBNMTc1LjMsOTQuNGwtNi4zLTkNCgkJYzIuMS0xLjQsOC43LTUuNyw4LjctMTcuN2MwLTItMC4yLTQuMS0xLTYuMmMtMS43LTQuMS00LjYtNC45LTYuNi00LjljLTMuNiwwLTQuOSwyLjUtNS43LDQuM2MtMC41LDEuMy0wLjYsMS41LTEuOCw2LjZsLTEuNSw2LjkNCgkJYy0wLjksMy42LTEuMyw1LjQtMiw3LjJjLTEuMSwyLjYtNC41LDkuNi0xNCw5LjZjLTEwLjksMC0xNy44LTkuMi0xNy44LTIyLjZjMC0xMi4zLDYuMS0xOSwxMS42LTIzbDYuNiw4LjgNCgkJYy0yLjgsMS45LTguNSw1LjctOC41LDE0LjhjMCw1LjgsMi42LDEwLjgsNywxMC44YzQuOSwwLDUuOC01LjMsNi44LTEwLjVsMS4zLTUuOWMxLjYtNy43LDQuOC0xOC42LDE3LTE4LjYNCgkJYzEzLjEsMCwxOC40LDEyLjIsMTguNCwyNC4zYzAsMy4yLTAuMyw2LjctMS4zLDEwLjJDMTg1LjEsODMuNCwxODIuMyw5MC4xLDE3NS4zLDk0LjR6Ii8+DQo8L2c+DQo8L3N2Zz4NCg==", + "bookmarked" : "false" + }, + + { + "_id" : "t1", + "name" : "My Nice Image 1", + "dataURL" : "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBkPSJNMTgwLDQxLjdoLTUxLjFWMzEuMWg0Mi4yQzE1My4xLDEyLjUsMTI3LjgsMSw5OS45LDFDNDUuMiwxLjEsMC45LDQ1LjQsMSwxMDAuMWMwLDI2LjgsMTAuNyw1MS4xLDI4LjEsNjguOQ0KCQljLTEuNC0yLTIuNC00LjEtMy02LjFjLTEtMy41LTEtNS45LTEuMS0xNS44di00Ny4xaDE0Ljh2NDguNWMwLDMuNC0wLjEsNi42LDEsOS42YzMsNy42LDExLjMsOC41LDE2LDguNWMyLjMsMCw4LjMtMC4xLDEyLjYtMy45DQoJCWM0LjQtMy45LDQuNC04LjQsNC40LTE1di00Ny43aDE0Ljl2NDkuN2MtMC4xLDguOS0wLjEsMTYuMy04LjUsMjMuNWMtOCw3LTE4LjQsNy43LTIzLjgsNy43Yy00LjgsMC05LjUtMC42LTE0LTIuMQ0KCQljLTEuOC0wLjYtMy41LTEuNC01LTIuM2MxNy4xLDE0LDM5LDIyLjQsNjIuOCwyMi40YzU0LjctMC4xLDk5LTQ0LjQsOTguOS05OS4xQzE5OSw3OC4xLDE5MS45LDU4LDE4MCw0MS43eiBNMTc1LjMsOTQuNGwtNi4zLTkNCgkJYzIuMS0xLjQsOC43LTUuNyw4LjctMTcuN2MwLTItMC4yLTQuMS0xLTYuMmMtMS43LTQuMS00LjYtNC45LTYuNi00LjljLTMuNiwwLTQuOSwyLjUtNS43LDQuM2MtMC41LDEuMy0wLjYsMS41LTEuOCw2LjZsLTEuNSw2LjkNCgkJYy0wLjksMy42LTEuMyw1LjQtMiw3LjJjLTEuMSwyLjYtNC41LDkuNi0xNCw5LjZjLTEwLjksMC0xNy44LTkuMi0xNy44LTIyLjZjMC0xMi4zLDYuMS0xOSwxMS42LTIzbDYuNiw4LjgNCgkJYy0yLjgsMS45LTguNSw1LjctOC41LDE0LjhjMCw1LjgsMi42LDEwLjgsNywxMC44YzQuOSwwLDUuOC01LjMsNi44LTEwLjVsMS4zLTUuOWMxLjYtNy43LDQuOC0xOC42LDE3LTE4LjYNCgkJYzEzLjEsMCwxOC40LDEyLjIsMTguNCwyNC4zYzAsMy4yLTAuMyw2LjctMS4zLDEwLjJDMTg1LjEsODMuNCwxODIuMyw5MC4xLDE3NS4zLDk0LjR6Ii8+DQo8L2c+DQo8L3N2Zz4NCg==", + "bookmarked" : "true" + }, + + { + "_id" : "t2", + "name" : "My Nice Image 2", + "dataURL" : "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBkPSJNMTgwLDQxLjdoLTUxLjFWMzEuMWg0Mi4yQzE1My4xLDEyLjUsMTI3LjgsMSw5OS45LDFDNDUuMiwxLjEsMC45LDQ1LjQsMSwxMDAuMWMwLDI2LjgsMTAuNyw1MS4xLDI4LjEsNjguOQ0KCQljLTEuNC0yLTIuNC00LjEtMy02LjFjLTEtMy41LTEtNS45LTEuMS0xNS44di00Ny4xaDE0Ljh2NDguNWMwLDMuNC0wLjEsNi42LDEsOS42YzMsNy42LDExLjMsOC41LDE2LDguNWMyLjMsMCw4LjMtMC4xLDEyLjYtMy45DQoJCWM0LjQtMy45LDQuNC04LjQsNC40LTE1di00Ny43aDE0Ljl2NDkuN2MtMC4xLDguOS0wLjEsMTYuMy04LjUsMjMuNWMtOCw3LTE4LjQsNy43LTIzLjgsNy43Yy00LjgsMC05LjUtMC42LTE0LTIuMQ0KCQljLTEuOC0wLjYtMy41LTEuNC01LTIuM2MxNy4xLDE0LDM5LDIyLjQsNjIuOCwyMi40YzU0LjctMC4xLDk5LTQ0LjQsOTguOS05OS4xQzE5OSw3OC4xLDE5MS45LDU4LDE4MCw0MS43eiBNMTc1LjMsOTQuNGwtNi4zLTkNCgkJYzIuMS0xLjQsOC43LTUuNyw4LjctMTcuN2MwLTItMC4yLTQuMS0xLTYuMmMtMS43LTQuMS00LjYtNC45LTYuNi00LjljLTMuNiwwLTQuOSwyLjUtNS43LDQuM2MtMC41LDEuMy0wLjYsMS41LTEuOCw2LjZsLTEuNSw2LjkNCgkJYy0wLjksMy42LTEuMyw1LjQtMiw3LjJjLTEuMSwyLjYtNC41LDkuNi0xNCw5LjZjLTEwLjksMC0xNy44LTkuMi0xNy44LTIyLjZjMC0xMi4zLDYuMS0xOSwxMS42LTIzbDYuNiw4LjgNCgkJYy0yLjgsMS45LTguNSw1LjctOC41LDE0LjhjMCw1LjgsMi42LDEwLjgsNywxMC44YzQuOSwwLDUuOC01LjMsNi44LTEwLjVsMS4zLTUuOWMxLjYtNy43LDQuOC0xOC42LDE3LTE4LjYNCgkJYzEzLjEsMCwxOC40LDEyLjIsMTguNCwyNC4zYzAsMy4yLTAuMyw2LjctMS4zLDEwLjJDMTg1LjEsODMuNCwxODIuMyw5MC4xLDE3NS4zLDk0LjR6Ii8+DQo8L2c+DQo8L3N2Zz4NCg==", + "bookmarked" : "false" + }, + + { + "_id" : "t3", + "name" : "My Nice Image 3", + "dataURL" : "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBkPSJNMTgwLDQxLjdoLTUxLjFWMzEuMWg0Mi4yQzE1My4xLDEyLjUsMTI3LjgsMSw5OS45LDFDNDUuMiwxLjEsMC45LDQ1LjQsMSwxMDAuMWMwLDI2LjgsMTAuNyw1MS4xLDI4LjEsNjguOQ0KCQljLTEuNC0yLTIuNC00LjEtMy02LjFjLTEtMy41LTEtNS45LTEuMS0xNS44di00Ny4xaDE0Ljh2NDguNWMwLDMuNC0wLjEsNi42LDEsOS42YzMsNy42LDExLjMsOC41LDE2LDguNWMyLjMsMCw4LjMtMC4xLDEyLjYtMy45DQoJCWM0LjQtMy45LDQuNC04LjQsNC40LTE1di00Ny43aDE0Ljl2NDkuN2MtMC4xLDguOS0wLjEsMTYuMy04LjUsMjMuNWMtOCw3LTE4LjQsNy43LTIzLjgsNy43Yy00LjgsMC05LjUtMC42LTE0LTIuMQ0KCQljLTEuOC0wLjYtMy41LTEuNC01LTIuM2MxNy4xLDE0LDM5LDIyLjQsNjIuOCwyMi40YzU0LjctMC4xLDk5LTQ0LjQsOTguOS05OS4xQzE5OSw3OC4xLDE5MS45LDU4LDE4MCw0MS43eiBNMTc1LjMsOTQuNGwtNi4zLTkNCgkJYzIuMS0xLjQsOC43LTUuNyw4LjctMTcuN2MwLTItMC4yLTQuMS0xLTYuMmMtMS43LTQuMS00LjYtNC45LTYuNi00LjljLTMuNiwwLTQuOSwyLjUtNS43LDQuM2MtMC41LDEuMy0wLjYsMS41LTEuOCw2LjZsLTEuNSw2LjkNCgkJYy0wLjksMy42LTEuMyw1LjQtMiw3LjJjLTEuMSwyLjYtNC41LDkuNi0xNCw5LjZjLTEwLjksMC0xNy44LTkuMi0xNy44LTIyLjZjMC0xMi4zLDYuMS0xOSwxMS42LTIzbDYuNiw4LjgNCgkJYy0yLjgsMS45LTguNSw1LjctOC41LDE0LjhjMCw1LjgsMi42LDEwLjgsNywxMC44YzQuOSwwLDUuOC01LjMsNi44LTEwLjVsMS4zLTUuOWMxLjYtNy43LDQuOC0xOC42LDE3LTE4LjYNCgkJYzEzLjEsMCwxOC40LDEyLjIsMTguNCwyNC4zYzAsMy4yLTAuMyw2LjctMS4zLDEwLjJDMTg1LjEsODMuNCwxODIuMyw5MC4xLDE3NS4zLDk0LjR6Ii8+DQo8L2c+DQo8L3N2Zz4NCg==", + "bookmarked" : "true" + }, + + { + "_id" : "t4", + "name" : "My Nice Image 4", + "dataURL" : "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBkPSJNMTgwLDQxLjdoLTUxLjFWMzEuMWg0Mi4yQzE1My4xLDEyLjUsMTI3LjgsMSw5OS45LDFDNDUuMiwxLjEsMC45LDQ1LjQsMSwxMDAuMWMwLDI2LjgsMTAuNyw1MS4xLDI4LjEsNjguOQ0KCQljLTEuNC0yLTIuNC00LjEtMy02LjFjLTEtMy41LTEtNS45LTEuMS0xNS44di00Ny4xaDE0Ljh2NDguNWMwLDMuNC0wLjEsNi42LDEsOS42YzMsNy42LDExLjMsOC41LDE2LDguNWMyLjMsMCw4LjMtMC4xLDEyLjYtMy45DQoJCWM0LjQtMy45LDQuNC04LjQsNC40LTE1di00Ny43aDE0Ljl2NDkuN2MtMC4xLDguOS0wLjEsMTYuMy04LjUsMjMuNWMtOCw3LTE4LjQsNy43LTIzLjgsNy43Yy00LjgsMC05LjUtMC42LTE0LTIuMQ0KCQljLTEuOC0wLjYtMy41LTEuNC01LTIuM2MxNy4xLDE0LDM5LDIyLjQsNjIuOCwyMi40YzU0LjctMC4xLDk5LTQ0LjQsOTguOS05OS4xQzE5OSw3OC4xLDE5MS45LDU4LDE4MCw0MS43eiBNMTc1LjMsOTQuNGwtNi4zLTkNCgkJYzIuMS0xLjQsOC43LTUuNyw4LjctMTcuN2MwLTItMC4yLTQuMS0xLTYuMmMtMS43LTQuMS00LjYtNC45LTYuNi00LjljLTMuNiwwLTQuOSwyLjUtNS43LDQuM2MtMC41LDEuMy0wLjYsMS41LTEuOCw2LjZsLTEuNSw2LjkNCgkJYy0wLjksMy42LTEuMyw1LjQtMiw3LjJjLTEuMSwyLjYtNC41LDkuNi0xNCw5LjZjLTEwLjksMC0xNy44LTkuMi0xNy44LTIyLjZjMC0xMi4zLDYuMS0xOSwxMS42LTIzbDYuNiw4LjgNCgkJYy0yLjgsMS45LTguNSw1LjctOC41LDE0LjhjMCw1LjgsMi42LDEwLjgsNywxMC44YzQuOSwwLDUuOC01LjMsNi44LTEwLjVsMS4zLTUuOWMxLjYtNy43LDQuOC0xOC42LDE3LTE4LjYNCgkJYzEzLjEsMCwxOC40LDEyLjIsMTguNCwyNC4zYzAsMy4yLTAuMyw2LjctMS4zLDEwLjJDMTg1LjEsODMuNCwxODIuMyw5MC4xLDE3NS4zLDk0LjR6Ii8+DQo8L2c+DQo8L3N2Zz4NCg==", + "bookmarked" : "false" + }, + + { + "_id" : "t5", + "name" : "MyNiceImage5", + "dataURL" : "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBkPSJNMTgwLDQxLjdoLTUxLjFWMzEuMWg0Mi4yQzE1My4xLDEyLjUsMTI3LjgsMSw5OS45LDFDNDUuMiwxLjEsMC45LDQ1LjQsMSwxMDAuMWMwLDI2LjgsMTAuNyw1MS4xLDI4LjEsNjguOQ0KCQljLTEuNC0yLTIuNC00LjEtMy02LjFjLTEtMy41LTEtNS45LTEuMS0xNS44di00Ny4xaDE0Ljh2NDguNWMwLDMuNC0wLjEsNi42LDEsOS42YzMsNy42LDExLjMsOC41LDE2LDguNWMyLjMsMCw4LjMtMC4xLDEyLjYtMy45DQoJCWM0LjQtMy45LDQuNC04LjQsNC40LTE1di00Ny43aDE0Ljl2NDkuN2MtMC4xLDguOS0wLjEsMTYuMy04LjUsMjMuNWMtOCw3LTE4LjQsNy43LTIzLjgsNy43Yy00LjgsMC05LjUtMC42LTE0LTIuMQ0KCQljLTEuOC0wLjYtMy41LTEuNC01LTIuM2MxNy4xLDE0LDM5LDIyLjQsNjIuOCwyMi40YzU0LjctMC4xLDk5LTQ0LjQsOTguOS05OS4xQzE5OSw3OC4xLDE5MS45LDU4LDE4MCw0MS43eiBNMTc1LjMsOTQuNGwtNi4zLTkNCgkJYzIuMS0xLjQsOC43LTUuNyw4LjctMTcuN2MwLTItMC4yLTQuMS0xLTYuMmMtMS43LTQuMS00LjYtNC45LTYuNi00LjljLTMuNiwwLTQuOSwyLjUtNS43LDQuM2MtMC41LDEuMy0wLjYsMS41LTEuOCw2LjZsLTEuNSw2LjkNCgkJYy0wLjksMy42LTEuMyw1LjQtMiw3LjJjLTEuMSwyLjYtNC41LDkuNi0xNCw5LjZjLTEwLjksMC0xNy44LTkuMi0xNy44LTIyLjZjMC0xMi4zLDYuMS0xOSwxMS42LTIzbDYuNiw4LjgNCgkJYy0yLjgsMS45LTguNSw1LjctOC41LDE0LjhjMCw1LjgsMi42LDEwLjgsNywxMC44YzQuOSwwLDUuOC01LjMsNi44LTEwLjVsMS4zLTUuOWMxLjYtNy43LDQuOC0xOC42LDE3LTE4LjYNCgkJYzEzLjEsMCwxOC40LDEyLjIsMTguNCwyNC4zYzAsMy4yLTAuMyw2LjctMS4zLDEwLjJDMTg1LjEsODMuNCwxODIuMyw5MC4xLDE3NS4zLDk0LjR6Ii8+DQo8L2c+DQo8L3N2Zz4NCg==", + "bookmarked" : "true" + } +] + +module.exports = favorites; diff --git a/hw6/Claudio_Maggioni/views/500.dust b/hw6/Claudio_Maggioni/views/500.dust new file mode 100644 index 0000000..2424e87 --- /dev/null +++ b/hw6/Claudio_Maggioni/views/500.dust @@ -0,0 +1,14 @@ +{! vim: set ts=2 sw=2 et tw=120: !} + + + + + + +

Error 500

+
+    {err}
+    
+ + + diff --git a/hw6/Claudio_Maggioni/views/favourite.dust b/hw6/Claudio_Maggioni/views/favourite.dust new file mode 100644 index 0000000..3fe4589 --- /dev/null +++ b/hw6/Claudio_Maggioni/views/favourite.dust @@ -0,0 +1,13 @@ +{! vim: set ft=html ts=2 sw=2 et tw=120: !} + + + + + {name} + + + {>"favourite_partial" /} + + + + diff --git a/hw6/Claudio_Maggioni/views/favourite_partial.dust b/hw6/Claudio_Maggioni/views/favourite_partial.dust new file mode 100644 index 0000000..a431d83 --- /dev/null +++ b/hw6/Claudio_Maggioni/views/favourite_partial.dust @@ -0,0 +1,28 @@ +{! vim: set ft=html ts=2 sw=2 et tw=120: !} + +

{name}

+{name} +{?b} +

+ Bookmarked +

+{/b} +{?details} +Details +{:else} +
+ + +
+
+
+ {?b} + + {:else} + + {/b} +
+Favourites list +{/details} diff --git a/hw6/Claudio_Maggioni/views/favourites.dust b/hw6/Claudio_Maggioni/views/favourites.dust new file mode 100644 index 0000000..271d285 --- /dev/null +++ b/hw6/Claudio_Maggioni/views/favourites.dust @@ -0,0 +1,28 @@ +{! vim: set ft=html ts=2 sw=2 et tw=120: !} + + + + + {?bookmarked} + Bookmarked + {:else} + Favourites + {/bookmarked} + + + {?bookmarked} +

Bookmarked

+ {:else} +

Favourites

+ {/bookmarked} + {#favs} +
+ {>"favourite_partial" name=name dataURL=dataURL _id=_id b=b details="true" /} +
+ {:else} + No favourites. + {/favs} + + + + diff --git a/hw6/Claudio_Maggioni/views/index.dust b/hw6/Claudio_Maggioni/views/index.dust new file mode 100644 index 0000000..02c3344 --- /dev/null +++ b/hw6/Claudio_Maggioni/views/index.dust @@ -0,0 +1,41 @@ +{! vim: set ft=html ts=2 sw=2 et tw=120: !} + + + + + + + OO-JS Exercise - Web Atelier 2017 + + + + + +

+ OO-JS Exercise: Canvas +

+
+
+ + + +
+ +
+ +
+
+

Favourites

+
+ {#favs} + {>"favourite_partial" name=name dataURL=dataURL _id=_id b=b details="true" /} + {/favs} +
+ + + + + + + + diff --git a/hw6/Claudio_Maggioni/yarn.lock b/hw6/Claudio_Maggioni/yarn.lock new file mode 100644 index 0000000..eac1985 --- /dev/null +++ b/hw6/Claudio_Maggioni/yarn.lock @@ -0,0 +1,2318 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +ajv@^6.5.5: + version "6.10.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" + integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA== + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= + dependencies: + arr-flatten "^1.0.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +basic-auth@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" + integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== + dependencies: + safe-buffer "5.1.2" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +bluebird@3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== + +body-parser@1.19.0, body-parser@^1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +browser-stdout@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" + integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8= + +bson@^1.1.1, bson@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.1.tgz#4330f5e99104c4e751e7351859e2d408279f2f13" + integrity sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg== + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chokidar@~1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.5.2.tgz#293e728640cc93dd8277424334b3c6d4ad3a348a" + integrity sha1-KT5yhkDMk92Cd0JDNLPG1K06NIo= + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chownr@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" + integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cli/-/cli-1.0.1.tgz#22817534f24bfa4950c34d532d48ecbc621b8c14" + integrity sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ= + dependencies: + exit "0.1.2" + glob "^7.1.1" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== + +component-emitter@^1.2.0, component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +cookiejar@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" + integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^3.1.0, debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +diff@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" + integrity sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww== + +dustjs-linkedin@^2.7.5: + version "2.7.5" + resolved "https://registry.yarnpkg.com/dustjs-linkedin/-/dustjs-linkedin-2.7.5.tgz#618f063f72c19b78c8055ac2301c75b7b6bbdccc" + integrity sha1-YY8GP3LBm3jIBVrCMBx1t7a73Mw= + dependencies: + chokidar "~1.5.1" + cli "^1.0.1" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +exit@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= + dependencies: + is-posix-bracket "^0.1.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= + dependencies: + fill-range "^2.1.0" + +express@^4.16.2: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= + dependencies: + is-extglob "^1.0.0" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= + +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@^2.3.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" + integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +formidable@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659" + integrity sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg== + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs-minipass@^1.2.5: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.0.0: + version "1.2.9" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" + integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== + dependencies: + nan "^2.12.1" + node-pre-gyp "^0.12.0" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= + dependencies: + is-glob "^2.0.0" + +glob@7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.1, glob@^7.1.3: + version "7.1.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0" + integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +graceful-fs@^4.1.11: + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== + +growl@1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" + integrity sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q== + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@0.4.24, iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore-walk@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" + integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== + dependencies: + minimatch "^3.0.4" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +ipaddr.js@1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" + integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= + dependencies: + is-extglob "^1.0.0" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +kareem@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.1.tgz#def12d9c941017fabfb00f873af95e9c99e1be87" + integrity sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +klei-dust@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/klei-dust/-/klei-dust-1.0.0.tgz#493f00faa892298a69d59f3455bc0238c917a674" + integrity sha1-ST8A+qiSKYpp1Z80VbwCOMkXpnQ= + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +math-random@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" + integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +method-override@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/method-override/-/method-override-3.0.0.tgz#6ab0d5d574e3208f15b0c9cf45ab52000468d7a2" + integrity sha512-IJ2NNN/mSl9w3kzWB92rcdHpz+HjkxhDJWNDBqSlas+zQdP8wBiJzITPg08M/k2uVvMow7Sk41atndNtt/PHSA== + dependencies: + debug "3.1.0" + methods "~1.1.2" + parseurl "~1.3.2" + vary "~1.1.2" + +methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +mime-db@1.40.0: + version "1.40.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" + integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== + +mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.24" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" + integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== + dependencies: + mime-db "1.40.0" + +mime@1.6.0, mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +mocha@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" + integrity sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA== + dependencies: + browser-stdout "1.3.0" + commander "2.11.0" + debug "3.1.0" + diff "3.3.1" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.3" + he "1.1.1" + mkdirp "0.5.1" + supports-color "4.4.0" + +mongodb@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.3.3.tgz#509cad2225a1c56c65a331ed73a0d5d4ed5cbe67" + integrity sha512-MdRnoOjstmnrKJsK8PY0PjP6fyF/SBS4R8coxmhsfEU7tQ46/J6j+aSHF2n4c2/H8B+Hc/Klbfp8vggZfI0mmA== + dependencies: + bson "^1.1.1" + require_optional "^1.0.1" + safe-buffer "^5.1.2" + optionalDependencies: + saslprep "^1.0.0" + +mongoose-legacy-pluralize@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz#3ba9f91fa507b5186d399fb40854bff18fb563e4" + integrity sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ== + +mongoose@^5.7.7: + version "5.7.7" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-5.7.7.tgz#038b47d10434ea6cc9ec9b45d88bfcf9ab401a1a" + integrity sha512-FU59waB4LKBa9KOnqBUcCcMIVRc09TFo1F8nMxrzSiIWATaJpjxxSSH5FBVUDxQfNdJLfg9uFHxaTxhhwjsZOQ== + dependencies: + bson "~1.1.1" + kareem "2.3.1" + mongodb "3.3.3" + mongoose-legacy-pluralize "1.0.2" + mpath "0.6.0" + mquery "3.2.2" + ms "2.1.2" + regexp-clone "1.0.0" + safe-buffer "5.1.2" + sift "7.0.1" + sliced "1.0.1" + +morgan@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59" + integrity sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA== + dependencies: + basic-auth "~2.0.0" + debug "2.6.9" + depd "~1.1.2" + on-finished "~2.3.0" + on-headers "~1.0.1" + +mpath@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.6.0.tgz#aa922029fca4f0f641f360e74c5c1b6a4c47078e" + integrity sha512-i75qh79MJ5Xo/sbhxrDrPSEG0H/mr1kcZXJ8dH6URU5jD/knFxCVqVC/gVSW7GIXL/9hHWlT9haLbCXWOll3qw== + +mquery@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.2.tgz#e1383a3951852ce23e37f619a9b350f1fb3664e7" + integrity sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q== + dependencies: + bluebird "3.5.1" + debug "3.1.0" + regexp-clone "^1.0.0" + safe-buffer "5.1.2" + sliced "1.0.1" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@2.1.2, ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nan@^2.12.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" + integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +node-pre-gyp@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" + integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-path@^2.0.0, normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-packlist@^1.1.6: + version "1.4.6" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.6.tgz#53ba3ed11f8523079f1457376dd379ee4ea42ff4" + integrity sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +proxy-addr@~2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" + integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.0" + +psl@^1.1.24: + version "1.4.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2" + integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw== + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +qs@^6.5.1: + version "6.9.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.0.tgz#d1297e2a049c53119cb49cca366adbbacc80b409" + integrity sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA== + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== + dependencies: + is-equal-shallow "^0.1.3" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexp-clone@1.0.0, regexp-clone@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" + integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +request@^2.88.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.0" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require_optional@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e" + integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g== + dependencies: + resolve-from "^2.0.0" + semver "^5.1.0" + +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rimraf@^2.6.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@^5.0.1, safe-buffer@^5.1.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saslprep@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" + integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== + dependencies: + sparse-bitfield "^3.0.3" + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +semver@^5.1.0, semver@^5.3.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +should-equal@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3" + integrity sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA== + dependencies: + should-type "^1.4.0" + +should-format@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/should-format/-/should-format-3.0.3.tgz#9bfc8f74fa39205c53d38c34d717303e277124f1" + integrity sha1-m/yPdPo5IFxT04w01xcwPidxJPE= + dependencies: + should-type "^1.3.0" + should-type-adaptors "^1.0.1" + +should-type-adaptors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz#401e7f33b5533033944d5cd8bf2b65027792e27a" + integrity sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA== + dependencies: + should-type "^1.3.0" + should-util "^1.0.0" + +should-type@^1.3.0, should-type@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/should-type/-/should-type-1.4.0.tgz#0756d8ce846dfd09843a6947719dfa0d4cff5cf3" + integrity sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM= + +should-util@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/should-util/-/should-util-1.0.1.tgz#fb0d71338f532a3a149213639e2d32cbea8bcb28" + integrity sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g== + +should@^13.1.3: + version "13.2.3" + resolved "https://registry.yarnpkg.com/should/-/should-13.2.3.tgz#96d8e5acf3e97b49d89b51feaa5ae8d07ef58f10" + integrity sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ== + dependencies: + should-equal "^2.0.0" + should-format "^3.0.3" + should-type "^1.4.0" + should-type-adaptors "^1.0.1" + should-util "^1.0.0" + +sift@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/sift/-/sift-7.0.1.tgz#47d62c50b159d316f1372f8b53f9c10cd21a4b08" + integrity sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g== + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +sliced@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" + integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" + integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= + dependencies: + memory-pager "^1.0.2" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +superagent@^3.8.3: + version "3.8.3" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" + integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== + dependencies: + component-emitter "^1.2.0" + cookiejar "^2.1.0" + debug "^3.1.0" + extend "^3.0.0" + form-data "^2.3.1" + formidable "^1.2.0" + methods "^1.1.1" + mime "^1.4.1" + qs "^6.5.1" + readable-stream "^2.3.5" + +supertest@^3.0.0: + version "3.4.2" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-3.4.2.tgz#bad7de2e43d60d27c8caeb8ab34a67c8a5f71aad" + integrity sha512-WZWbwceHUo2P36RoEIdXvmqfs47idNNZjCuJOqDz6rvtkk8ym56aU5oglORCpPeXGxT7l9rkJ41+O1lffQXYSA== + dependencies: + methods "^1.1.2" + superagent "^3.8.3" + +supports-color@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" + integrity sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ== + dependencies: + has-flag "^2.0.0" + +tar@^4: + version "4.4.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" + integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.8.6" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +tough-cookie@~2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" + integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +yallist@^3.0.0, yallist@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== From ab8c9c9668fca77e2ee9f947acaefbdec147b3ba Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Mon, 28 Oct 2019 22:12:20 +0100 Subject: [PATCH 3/8] hw6: mandatory tasks done (tests pass, manual test needed for HTML) --- hw6/Claudio_Maggioni/app.js | 3 +- .../routes/favourites_db/router.js | 73 +++++----- .../routes/favourites_db_promises/router.js | 136 ++++++++++++++++++ hw6/Claudio_Maggioni/routes/utils.js | 43 ++++-- .../views/favourite_partial.dust | 4 +- hw6/Claudio_Maggioni/views/favourites.dust | 2 +- hw6/Claudio_Maggioni/views/index.dust | 2 +- 7 files changed, 211 insertions(+), 52 deletions(-) create mode 100644 hw6/Claudio_Maggioni/routes/favourites_db_promises/router.js diff --git a/hw6/Claudio_Maggioni/app.js b/hw6/Claudio_Maggioni/app.js index b9367aa..0ccd0e7 100644 --- a/hw6/Claudio_Maggioni/app.js +++ b/hw6/Claudio_Maggioni/app.js @@ -39,7 +39,8 @@ app.use(express.static('public')); // Initialize routers here const routers = require('./routes/routers'); app.use('/', routers.root); -app.use('/favorites', routers.favourites_db); +// app.use('/favorites', routers.favourites_db); +app.use('/favorites', routers.favourites_db_promises); app.use('/bookmarked', routers.bookmarked); module.exports = app; diff --git a/hw6/Claudio_Maggioni/routes/favourites_db/router.js b/hw6/Claudio_Maggioni/routes/favourites_db/router.js index efc3cd9..cb1d70b 100644 --- a/hw6/Claudio_Maggioni/routes/favourites_db/router.js +++ b/hw6/Claudio_Maggioni/routes/favourites_db/router.js @@ -7,7 +7,17 @@ const express = require('express'); const router = express.Router(); const mongoose = require('mongoose'); const Favorite = mongoose.model('Favorite'); -const { error, renderFav } = require('../utils'); +const { error, renderFav, parseId, notFound } = require('../utils'); + +function findAndRender(filter, req, res) { + Favorite.find(filter, (err, favs) => { + if (err) { + return error(err, res); + } + + renderFav(req, res, favs); + }); +} router.post('/', (req, res) => { if (!req.body.name || !req.body.dataURL) { @@ -25,6 +35,8 @@ router.post('/', (req, res) => { if (req.body._id) { favourite._id = req.body._id; + } else { + favourite._id = mongoose.Types.ObjectId(); } favourite.save((err, fav) => { @@ -39,13 +51,7 @@ router.post('/', (req, res) => { }); router.get('/', (req, res) => { - Favorite.find({}, (err, favs) => { - if (err) { - return error(err, res); - } - - renderFav(req, res, favs); - }); + findAndRender({}, req, res); }); router.get('/search', (req, res) => { @@ -53,25 +59,20 @@ router.get('/search', (req, res) => { delete filter['dataURL']; delete filter['_method']; - Favorite.find(filter, (err, favs) => { - if (err) { - return error(err, res); - } - - renderFav(req, res, favs); - }); + findAndRender(filter, req, res); }); router.get('/:id', (req, res) => { - Favorite.findById(req.params.id, (err, fav) => { + Favorite.findById(parseId(req), (err, fav) => { if (err) { return error(err, res); - } else if (!fav) { - res.writeHead(404, {'Content-Type': 'text/plain'}); - res.end('Not found'); - } else { - renderFav(req, res, fav, false); } + + if (notFound(fav, res)) { + return; + } + + renderFav(req, res, fav, false); }); }); @@ -90,10 +91,10 @@ function handleUpdate(partial = false) { } if (req.body.bookmarked !== undefined) { - edit.bookmarked = !!req.body.bookmarked; + edit.bookmarked = req.body.bookmarked; } - Favorite.findByIdAndUpdate(req.params.id, { $set: edit }, { + Favorite.findByIdAndUpdate(parseId(req), { $set: edit }, { new: true, upsert: true, setDefaultsOnInsert: true, @@ -112,18 +113,16 @@ function handleUpdate(partial = false) { } router.put('/:id', handleUpdate()); + router.patch('/:id', handleUpdate(true)); - router.delete('/:id', (req, res) => { - Favorite.findByIdAndDelete(req.params.id, (err, fav) => { + Favorite.findByIdAndDelete(parseId(req), (err, fav) => { if (err) { return error(err, res); } - if (fav == null) { - res.writeHead(404, { 'Content-Type': 'text/plain' }); - res.end('Favourite not found'); + if (notFound(fav, res)) { return; } @@ -136,20 +135,18 @@ router.delete('/:id', (req, res) => { }); router.put('/:id/bookmarked', (req, res) => { - Favorite.findByIdAndUpdate(req.params.id, { - $set: { bookmarked: !!req.body.bookmarked } + Favorite.findByIdAndUpdate(parseId(req), { + $set: { bookmarked: req.body.bookmarked } }, { new: true }, (err, fav) => { - if (false) { - res.writeHead(404, { 'Content-Type': 'text/plain' }); - res.end('Favourite to bookmark not found'); - } else if (!req.body.bookmarked) { + if (notFound(fav, res)) { + return; + } + + if (!req.body.bookmarked) { res.writeHead(400, { 'Content-Type': 'text/plain' }); res.end('Bad PUT bookmark form parameters'); } else { - res.format({ - html: () => renderFav(req, res, fav, false), - json: () => res.json(fav) - }); + renderFav(req, res, fav, false); } }); }); diff --git a/hw6/Claudio_Maggioni/routes/favourites_db_promises/router.js b/hw6/Claudio_Maggioni/routes/favourites_db_promises/router.js new file mode 100644 index 0000000..3139d2f --- /dev/null +++ b/hw6/Claudio_Maggioni/routes/favourites_db_promises/router.js @@ -0,0 +1,136 @@ +/** @module root/router */ +'use strict'; +// vim: set ts=2 sw=2 et tw=80: + +const fs = require('fs'); +const express = require('express'); +const router = express.Router(); + +const mongoose = require('mongoose'); +const Favorite = mongoose.model('Favorite'); + +const { error, catchErrs, renderFav, parseId, notFound } = require('../utils'); + +function findAndRender(filter, req, res) { + catchErrs(Favorite.find(filter), res).then(favs => { + renderFav(req, res, favs); + }); +} + +router.post('/', (req, res) => { + if (!req.body.name || !req.body.dataURL) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad create form parameters'); + return; + } + + const data = { + name: req.body.name, + dataURL: req.body.dataURL, + bookmarked: req.body.bookmarked, + }; + const favourite = new Favorite(data); + + if (req.body._id) { + favourite._id = req.body._id; + } else { + favourite._id = mongoose.Types.ObjectId(); + } + + catchErrs(favourite.save(), res).then(fav => { + res.status = 201; + const _id = fav._id; + renderFav(req, res, Object.assign({ _id }, data), false); + }); +}); + +router.get('/', (req, res) => { + findAndRender({}, req, res); +}); + +router.get('/search', (req, res) => { + const filter = Object.assign({}, req.query); + delete filter['dataURL']; + delete filter['_method']; + + findAndRender(filter, req, res); +}); + +router.get('/:id', (req, res) => { + catchErrs(Favorite.findById(parseId(req)), res).then(fav => { + if (notFound(fav, res)) { + return; + } + + renderFav(req, res, fav, false); + }); +}); + +function handleUpdate(partial = false) { + return (req, res) => { + const edit = {}; + for (const key of ['dataURL', 'name']) { + if (req.body[key]) { + edit[key] = req.body[key]; + } else if (!partial) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad PUT form parameters'); + return; + } + } + + if (req.body.bookmarked !== undefined) { + edit.bookmarked = req.body.bookmarked; + } + + catchErrs(Favorite.findByIdAndUpdate(parseId(req), { $set: edit }, { + new: true, + upsert: true, + setDefaultsOnInsert: true, + }), res).then(fav => { + console.log(arguments); + + // FIXME: return 201 on creation + res.status = 200; + renderFav(req, res, fav, false); + }); + }; +} + +router.put('/:id', handleUpdate()); + +router.patch('/:id', handleUpdate(true)); + +router.delete('/:id', (req, res) => { + catchErrs(Favorite.findByIdAndDelete(parseId(req)), res).then(fav => { + if (notFound(fav, res)) { + return; + } + + res.format({ + json: () => res.writeHead(204), + html: () => res.writeHead(302, { 'Location': '/favorites' }) + }); + res.end(); + }); +}); + +router.put('/:id/bookmarked', (req, res) => { + catchErrs(Favorite.findByIdAndUpdate(parseId(req), { + $set: { bookmarked: req.body.bookmarked } + }, { new: true }), res).then(fav => { + if (notFound(fav, res)) { + return; + } + + if (!req.body.bookmarked) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad PUT bookmark form parameters'); + } else { + renderFav(req, res, fav, false); + } + }); +}); + +/** router for /root */ +module.exports = router; diff --git a/hw6/Claudio_Maggioni/routes/utils.js b/hw6/Claudio_Maggioni/routes/utils.js index f62be29..215c1d7 100644 --- a/hw6/Claudio_Maggioni/routes/utils.js +++ b/hw6/Claudio_Maggioni/routes/utils.js @@ -1,8 +1,16 @@ +// vim: set ts=2 sw=2 et tw=80: + +const mongoose = require('mongoose'); + +function catchErrs(promise, res) { + return promise.catch(err => error(err, res)); +} + function error(err, res) { console.error(err); res.status = 500; res.format({ - json: () => res.json({error: err}), + json: () => res.json({ error: err }), html: () => res.render('500.dust', { err: JSON.stringify(err, null, 2) }), }); res.end(); @@ -18,15 +26,16 @@ function renderFav(req, res, favs, list = true) { } }; - if (list) { - favs = favs.map(makeTestsPass); - } else { - favs = makeTestsPass(favs); - } - if (req.accepts('html')) { - res.render(favs ? 'favourites.dust' : 'favourite.dust', list ? { favs } : favs); + res.render(list ? 'favourites.dust' : 'favourite.dust', + list ? { favs } : favs); } else if (req.accepts('json')) { + if (list) { + favs = favs.map(makeTestsPass); + } else { + favs = makeTestsPass(favs); + } + res.json(favs); } else { res.writeHead(406); @@ -34,6 +43,22 @@ function renderFav(req, res, favs, list = true) { } } -module.exports = { error, renderFav }; +function parseId(req) { + if (typeof req.params.id === 'string' && req.params.id.length == 24) { + return mongoose.Types.ObjectId(req.params.id); + } else { + return req.params.id; + } +} + +function notFound(e, res) { + if (e == null) { + res.writeHead(404, {'Content-Type': 'text/plain'}); + res.end('Not found'); + return true; + } else return false; +} + +module.exports = { error, renderFav, catchErrs, parseId, notFound }; diff --git a/hw6/Claudio_Maggioni/views/favourite_partial.dust b/hw6/Claudio_Maggioni/views/favourite_partial.dust index a431d83..703a421 100644 --- a/hw6/Claudio_Maggioni/views/favourite_partial.dust +++ b/hw6/Claudio_Maggioni/views/favourite_partial.dust @@ -16,13 +16,13 @@


- {?b} + {?bookmarked} {:else} - {/b} + {/bookmarked} Favourites list {/details} diff --git a/hw6/Claudio_Maggioni/views/favourites.dust b/hw6/Claudio_Maggioni/views/favourites.dust index 271d285..b8dc167 100644 --- a/hw6/Claudio_Maggioni/views/favourites.dust +++ b/hw6/Claudio_Maggioni/views/favourites.dust @@ -17,7 +17,7 @@ {/bookmarked} {#favs}
- {>"favourite_partial" name=name dataURL=dataURL _id=_id b=b details="true" /} + {>"favourite_partial" name=name dataURL=dataURL _id=_id bookmarked=bookmarked details="true" /}
{:else} No favourites. diff --git a/hw6/Claudio_Maggioni/views/index.dust b/hw6/Claudio_Maggioni/views/index.dust index 02c3344..e7febfa 100644 --- a/hw6/Claudio_Maggioni/views/index.dust +++ b/hw6/Claudio_Maggioni/views/index.dust @@ -28,7 +28,7 @@

Favourites

{#favs} - {>"favourite_partial" name=name dataURL=dataURL _id=_id b=b details="true" /} + {>"favourite_partial" name=name dataURL=dataURL _id=_id bookmarked=bookmarked details="true" /} {/favs}
From 9d82eaaad23ff6784e3fcc4d69bbcfa62a39102e Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Mon, 28 Oct 2019 22:45:15 +0100 Subject: [PATCH 4/8] hw6: Fixed 201 (to test) --- .../routes/favourites_db/router.js | 43 +++++++++++-------- .../routes/favourites_db_promises/router.js | 32 ++++++++------ 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/hw6/Claudio_Maggioni/routes/favourites_db/router.js b/hw6/Claudio_Maggioni/routes/favourites_db/router.js index cb1d70b..03bea0c 100644 --- a/hw6/Claudio_Maggioni/routes/favourites_db/router.js +++ b/hw6/Claudio_Maggioni/routes/favourites_db/router.js @@ -29,8 +29,8 @@ router.post('/', (req, res) => { const data = { name: req.body.name, dataURL: req.body.dataURL, - bookmarked: req.body.bookmarked, - }; + bookmarked: req.body.bookmarked + } const favourite = new Favorite(data); if (req.body._id) { @@ -45,8 +45,7 @@ router.post('/', (req, res) => { } res.status = 201; - const _id = fav._id; - renderFav(req, res, Object.assign({ _id }, data), false); + renderFav(req, res, fav, false); }); }); @@ -62,19 +61,23 @@ router.get('/search', (req, res) => { findAndRender(filter, req, res); }); -router.get('/:id', (req, res) => { - Favorite.findById(parseId(req), (err, fav) => { - if (err) { - return error(err, res); - } +function findOne(id) { + return (req, res) => { + Favorite.findById(id(req), (err, fav) => { + if (err) { + return error(err, res); + } - if (notFound(fav, res)) { - return; - } + if (notFound(fav, res)) { + return; + } - renderFav(req, res, fav, false); - }); -}); + renderFav(req, res, fav, false); + }); + }; +} + +router.get('/:id', findOne(req => parseId(req))); function handleUpdate(partial = false) { return (req, res) => { @@ -95,17 +98,21 @@ function handleUpdate(partial = false) { } Favorite.findByIdAndUpdate(parseId(req), { $set: edit }, { - new: true, + new: false, upsert: true, setDefaultsOnInsert: true, + passRawResult: true, }, (err, fav) => { if (err) { return error(err, res); } - console.log(arguments); + if (fav == null) { + res.status = 201; + findOne(() => parseId(req))(req, res); + return; + } - // FIXME: return 201 on creation res.status = 200; renderFav(req, res, fav, false); }); diff --git a/hw6/Claudio_Maggioni/routes/favourites_db_promises/router.js b/hw6/Claudio_Maggioni/routes/favourites_db_promises/router.js index 3139d2f..ca08ca8 100644 --- a/hw6/Claudio_Maggioni/routes/favourites_db_promises/router.js +++ b/hw6/Claudio_Maggioni/routes/favourites_db_promises/router.js @@ -39,8 +39,7 @@ router.post('/', (req, res) => { catchErrs(favourite.save(), res).then(fav => { res.status = 201; - const _id = fav._id; - renderFav(req, res, Object.assign({ _id }, data), false); + renderFav(req, res, fav, false); }); }); @@ -56,15 +55,19 @@ router.get('/search', (req, res) => { findAndRender(filter, req, res); }); -router.get('/:id', (req, res) => { - catchErrs(Favorite.findById(parseId(req)), res).then(fav => { - if (notFound(fav, res)) { - return; - } +function findOne(id) { + return (req, res) => { + catchErrs(Favorite.findById(id(req)), res).then(fav => { + if (notFound(fav, res)) { + return; + } - renderFav(req, res, fav, false); - }); -}); + renderFav(req, res, fav, false); + }); + }; +} + +router.get('/:id', findOne(req => parseId(req))); function handleUpdate(partial = false) { return (req, res) => { @@ -84,13 +87,16 @@ function handleUpdate(partial = false) { } catchErrs(Favorite.findByIdAndUpdate(parseId(req), { $set: edit }, { - new: true, + new: false, upsert: true, setDefaultsOnInsert: true, }), res).then(fav => { - console.log(arguments); + if (fav == null) { + res.status = 201; + findOne(() => parseId(req))(req, res); + return; + } - // FIXME: return 201 on creation res.status = 200; renderFav(req, res, fav, false); }); From 6959f2a6bfe4836782d3fc5bcebde221b6ff4999 Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Mon, 28 Oct 2019 23:05:09 +0100 Subject: [PATCH 5/8] hw6: bonus done (tests pass, needs manual testing for HTML) --- hw6/Claudio_Maggioni/app.js | 3 +- .../routes/favourites_db_asaw/router.js | 164 ++++++++++++++++++ 2 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 hw6/Claudio_Maggioni/routes/favourites_db_asaw/router.js diff --git a/hw6/Claudio_Maggioni/app.js b/hw6/Claudio_Maggioni/app.js index 0ccd0e7..6d61bea 100644 --- a/hw6/Claudio_Maggioni/app.js +++ b/hw6/Claudio_Maggioni/app.js @@ -40,7 +40,8 @@ app.use(express.static('public')); const routers = require('./routes/routers'); app.use('/', routers.root); // app.use('/favorites', routers.favourites_db); -app.use('/favorites', routers.favourites_db_promises); +// app.use('/favorites', routers.favourites_db_promises); +app.use('/favorites', routers.favourites_db_asaw); app.use('/bookmarked', routers.bookmarked); module.exports = app; diff --git a/hw6/Claudio_Maggioni/routes/favourites_db_asaw/router.js b/hw6/Claudio_Maggioni/routes/favourites_db_asaw/router.js new file mode 100644 index 0000000..ae1385d --- /dev/null +++ b/hw6/Claudio_Maggioni/routes/favourites_db_asaw/router.js @@ -0,0 +1,164 @@ +/** @module root/router */ +'use strict'; +// vim: set ts=2 sw=2 et tw=80: + +const fs = require('fs'); +const express = require('express'); +const router = express.Router(); + +const mongoose = require('mongoose'); +const Favorite = mongoose.model('Favorite'); + +const { error, catchErrs, renderFav, parseId, notFound } = require('../utils'); + +async function findAndRender(filter, req, res) { + try { + const favs = await Favorite.find(filter); + renderFav(req, res, favs); + } catch(e) { + error(e, res); + } +} + +router.post('/', async (req, res) => { + if (!req.body.name || !req.body.dataURL) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad create form parameters'); + return; + } + + const data = { + name: req.body.name, + dataURL: req.body.dataURL, + bookmarked: req.body.bookmarked, + }; + const favourite = new Favorite(data); + + if (req.body._id) { + favourite._id = req.body._id; + } else { + favourite._id = mongoose.Types.ObjectId(); + } + + try { + const fav = await favourite.save(); + res.status = 201; + renderFav(req, res, fav, false); + } catch(e) { + error(e, res); + } +}); + +router.get('/', async (req, res) => { + await findAndRender({}, req, res); +}); + +router.get('/search', async (req, res) => { + const filter = Object.assign({}, req.query); + delete filter['dataURL']; + delete filter['_method']; + + await findAndRender(filter, req, res); +}); + +function findOne(id) { + return async (req, res) => { + try { + const fav = await Favorite.findById(id(req)); + + if (notFound(fav, res)) { + return; + } + + renderFav(req, res, fav, false); + } catch(e) { + error(e, res); + } + }; +} + +router.get('/:id', findOne(req => parseId(req))); + +function handleUpdate(partial = false) { + return async (req, res) => { + const edit = {}; + for (const key of ['dataURL', 'name']) { + if (req.body[key]) { + edit[key] = req.body[key]; + } else if (!partial) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad PUT form parameters'); + return; + } + } + + if (req.body.bookmarked !== undefined) { + edit.bookmarked = req.body.bookmarked; + } + + try { + const fav = await Favorite.findByIdAndUpdate(parseId(req), { $set: edit }, { + new: false, + upsert: true, + setDefaultsOnInsert: true, + }); + + if (fav == null) { + res.status = 201; + await findOne(() => parseId(req))(req, res); + return; + } + + res.status = 200; + renderFav(req, res, fav, false); + } catch (e) { + error(e, res); + } + }; +} + +router.put('/:id', handleUpdate()); + +router.patch('/:id', handleUpdate(true)); + +router.delete('/:id', async (req, res) => { + try { + const fav = await Favorite.findByIdAndDelete(parseId(req)); + + if (notFound(fav, res)) { + return; + } + + res.format({ + json: () => res.writeHead(204), + html: () => res.writeHead(302, { 'Location': '/favorites' }) + }); + res.end(); + } catch (e) { + error(e, res); + } +}); + +router.put('/:id/bookmarked', (req, res) => { + try { + const fav = Favorite.findByIdAndUpdate(parseId(req), { + $set: { bookmarked: req.body.bookmarked } + }, { new: true }); + + if (notFound(fav, res)) { + return; + } + + if (!req.body.bookmarked) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad PUT bookmark form parameters'); + } else { + renderFav(req, res, fav, false); + } + } catch (e) { + error(e, res); + } +}); + +/** router for /root */ +module.exports = router; From 6e78f24bdd77fb58e8190dce51262b38837c8857 Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Mon, 28 Oct 2019 23:06:24 +0100 Subject: [PATCH 6/8] hw6: ready for submission --- hw6/Claudio_Maggioni/readme.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 hw6/Claudio_Maggioni/readme.md diff --git a/hw6/Claudio_Maggioni/readme.md b/hw6/Claudio_Maggioni/readme.md new file mode 100644 index 0000000..4d21af5 --- /dev/null +++ b/hw6/Claudio_Maggioni/readme.md @@ -0,0 +1,2 @@ +# Bonuses implemented: +- *Excercise 4*, Use mongoose and MongoDB with async/await From eedf00fdcc8dec558d3889ffbb55839bf54dc6e8 Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Tue, 29 Oct 2019 11:49:56 +0100 Subject: [PATCH 7/8] hw6: 400 on mongoose errors --- hw6/Claudio_Maggioni/routes/utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw6/Claudio_Maggioni/routes/utils.js b/hw6/Claudio_Maggioni/routes/utils.js index 215c1d7..0225b51 100644 --- a/hw6/Claudio_Maggioni/routes/utils.js +++ b/hw6/Claudio_Maggioni/routes/utils.js @@ -8,7 +8,8 @@ function catchErrs(promise, res) { function error(err, res) { console.error(err); - res.status = 500; + res.status = err instanceof mongoose.CastError || + err instanceof mongoose.TypeError ? 400 : 500; res.format({ json: () => res.json({ error: err }), html: () => res.render('500.dust', { err: JSON.stringify(err, null, 2) }), From f791834a2ebd48bcd95a84adae1b89ca64a0c89e Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Fri, 1 Nov 2019 15:06:59 +0100 Subject: [PATCH 8/8] Removed ft=html from dust files --- hw5/Claudio_Maggioni/views/favourite.dust | 2 +- .../views/favourite_partial.dust | 2 +- hw5/Claudio_Maggioni/views/favourites.dust | 2 +- hw5/Claudio_Maggioni/views/index.dust | 2 +- hw6/Claudio_Maggioni.zip | Bin 0 -> 239950 bytes hw6/Claudio_Maggioni/views/favourite.dust | 2 +- .../views/favourite_partial.dust | 2 +- hw6/Claudio_Maggioni/views/favourites.dust | 2 +- hw6/Claudio_Maggioni/views/index.dust | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 hw6/Claudio_Maggioni.zip diff --git a/hw5/Claudio_Maggioni/views/favourite.dust b/hw5/Claudio_Maggioni/views/favourite.dust index 3fe4589..314dccb 100644 --- a/hw5/Claudio_Maggioni/views/favourite.dust +++ b/hw5/Claudio_Maggioni/views/favourite.dust @@ -1,4 +1,4 @@ -{! vim: set ft=html ts=2 sw=2 et tw=120: !} +{! vim: set ts=2 sw=2 et tw=120: !} diff --git a/hw5/Claudio_Maggioni/views/favourite_partial.dust b/hw5/Claudio_Maggioni/views/favourite_partial.dust index a431d83..5f482bd 100644 --- a/hw5/Claudio_Maggioni/views/favourite_partial.dust +++ b/hw5/Claudio_Maggioni/views/favourite_partial.dust @@ -1,4 +1,4 @@ -{! vim: set ft=html ts=2 sw=2 et tw=120: !} +{! vim: set ts=2 sw=2 et tw=120: !}

{name}

{name} diff --git a/hw5/Claudio_Maggioni/views/favourites.dust b/hw5/Claudio_Maggioni/views/favourites.dust index 271d285..1e5eb93 100644 --- a/hw5/Claudio_Maggioni/views/favourites.dust +++ b/hw5/Claudio_Maggioni/views/favourites.dust @@ -1,4 +1,4 @@ -{! vim: set ft=html ts=2 sw=2 et tw=120: !} +{! vim: set ts=2 sw=2 et tw=120: !} diff --git a/hw5/Claudio_Maggioni/views/index.dust b/hw5/Claudio_Maggioni/views/index.dust index 02c3344..cf7a41e 100644 --- a/hw5/Claudio_Maggioni/views/index.dust +++ b/hw5/Claudio_Maggioni/views/index.dust @@ -1,4 +1,4 @@ -{! vim: set ft=html ts=2 sw=2 et tw=120: !} +{! vim: set ts=2 sw=2 et tw=120: !} diff --git a/hw6/Claudio_Maggioni.zip b/hw6/Claudio_Maggioni.zip new file mode 100644 index 0000000000000000000000000000000000000000..c660f07901afb2e9d7a749098e9f4173e920b556 GIT binary patch literal 239950 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�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 O=KB3Bl}#!K+FBRy9?o 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 literal 0 HcmV?d00001 diff --git a/hw6/Claudio_Maggioni/views/favourite.dust b/hw6/Claudio_Maggioni/views/favourite.dust index 3fe4589..314dccb 100644 --- a/hw6/Claudio_Maggioni/views/favourite.dust +++ b/hw6/Claudio_Maggioni/views/favourite.dust @@ -1,4 +1,4 @@ -{! vim: set ft=html ts=2 sw=2 et tw=120: !} +{! vim: set ts=2 sw=2 et tw=120: !} diff --git a/hw6/Claudio_Maggioni/views/favourite_partial.dust b/hw6/Claudio_Maggioni/views/favourite_partial.dust index 703a421..3956706 100644 --- a/hw6/Claudio_Maggioni/views/favourite_partial.dust +++ b/hw6/Claudio_Maggioni/views/favourite_partial.dust @@ -1,4 +1,4 @@ -{! vim: set ft=html ts=2 sw=2 et tw=120: !} +{! vim: set ts=2 sw=2 et tw=120: !}

{name}

{name} diff --git a/hw6/Claudio_Maggioni/views/favourites.dust b/hw6/Claudio_Maggioni/views/favourites.dust index b8dc167..261b394 100644 --- a/hw6/Claudio_Maggioni/views/favourites.dust +++ b/hw6/Claudio_Maggioni/views/favourites.dust @@ -1,4 +1,4 @@ -{! vim: set ft=html ts=2 sw=2 et tw=120: !} +{! vim: set ts=2 sw=2 et tw=120: !} diff --git a/hw6/Claudio_Maggioni/views/index.dust b/hw6/Claudio_Maggioni/views/index.dust index e7febfa..27d5932 100644 --- a/hw6/Claudio_Maggioni/views/index.dust +++ b/hw6/Claudio_Maggioni/views/index.dust @@ -1,4 +1,4 @@ -{! vim: set ft=html ts=2 sw=2 et tw=120: !} +{! vim: set ts=2 sw=2 et tw=120: !}