{"id":16939474,"url":"https://github.com/a8m/agile","last_synced_at":"2025-03-17T08:36:49.395Z","repository":{"id":22266248,"uuid":"25600346","full_name":"a8m/agile","owner":"a8m","description":"Like Underscore, but with zero callbacks and really more fun, v0.0.2","archived":false,"fork":false,"pushed_at":"2017-04-16T19:26:09.000Z","size":874,"stargazers_count":69,"open_issues_count":5,"forks_count":5,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-04-26T20:07:11.485Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/a8m.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-10-22T19:32:50.000Z","updated_at":"2024-03-07T12:58:18.000Z","dependencies_parsed_at":"2022-08-21T01:00:52.119Z","dependency_job_id":null,"html_url":"https://github.com/a8m/agile","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a8m%2Fagile","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a8m%2Fagile/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a8m%2Fagile/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a8m%2Fagile/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/a8m","download_url":"https://codeload.github.com/a8m/agile/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243852425,"owners_count":20358270,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T21:04:50.043Z","updated_at":"2025-03-17T08:36:49.004Z","avatar_url":"https://github.com/a8m.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"#Agile.js \n[![NPM version][npm-image]][npm-url]\n[![Build status][travis-image]][travis-url]\n[![Test coverage][coveralls-image]][coveralls-url]\n[![Dependency Status][david-image]][david-url]\n[![License][license-image]][license-url]\n[![Downloads][downloads-image]][downloads-url]\n\u003eLike Underscore, but with zero callbacks and really more fun, **v0.0.2**\n\n- [Get Started](#get-started)\n- [Contributing](#contributing)\n- [Collection](#collection)\n  - [add](#add)\n  - [after](#after)\n  - [afterWhere](#afterwhere)\n  - [before](#before)\n  - [beforeWhere](#beforeWhere)\n  - [contains](#contains)\n  - [countBy](#countby)\n  - [defaults](#defaults)\n  - [every](#every)\n  - [filter](#filter)\n  - [find](#find)\n  - [findIndex](#findindex)\n  - [findLast](#findlast)\n  - [findLastIndex](#findlastindex)\n  - [first](#first)\n  - [flatten](#flatten)\n  - [groupBy](#groupby)\n  - [last](#last)\n  - [map](#map)\n  - [max](#max)\n  - [min](#min)\n  - [omit](#omit)\n  - [orderBy](#orderby)\n  - [remove](#remove)\n  - [reverse](#reverse)\n  - [some](#contains)\n  - [sortBy](#orderby)\n  - [sum](#sum)\n  - [pick](#filter)\n  - [pluck](#map)\n  - [unique](#unique)\n  - [xor](#xor)\n- [Object](#object)\n  - [keys](#keys)\n  - [toArray](#toarray)\n  - [parse](#parse)\n- [String](#string)\n  - [endsWith](#endswith)\n  - [ltrim](#ltrim)\n  - [repeat](#repeat)\n  - [rtrim](#rtrim)\n  - [reverse](#reverse)\n  - [slugify](#slugify)\n  - [startsWith](#startswith)\n  - [stringular](#stringular)\n  - [stripTags](#striptags)\n  - [trim](#trim)\n  - [truncate](#truncate)\n  - [ucfirst](#ucfirst)\n  - [wrap](#wrap)\n- [Utils](#utils)\n  - [copy](#copy)\n  - [dictionary](#dictionary)\n  - [equals](#equals)\n  - [extend](#extend)\n  - [identity](#identity)\n  - [forEach](#foreach)\n  - [lowercase](#lowercase)\n  - [uppercase](#uppercase)\n  - [noop](#noop)\n  - [toJson](#tojson)\n- [Boolean](#boolean)\n  - [isArray](#isarray)\n  - [isDate](#isdate)\n  - [isDefined](#isdefined)\n  - [isUndefined](#isundefined)\n  - [isString](#isstring)\n  - [isObject](#isobject)\n  - [isNumber](#isnumber)\n  - [isFunction](#isfunction)\n  - [isEmpty](#isempty)\n\n#Get Started\n**(1)** You can install **agile.js** using 3 different methods:  \n- clone \u0026 [build](#developing) this repository\n- via **[Bower](http://bower.io/)**: by running `$ bower install agile` from your terminal\n- via **[npm](https://www.npmjs.org/)**: by running `$ npm install agile` from your terminal\n- soon, \u003ci\u003ecdnjs\u003c/i\u003e will be one of the options\n\n**(2)** Add to your project:  \n**For the Browser:**  \nInclude `agile.js` (or `agile.min.js`) in your `index.html`.  \n```html\n\u003cscript src=\"bower_components/agile/dist/agile.js\"\u003e\u003c/script\u003e\n```\n**For Node Apps:**  \n```js\nvar _ = require('agile');\n```\n**(3)** Start Playing with agile.js:\n```js\nvar orders = [\n  { id: 21, customer: { id: 2, name: 'John P.' }, product: { price: 21.12 }  },\n  { id: 22, customer: { id: 1, name: 'Cati P.' }, product: { price: 89.21 }  },\n  { id: 23, customer: { id: 1, name: 'Cati P.' }, product: { price: 49.00 }  },\n  { id: 24, customer: { id: 3, name: 'Poul S.' }, product: { price: 10.22 }  },\n  { id: 25, customer: { id: 4, name: 'Erik L.' }, product: { price: 11.31 }  },\n  { id: 26, customer: { id: 4, name: 'Erik L.' }, product: { price: 90.99 }  },\n  { id: 27, customer: { id: 2, name: 'Cati P.' }, product: { price: 88.99 }  }\n];\n_(orders)               // ArrayWrapper\n  .map('product.price') // [21.12, 89.21, 49, 10.22, 11.31, 90.99, 88.99]\n  .sum()                // 360.84\n  .round()              // 361\n  .add(10)              // 371\n  .value();             // get the value;\n```\n\n#Collection\n###after\nget a collection and specified count, and returns all of the items in the collection after the specified count.  \n**Usage:** `_.after(array, count)`\n```js\nvar users = [\n    { name: 'foo' },\n    { name: 'bar' },\n    { name: 'baz' },\n    { name: 'zap' }\n];\n\n_.after(users, 2);\n// → [ { name: 'baz' }, { name: 'zap' } ]\n```\n###afterWhere\nget a collection and `expression`/`callback`, and returns all of the items in the collection after the first that return true, include it.  \n**Usage:** `_.afterWhere(array, expression/callback)`\n```js\nvar orders = [\n    { id: 1, date: 'Tue Jul 15 2014' },\n    { id: 2, date: 'Tue Jul 16 2014' },\n    { id: 3, date: 'Tue Jul 17 2014' },\n    { id: 4, date: 'Tue Jul 18 2014' },\n    { id: 5, date: 'Tue Jul 19 2014' }\n];\n\n_.afterWhere(orders, 'date == \"Tue Jul 17 2014\"');\n// → [ orders[2], orders[3], orders[4] ]\n\n_.afterWhere(orders, 'id \u003e 3');\n// → [ orders[3], orders[4] ]\n\n_.afterWhere(orders, function(e) { \n    return e.id \u003e 3;\n});\n// → [ orders[3], orders[4] ]\n```\n###add\n`add` is similar to `Array.push`, but can get a multiple arguments, and return the array instead of the value.  \n**Usage:** `_.add(array, args)`\n```js\n_.add([1,2,3], 4,5,6); // → [1, 2, 3, 4, 5, 6]\n```\n\n###before\nget a collection and specified count, and returns all of the items in the collection before the specified count.  \n**Usage:** `_.before(array, count)`\n```js\nvar users = [\n    { name: 'foo' },\n    { name: 'bar' },\n    { name: 'baz' },\n    { name: 'zap' }\n];\n\n_.before(users, 2);\n// → [ { name: 'foo' }, { name: 'bar' } ]\n```\n###beforeWhere\nget a collection and `expression`/`callback`, and returns all of the items in the collection before the first that return true, including it.  \n**Usage:** `_.beforeWhere(array, expression/callback)`\n```js\nvar orders = [\n    { id: 1, date: 'Tue Jul 15 2014' },\n    { id: 2, date: 'Tue Jul 16 2014' },\n    { id: 3, date: 'Tue Jul 17 2014' },\n    { id: 4, date: 'Tue Jul 18 2014' },\n    { id: 5, date: 'Tue Jul 19 2014' }\n];\n\n_.beforeWhere(orders, 'date == \"Tue Jul 17 2014\"');\n// → [ orders[0], orders[1], orders[2] ]\n\n_.beforeWhere(orders, 'id \u003c 3');\n// → [ orders[0], orders[1] ]\n\n_.beforeWhere(orders, function(e) { \n    return e.id \u003c 3;\n});\n// → [ orders[0], orders[1] ]\n```\n###contains\nChecks if given expression(or value) is present in one or more object in the array.  \n**Usage:** `_.contains(array, expression/callback/value)`  \n**Aliases:** `_.some`\n```js\nvar nums = [1,2,3,4];\n_.contains(num, 2); \n// → true\n\nvar users = [\n  { user: { id: 2, name: 'foo' } },\n  { user: { id: 4, name: 'bar' } },\n  { user: { id: 6, name: 'baz' } }\n];\n_.some(users, '!(user.id % 2)');\n// → true\n_.some(users, '(user.id \u003e 5)');\n// → false\n```\n###countBy\nCreate an object composed of keys generated from the result of the running expression, each key is the count of objects in each group.  \n**Usage:** `_.countBy(array, expression/callback)`\n```js\nvar players = [\n  {name: 'Gene',    team: { name: 'alpha' } },\n  {name: 'George',  team: { name: 'beta'  } },\n  {name: 'Steve',   team: { name: 'gamma' } },\n  {name: 'Paula',   team: { name: 'beta'  } },\n  {name: 'Scruath', team: { name: 'gamma' } }\n];\n_.countBy(players, 'team.name');\n// → { alpha: 1, beta:  2, gamma:2 }\n```\n###defaults\ndefaults allows to specify a default fallback value for properties that resolve to undefined.  \n**Usage:** `_.defaults(array, object)`\n```js\nvar orders = [\n      { id:1, destination: { zip: 21908 }, name: 'Ariel M' },\n      { id:2, name: 'John F' },\n      { id:3, destination: { zip: 45841 } },\n      { id:4, destination: { zip: 78612 }, name: 'Danno L' }\n  ];\nvar fallback = {\n      name: 'Customer name not available',\n      destination: { zip: 'Pickup' }\n  };\n_.defaults(orders, fallback);\n// Results:\n// [{ id: 1, destination: { zip: 21908 }, name: 'Ariel M' },\n// { id: 2, destination: { zip: 'Pickup' }, name: 'John F'  },\n// { id: 3, destination: { zip: 45841 }, name: 'Customer name not available' },\n// { id: 4, destination: { zip: 78612 }, name: 'Danno L' }]\n```\n###every\nChecks if given expression/callback is present in all members in the array.  \n**Usage:** `_.every(array, expression/callback)`\n```js\nvar nums = [1,2,3,4];\n_.every(num, 2); \n// → false\n\nvar users = [\n  { id: 2, name: 'bob' } },\n  { id: 4, name: 'bar' } },\n  { id: 6, name: 'baz' } }\n];\n_.every(users, '!(id % 2)');\n// → true\n_.every(users, 'name.indexOf(\"ba\") != -1');\n// → false\n```\n###filter\nfilter by `expression/callback` return all elements that return `true`, avoid the rest.  \n**Usage:** `_.filter(array, expression/callback)  `\n**Aliases:** ` _.pick`\n```js\nvar users = [\n  { id: 1, user: { name: 'foo', isAdmin: true  } },\n  { id: 2, user: { name: 'bar', isAdmin: false } },\n  { id: 3, user: { name: 'baz', isAdmin: true  } }\n];\n_.pick(users, 'user.isAdmin');\n// → [ users[0], users[2] ]\n```\n###find\nIterate over the given array and return the first member that the `expression` returns truthy for.  \n**Usage:** `_.find(array, expression/callback)`\n```js\nvar orders = [\n  { id: 21, product: { price: 21.12 }, auth: ['3s!sa0'] },\n  { id: 22, product: { price: 89.21 }, auth: ['@3dRg1'] },\n  { id: 23, product: { price: 49.00 }, auth: ['a44Fy+'] },\n  { id: 24, product: { price: 10.22 }, auth: ['WS4%a0'] },\n  { id: 25, product: { price: 11.31 }, auth: ['7Y#d_1'] }\n];\n_.find(orders, 'product.price \u003e 50'); \n// → { id: 22, product: { price: 89.21 }, auth: ['@3dRg1'] }\n\n_.find(orders, 'auth.indexOf(\"7Y#d_1\") !== -1');\n// → { id: 25, product: { price: 11.31 }, auth: ['7Y#d_1'] }\n\n_.find(orders, '!(id%2)');\n// → { id: 22, product: { price: 89.21 }, auth: ['@3dRg1'] }\n```\n###findLast\nIterate over the given array and return the last member that the `expression` returns truthy for.  \n**Usage:** `_.findLast(array, expression/callback)`\n```js\nvar orders = [\n  { id: 21, product: { price: 21.12 }, auth: ['3s!sa0'] },\n  { id: 22, product: { price: 89.21 }, auth: ['@3dRg1'] },\n  { id: 23, product: { price: 49.00 }, auth: ['7Y#d_1'] },\n  { id: 24, product: { price: 10.22 }, auth: ['WS4%a0'] },\n  { id: 25, product: { price: 91.31 }, auth: ['7Y#d_1'] }\n];\n_.findLast(orders, 'product.price \u003e 50'); \n// → { id: 25, product: { price: 91.31 }, auth: ['7Y#d_1'] }\n\n_.findLast(orders, 'auth.indexOf(\"7Y#d_1\") !== -1');\n// → { id: 25, product: { price: 91.31 }, auth: ['7Y#d_1'] }\n\n_.findLast(orders, '!(id%2)');\n// → { id: 24, product: { price: 10.22 }, auth: ['WS4%a0'] }\n```\n###findIndex\nIterate over the given array and return the **index** of the first member that the `expression` returns truthy for.  \n**Usage:** `_.findIndex(array, expression/callback)`\n```js\nvar orders = [\n  { id: 21, product: { price: 21.12 }, auth: ['3s!sa0'] },\n  { id: 22, product: { price: 89.21 }, auth: ['@3dRg1'] },\n  { id: 23, product: { price: 49.00 }, auth: ['a44Fy+'] },\n  { id: 24, product: { price: 10.22 }, auth: ['WS4%a0'] },\n  { id: 25, product: { price: 11.31 }, auth: ['7Y#d_1'] }\n];\n_.findIndex(orders, 'product.price \u003e 50');            // → 1\n_.findIndex(orders, 'auth.indexOf(\"7Y#d_1\") !== -1'); // → 4\n```\n###findLastIndex\nIterate over the given array and return the **index** of the last member that the `expression` returns truthy for.  \n**Usage:** `_.findLastIndex(array, expression/callback)`\n```js\nvar orders = [\n  { id: 21, product: { price: 21.12 }, auth: ['3s!sa0'] },\n  { id: 22, product: { price: 89.21 }, auth: ['@3dRg1'] },\n  { id: 23, product: { price: 49.00 }, auth: ['a44Fy+'] },\n  { id: 24, product: { price: 90.22 }, auth: ['a44Fy+'] },\n  { id: 25, product: { price: 11.31 }, auth: ['7Y#d_1'] }\n];\n_.findLastIndex(orders, 'product.price \u003e 50');             // → 3\n_.findLastIndex(orders, 'auth.indexOf(\"a44Fy+\") !== -1');  // → 3\n```\n\n###first\nGets the first element **or** first `n` elements of an array.  \nif expression is provided, is returns as long the expression return truthy.  \n**Usage:** See below \n```js\nvar users = [\n  { id: 1, user: { name: 'foo', isAdmin: true  } },\n  { id: 2, user: { name: 'bar', isAdmin: false } },\n  { id: 3, user: { name: 'baz', isAdmin: true  } }\n];\n// Returns the first user\n_.first(users);\n// → { id: 1, user: { name: 'foo', isAdmin: true  } }\n\n// Return the first user whose not `admin`\n_.first(users, '!user.isAdmin');\n// → [{ id: 2, user: { name: 'bar', isAdmin: false } }]\n\n// Returns the first 2 users\n_.first(users, 2);\n// → [users[0], users[1]]\n\n// Returns the first 2 `admin` users \n_.first(users, 2, 'user.isAdmin');\n// → [users[0], users[2]]\n```\n###flatten\nFlattens a nested array (the nesting can be to any depth).  \nif `shallow` set to true, the array will only be flattened a one level.\n**Usage:** `_.flatten(array, shallow[optional])`\n```js\n_.flatten(['out', ['out', ['in']], ['out', 'out', ['in', 'in']], ['out', 'out']], true);\n// → ['out', 'out', ['in'], 'out', 'out', ['in', 'in'], 'out', 'out']\n\n_.flatten([[], 1, 2, 3, [4, 5, 6, [7, 8, 9, [10, 11, [12, [[[[[13], [[[[14, 15]]]]]]]]]]]]]));\n// → [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]\n```\n###groupBy\nGet a collection, `expression/callback` and return an object composed of keys generated from the result of running each members in the collection on the `expression`.  \neach key is an array contains the results members.  \n**Usage:** `_.groupBy(array, expression)`\n```js\nvar players = [\n  {name: 'Gene',    team: { name: 'alpha' } },\n  {name: 'George',  team: { name: 'beta'  } },\n  {name: 'Steve',   team: { name: 'gamma' } },\n  {name: 'Paula',   team: { name: 'beta'  } },\n  {name: 'Scruath', team: { name: 'gamma' } }\n];\n_.groupBy(players, 'team.name');\n// { \n//  alpha: [{name: 'Gene',    team: { name: 'alpha' } }],\n//  betta: [{name: 'George',  team: { name: 'beta'  } }, {name: 'Paula',   team: { name: 'beta'  } }],\n//  gamma: [{name: 'Steve',   team: { name: 'gamma' } }, {name: 'Scruath', team: { name: 'gamma' } }]\n// }\n```\n###last\nGets the last element **or** last `n` elements of an array.  \nif expression is provided, is returns as long the expression return truthy.  \n**Usage:** See below \n```js\nvar users = [\n  { id: 1, user: { name: 'foo', isAdmin: true  } },\n  { id: 2, user: { name: 'bar', isAdmin: false } },\n  { id: 3, user: { name: 'baz', isAdmin: false } },\n  { id: 4, user: { name: 'zak', isAdmin: true  } }\n];\n// Returns the last user\n_.last(users);\n// → { id: 4, user: { name: 'zak', isAdmin: true  } }\n\n// Return the last user whose not `admin`\n_.last(users, '!user.isAdmin');\n// → [{ id: 3, user: { name: 'baz', isAdmin: false } }]\n\n// Returns the last 2 users\n_.last(users, 2);\n// → [users[2], users[3]]\n\n// Returns the last 2 `admin` users \n_.last(users, 2, 'user.isAdmin');\n// → [users[0], users[3]]\n```\n###map\nReturns a new Array with the results of each expression execution.  \n**Usage:** `_.map(array, expression)`  \n**Aliases:** `_.pluck`\n```js\nvar users = [\n  { id:1, user: { name: 'Foo' } },\n  { id:2, user: { name: 'Bar' } },\n  { id:3, user: { name: 'Baz' } }\n];\n_.map(users, 'user.name');\n// → ['Foo', 'Bar', 'Baz']\n\n_.map(users, 'id \u003c= 2 ? id : 0')\n// → [1, 2, 0]\n```\n###max\nFind and return the largest number in a given array.  \nif an `expression` is provided, will return max value by expression.  \n**Usage:** `_.max(array, expression[optional])`\n```js\n_.max([1,2,3,4,7,8,9]) // → 9\n\n//By expression\nvar users = [\n  { name: 'foo', score: 89 },\n  { name: 'bar', score: 32 },\n  { name: 'baz', score: 49 }\n];\n_.max(users, 'score'); // → { name: 'foo', score: 89 }\n\n//Chaining example\nvar users = [\n  { player: { ... }, score: 891 },\n  { player: { ... }, score: 121 },\n  { player: { ... }, score: 641 },\n  { player: { ... }, score: 491 }\n]\n_(users)\n  .map('score')\n  .max()\n  .value() // → 891\n```\n###min\nFind and return the lowest number in a given array.  \nif an `expression` is provided, will return min value by expression.  \n**Usage:** `_.min(array, expression[optional])`\n```js\n_.min([1,2,3,4,7,8,9]) // → 1\n\n//By expression\nvar users = [\n  { user: { score: 197 } },\n  { user: { score: 212 } },\n  { user: { score: 978 } },\n  { user: { score: 121 } }\n];\n_.min(users, 'user.score') // → { user: { score: 121 } }\n\n//Chaining example\nvar users = [\n  { player: { ... }, score: 891 },\n  { player: { ... }, score: 121 },\n  { player: { ... }, score: 641 },\n  { player: { ... }, score: 491 }\n]\n_(users)\n  .map('score')\n  .min()\n  .value() // → 121\n```\n###omit\nGet an array, and return a new array without the omitted members(by `expression`).  \n**Usage:** `_.omit(array, expression)`\n```js\nvar users = [\n  { id: 1, name: 'foo' },\n  { id: 2, name: 'bar' },\n  { id: 3, name: 'baz' }\n];\n_.omit(users, 'id \u003e 2 \u0026\u0026 !name.indexOf(\"ba\")');\n// → [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }]\n```\n###orderBy\nOrders a specified array by the expression predicate.  \nIt is ordered alphabetically for strings and numerically for numbers.  \n**Usage:** `_.orderBy(array, expression/callback, reverse[optional])`  \n**Aliases:** `_.sortBy`\n```js\nvar orders = [\n  { id: 1, product: { price: 21.12 }, date: new Date('01/01/2014') },\n  { id: 2, product: { price: 99.21 }, date: new Date('01/01/2014') },\n  { id: 3, product: { price: 99.90 }, date: new Date('01/01/2013') },\n  { id: 4, product: { price: 99.99 }, date: new Date('01/01/1970') }\n];\n\n_.orderBy(orders, 'date');\n// → [orders[3], orders[2], orders[1], orders[0]];\n\n_.orderBy(orders, '+product.price');\n// → [orders[0], orders[1], orders[2], orders[3]];\n\n_.orderBy(orders, '-product.price');\n// → [orders[3], orders[2], orders[1], orders[0]]\n\n_.orderBy(orders, ['-date', '-id']);\n// → [orders[1], orders[0], orders[2], orders[3]]\n\n_.orderBy([5,1,4,3,2]);           // → [1, 2, 3, 4, 5]\n_.orderBy([5,1,4,3,2], '-');      // → [5, 4, 3, 2, 1]\n.orderBy([5,1,4,3,2], '-', true); // → [1, 2, 3, 4, 5]\n\n// sort by multiple arguments\n_.orderBy([{a:1, b:10}, {a:1, b:4}, {a:0, b:5}], ['a', 'b']);\n// → [{ a:0, b:5 }, { a:1, b:4 }, { a:1, b:10 }]\n```\n\n###remove\nremove specific members from array by equality.  \n**Usage:** `_.remove(array, args)`\n```js\nvar collection = [\n  { name: 'bar' },\n  { name: 'foo' },\n  null, 1\n];\n_.remove(collection, { name: 'foo' }, null, 1);\n// → [{ name: 'bar' }]\n```\n###reverse\nReverses a string or array(doesn't change the source array).  \n**Usage:** `_.reverse(array/string)`\n```js\n_.reverse([1,2,3]) // → [3, 2, 1]\n_.reverse('agile') // → eliga\n```\n###sum\nSum up all values within an array.  \n**Usage:** `_.sum(array)`\n```js\n_.sum([1,2,3,4,5]) // → 15\n\n//Chainig example\nvar scores = [\n  { player: { ... }, score: 891 },\n  { player: { ... }, score: 121 },\n  { player: { ... }, score: 641 },\n  { player: { ... }, score: 491 }\n];\n_(scores)\n  .map('score')\n  .sum()\n  .value(); // → 2144\n```\n###unique\nGet an array and filter duplicate members.  \nif `expression` is provided it's filters by this `expression` as unique identifier.  \n**Usage:** `_.unique(array, expression[optional])`  \n**Aliases:** `uniq`\n```js\n_.unique([12,3,4,12,4,5,6]) \n// → [12, 3, 4, 5, 6]\n\nvar orders = [\n  { id:1, customer: { name: 'John',    id: 10 } },\n  { id:2, customer: { name: 'William', id: 20 } },\n  { id:3, customer: { name: 'John',    id: 10 } },\n  { id:4, customer: { name: 'William', id: 20 } },\n  { id:5, customer: { name: 'Clive',   id: 30 } }\n];\n_.unique(orders, 'customer.id');\n// Results:\n// [{ id:1, customer: { name: 'John',    id: 10 } },\n//  { id:2, customer: { name: 'William', id: 20 } },\n//  { id:5, customer: { name: 'Clive',   id: 30 } }]\n\n//Chaining Example:\n_(orders)\n  .unique('customer.id')\n  .map('customer.name')\n  .join(', ')\n  .value(); // → John, William, Clive\n```\n###xor\nExclusive or filter by expression.  \n**Usage:** `_.xor(arr1, arr2, expression[optional])`\n```js\n_.xor([2,3,4], [3,4,5]);\n// → [2, 5]\n\n//Example with expression:\nvar users1 = [\n  { id: 0, details: { first_name: 'foo', last_name: 'bar' } }, \n  { id: 1, details: { first_name: 'foo', last_name: 'baz' } },\n  { id: 2, details: { first_name: 'foo', last_name: 'bag' } }\n];\nvar users2 = [\n  { id: 3, details: { first_name: 'foo', last_name: 'bar' } },\n  { id: 4, details: { first_name: 'foo', last_name: 'baz' } }\n];\n_.xor(users1, users2, 'details.last_name');\n// → [{ id: 2, details: { first_name: 'foo', last_name: 'bag' } }]\n```\n\n#Object\n###toArray\nConvert objects into stable arrays.  \nif addKey set to true,the filter also attaches a new property `$key` to the value containing the original key that was used in the object we are iterating over to reference the property.  \n**Usage:** `_.toArray(object, boolean[optional])`\n```js\nvar users = {\n  0: { name: 'Ariel', age: 25 },\n  1: { name: 'Dan',   age: 21 },\n  2: { name: 'John',  age: 31 }\n};\n_.toArray(users);\n// → [{name:'Ariel', age:25}, {name:'Dan', age:21}, {name:'John', age:31}]\n\n//Chaining example\n_({\n  Ariel: { age: 25 },\n  Dan  : { age: 21 },\n  John : { age: 31 }\n}).toArray(true)\n  .value(); // → [{$key:'Ariel', age:25}, {$key:'Dan', age:21}, {$key:'John', age:31}]\n```\n###keys\nCreates an array composed of the own enumerable property names of an object.  \nif `nested` set to true, it will return the properties in a recursively nested style(used mainly with `parse.setter`, `parse.getter`).  \n**Usage:** `_.keys(object, nested[optional])`\n```js\nvar user = { \n  name: 'Ariel M', \n  age: 26, \n  permissions: { isAdmin: true }, \n  details: { address: { city: 'Tel Aviv', zip: 61019 } }\n};\n_.keys(user); \n// → ['name', 'age', 'permissions', 'details']\n\n_.keys(user, true);\n// → ['name', 'age', 'permissions.isAdmin', 'details.address.city', 'details.address.zip']\n```\n###parse\nConvert `expression` into function.  \n**Usage:** `_.parse(expression)`  \n**Returns:** `Function(context, local)`  \n`context`**:** an object against which any expressions embedded in the strings are evaluated against.  \n`local`**:** local variables context object, useful for overriding values in context.  \n**Note:** The returned function also has the following properties:  \n`literal` : whether the expression's top-level node is a JavaScript literal.  \n`constant`: whether the expression is made entirely of JavaScript constant literals.  \n`assign`  : `{?function(context, value)}` – if the expression is assignable, this will be set to a function to change its value on the given context.\n```js\n//Simple getter / setter functions\nvar user = { \n  name: 'Ariel M.', \n  age : 26, \n  details: { address: { city: 'Tel Aviv', zip: 61019 } }\n};\nvar nameGetter = _.parse('name');\nvar nameSetter = nameGetter.assign;\n\nnameGetter(user); // → 'Ariel M.'\nnameSetter(user, 'Dan T.');\nnameGetter(user); // → 'Dan T.'\n\n//Example use local(override) object\nvar local = {\n  age: 50,\n  sayHello: function(name, age) { \n    return 'Hello ' + name + ' I\\'m '+ age + ' years old.' \n  }\n};\n_.parse('sayHello(name, age)')(user, local);\n// → Hello Ariel M. I'm 50 years old.\n\n_.parse('[1,2]').literal    // → true\n_.parse('[1 + 1]').constant // → true\n_.parse('[x + 1]').constant // → false\n```\n\n#String\n###endsWith\nreturn whether string ends with the ends parameter.  \n**Usage:** `_.endsWith(string, end, case-sensitive[optional])`\n```js\n_.endsWith('image.JPG', '.jpg'); // → true\n\n_.endsWith('image.JPG', '.jpg', true); // → false\n```\n###ltrim\nLeft trim. Similar to `trim`, but only for left side.  \n**Usage:** `_.ltrim(string, chars[optional])`\n```js\n_.ltrim('   foo   ') // → 'foo   '\n_.ltrim('barfoobar', 'bar') // → 'foobar'\n```\n###rtrim\nReft trim. Similar to `trim`, but only for right side.  \n**Usage:** `_.rtrim(string, chars[optional])`\n```js\n_.rtrim('   foo   ') // → '   foo'\n_.rtrim('barfoobar', 'bar') // → 'barfoo'\n```\n###repeat\nRepeats a string n times(**fast**).  \n**Usage:** `_.repeat(string, n)`\n```js\n_.repeat('*',10); // → '**********'\n_.repeat('foo');  // → 'foo'\n```\n###slugify\nTransform text into a URL slug. Replaces whitespaces, with dash(\"-\") or given argument.  \n**Usage:** `_.slugify(input, sub[optional])`\n```js\n_.slugify('Some string with spaces'); // → 'some-string-with-spaces'\n_.slugify('Some string with hashtags', '#'); // → 'some#string#with#hashtags'\n```\n###startsWith\nreturn whether `string` starts with the starts parameter.  \n**Usage:** `_.startsWith(str, case-sensitive[optional])`\n```js\n_.startsWith('Lorem ipsum', 'Lor'); // → true\n\n//Chaining example:\n_('Lorem ipsum')\n  .startsWith('lor', true); // → false\n```\n###stringular\nget string with `{n}` and replace matches with enumeration values.  \n**Usage:** `_.stringular(str, args...)`\n```js\n_.stringular('lorem {0} dolor {1} amet', 'ipsum', 'sit'); \n// → 'lorem ipsum dolor sit amet'\n\n_.stringular('{3} {0} dolor {1} amet', 'ipsum', 'sit', null, 'lorem');\n// → 'lorem ipsum dolor sit amet'\n```\n###stripTags\nstrip out `html` tags from string.  \n**Usage:** `_.stripTags(string)`\n```js\n_.stripTags('\u003cdiv id=\"fr\" class=\"paragraph\"\u003efoo\u003cbr/\u003e\u003c/div\u003e');\n// → 'foo'\n\n//Chaining example\n_('\u003cp class=\"paragraph\"\u003eLorem Ipsum...\u003c/p\u003e')\n  .stripTags()\n  .value(); // → 'Lorem Ipsum...'\n```\n###trim\nStrip whitespace (or other characters) from the beginning and end of a string.  \n**Usage:** `_.trim(string, chars[optional])`\n```js\n_.trim('foobarfoo', 'foo'); // → 'bar'\n_.trim('   foo   '); // → 'foo'\n```\n###truncate\ntruncates a string given a specified length, providing a custom string to denote an omission.  \n**Usage:** `_.truncate(str, length, suffix[optional], preserve[optinal])`\n```js\nvar text = 'lorem ipsum dolor sit amet';\n\n_.truncate(text, 13, '...', true); // → 'lorem ipsum dolor...'\n_.truncate(text, 13, '...');       // → 'lorem ipsum d...'\n_.truncate(text, 50, '...');       // → 'lorem ipsum dolor sit amet'\n```\n###ucfirst\nupper case first char.  \n**Usage:** `_.ucfirst(string)`\n```js\n_.ucfirst('ariel mashraki'); // → 'Ariel Mashraki'\n\n//Chaining example\n_(['ariel', 'dan', 'john'])\n  .join(', ')\n  .ucfirst()\n  .value(); // → 'Ariel, Dan, John'\n```\n###wrap\nWrap a string with another string.  \n**Usage:** `_.wrap(string, start, end[optional])`\n```js\n_.wrap('foo', 'bar');          // → 'barfoobar'\n_.wrap('text', '\u003cp\u003e', '\u003c/p\u003e'); // → '\u003cp\u003etext\u003c/p\u003e'\n\n//Chaining example:\n_(['ariel', 'dan', 'john'])\n  .join(', ')\n  .ucfirst()\n  .wrap('Team members: ', ' ')\n  .value(); // → 'Team members: Ariel, Dan, John'\n```\n#Utils\n###copy\nCreates a recursive copy of `source` object into `dest` object, could be an object or an array.  \n**Usage:** `_.copy(src, dst)`\n```js\nvar a = [1,2,3, { a: 1, b: 2 }];\nvar b;\n_.copy(a, b);\n\n//Test result\n_.equals(a, b); // → true\n```\n###dictionary\nCreates a new object without a prototype.  \n**Usage:** `_.dictionary()`\n```js\nvar map = _.dictionary();\nconsole.log(map.toString); // → undefined\n```\n###equals\nDetermines if two objects or two values are equivalent.  \n**Usage:** `_.equals(o1, o2)`\n```js\n_.equals({}, {});                   // → true\n_.equals(new Date(), new Date());   // → true\n_.equals(/\\//g, new RegExp(/\\//g)); // → true\n```\n###extend\nExtends the destination object `dst` by copying own enumerable properties from the `src` object(s) to `dst`. You can specify multiple `src` objects.  \n**Usage:** `_.extend(dst, arg...)`\n```js\n_.extend({a:1}, {b:2}, {a:3, c: 4}); // → {a: 3, b: 2, c: 4}\n```\n###identity\n`identity` function returns its first argument.  \n**Usage:** `_.identity(val)`\n```js\n_.identity(1); // → 1\n```\n###forEach\nInvokes an `iterator` function once for each member in a collection(object, array).  \nThe `iterator` function is invoked with (value, key/index, obj/array).  \n**Usage:** `_.forEach(collection, iteratorFn, context[optional]);`\n###noop\nA function that performs no operations.  \n**Usage:** `_.noop()`\n```js\nfunction fn(cb) {\n //...\n return (cb || _.noop)(args);\n}\n```\n#Contributing\n* If you planning add some feature please create issue before.\n* Don't forget about tests.  \n\n**Clone the project:**\n```sh\n$ git clone\n$ npm install\n$ bower install\n```\n**Run the tests:**\n```sh\n$ grunt test\n```\n**Deploy:**  \nRun the build task, update version before(bower,package)\n```sh\n$ grunt build\n$ git tag v0.*.*\n$ git push origin master --tags\n```\n[npm-image]: https://img.shields.io/npm/v/agile.svg?style=flat-square\n[npm-url]: https://npmjs.org/package/agile\n[travis-image]: https://img.shields.io/travis/a8m/agile.svg?style=flat-square\n[travis-url]: https://travis-ci.org/a8m/agile\n[coveralls-image]: https://img.shields.io/coveralls/a8m/agile.svg?style=flat-square\n[coveralls-url]: https://coveralls.io/r/a8m/agile\n[david-image]: http://img.shields.io/david/a8m/agile.svg?style=flat-square\n[david-url]: https://david-dm.org/a8m/agile\n[license-image]: http://img.shields.io/npm/l/agile.svg?style=flat-square\n[license-url]: LICENSE\n[downloads-image]: http://img.shields.io/npm/dm/agile.svg?style=flat-square\n[downloads-url]: https://npmjs.org/package/agile\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fa8m%2Fagile","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fa8m%2Fagile","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fa8m%2Fagile/lists"}