diff --git a/.travis.yml b/.travis.yml
index 2c573b8..350428f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,6 @@
 language: node_js
 node_js:
-  - '0.10'
+  - '6'
 before_script:
   - export DISPLAY=:99.0
   - sh -e /etc/init.d/xvfb start
diff --git a/README.md b/README.md
index 444a0e8..e26aef6 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,12 @@
-#Angular-filter &nbsp; [![NPM version][npm-image]][npm-url] [![Build status][travis-image]][travis-url] [![Test coverage][coveralls-image]][coveralls-url] [![License][license-image]][license-url]
->Bunch of useful filters for AngularJS (with no external dependencies!), **v0.5.8**
+# Angular-filter &nbsp; [![NPM version][npm-image]][npm-url] [![Build status][travis-image]][travis-url] [![Test coverage][coveralls-image]][coveralls-url] [![License][license-image]][license-url]
+Bunch of useful filters for AngularJS *(with no external dependencies!)*
 
-**Notice:** if you want to use `angular-filter` out of AngularJS(e.g: Node, etc..), check [Agile.js repo](https://github.com/a8m/agile)
+<h3 align="center">
+<img src="https://angular.io/assets/images/logos/angular/angular.svg" width="50" alt="angular pipes"><br/>
+ Angular 2 version is now available: <a href="https://github.com/a8m/ng-pipes">ng-pipes</a>
+ </h3>
 
-##Table of contents:
+## Table of contents:
 - [![Gitter][gitter-image]][gitter-url]
 - [Get Started](#get-started)
 - [Common Questions](https://github.com/a8m/angular-filter/wiki/Common-Questions)
@@ -46,15 +49,17 @@
   - [xor](#xor)
 - [String](#string)
   - [endsWith](#endswith)
+  - [latinize](#latinize)
   - [repeat](#repeat)
   - [reverse](#reverse-1)
   - [slugify](#slugify)
-  - [latinize](#latinize)
+  - [split](#split)
   - [startsWith](#startswith)
   - [stripTags](#striptags)
   - [stringular](#stringular)
-  - [test](#test)
   - [match](#match)
+  - [phoneUS](#phoneus)
+  - [test](#test)
   - [trim](#trim)
   - [ltrim](#ltrim)
   - [rtrim](#rtrim)
@@ -66,6 +71,7 @@
 - [Math](#math)
   - [min](#min)
   - [max](#max)
+  - [abs](#abs)
   - [percent](#percent)
   - [radix](#radix)
   - [sum](#sum)
@@ -93,7 +99,7 @@
   - [isIdenticalTo](#isidenticalto) `===`
   - [isNotIdenticalTo](#isnotidenticalto) `!==`
 
-#Get Started
+## Get Started
 **(1)** You can install angular-filter using 4 different methods:
   - clone & [build](#Contributing) this repository
   - via **[Bower](http://bower.io/)**: by running `$ bower install angular-filter` from your terminal
@@ -126,9 +132,9 @@ When you're done, your setup should look similar to the following:
 </html>
 ```
 
-#Collection
+## Collection
 
-###concat
+### concat
 
 Concatenates an array/object into another one.
 
@@ -163,7 +169,7 @@ result:
 -->
 ```
 
-###unique
+### unique
 Remove duplicates from an array/object.<br/>
 If a string is provided, it will filter out duplicates using the provided expression.<br/>
 **Usage:** ```collection | unique: 'property' ```<br/>
@@ -193,7 +199,7 @@ William 20
 Clive 30
 
 ```
-###filterBy
+### filterBy
 Filter a collection by a specific property.<br/>
 **Usage:** ```collection | filterBy: [prop, nested.prop, etc..]: search: strict[optional]```<br/>
 **Note:** You can even use compound properties (e.g: ```|filterBy: [property + property]: model```)<br/>
@@ -240,7 +246,7 @@ Return users whose full name is
   3: Rob Johannson
 -->
 ```
-###first
+### first
 Gets the first element(s) of a collection.<br/>
 If an expression is provided, it will only return elements whose expression is truthy.<br/>
 ***Usage:*** See below <br/>
@@ -292,7 +298,7 @@ Return the first two users with even id
 Mike
 Rob
 ```
-###last
+### last
 Gets the last element or last n elements of a collection,<br/>
 if expression is provided, is returns as long the expression return truthy<br/>
 ***Usage:*** See below <br/>
@@ -333,7 +339,7 @@ lol
 baz
 lol
 ```
-###flatten
+### flatten
 Flattens a nested array (the nesting can be to any depth).<br/>
 If you pass shallow, the array will only be flattened a single level<br/>
 **Usage:** ```collection | flatten: shallow[optional]```
@@ -367,7 +373,7 @@ $scope.names = ['John', 'Sebastian', 'Will', 'James'];
 ```
 
 
-###fuzzy
+### fuzzy
 fuzzy string searching(approximate string matching). [Read more](http://en.wikipedia.org/wiki/Approximate_string_matching)<br/>
 **note:** use fuzzyBy to filter by one property to improve performance<br/>
 **Usage:** ```collection | fuzzy: search: caseSensitive[optional]```
@@ -390,7 +396,7 @@ $scope.books = [
   {{ book.title }}
 </li>
 ```
-###fuzzyBy
+### fuzzyBy
 fuzzy string searching(approximate string matching) by property(nested to). [Read more](http://en.wikipedia.org/wiki/Approximate_string_matching)<br/>
 **Usage:** ```collection | fuzzyBy: 'property': search: caseSensitive[optional]```
 ```js
@@ -412,7 +418,7 @@ $scope.books = [
   {{ book.title }}
 </li>
 ```
-###groupBy
+### groupBy
 Create an object composed of keys generated from the result of running each element of a collection,<br/>
 each key is an array of the elements.<br/>
 **Usage:** ```(key, value) in collection | groupBy: 'property'``` or ```... | groupBy: 'nested.property'```
@@ -446,7 +452,7 @@ $scope.players = [
     * player: Steve
     * player: Scruath
 ```
-###countBy
+### countBy
 Create an object composed of keys generated from the result of running each element of a collection,<br/>
 each key is the count of objects in each group<br/>
 **Usage:** ```(key, value) in collection | countBy: 'property'``` or ```... | countBy: 'nested.property'```
@@ -468,8 +474,8 @@ $scope.players = [
   Group name: beta, length: 2
   Group name: gamma, length: 2
 ```
-###chunkBy
-Collect data into fixed-length chunks or blocks  
+### chunkBy
+Collect data into fixed-length chunks or blocks
 **Usage:** ```(key, value) in collection | chunkBy: 'n': fill-value(optional)```
 ```js
 $scope.array = [1, 2, 3, 4, 5, 6];
@@ -492,7 +498,7 @@ $scope.array = [1, 2, 3, 4, 5, 6];
   Block: [5, 6, 0, 0]
 ```
 
-###defaults
+### defaults
 `defaultsFilter` allows to specify a default fallback value for properties that resolve to undefined.<br/>
 **Usage:** `col in collection | defaults: fallback`
 ```js
@@ -520,7 +526,7 @@ $scope.fallback = {
 * id: 4, name: Danno L, shipping address: 78612
 ```
 **Note:** `defaultsFilter` change the source object.<br/>
-**Why?** if we not change the source object, it's actually means we gonna return **new** object(copy operation)  **each digest cycle**.<br/>
+**Why?** if we don't change the source object, it actually means we're gonna return a **new** object (copy operation) on **each digest cycle**.<br/>
 And it will cause adverse memory and performance implications.<br/>
 **How to avoid it?** see below
 ```js
@@ -532,7 +538,7 @@ $scope.ordersWithFallback = angular.copy($scope.orders);
     <!-- ..... -->
 </li>
 ```
-###where
+### where
 comparison for each element in a collection to the given properties object,<br/>
 returning an array of all elements that have equivalent property values.
 ```js
@@ -558,7 +564,7 @@ returning an array of all elements that have equivalent property values.
   foo
   -->
 ```
-###omit
+### omit
 return collection without the omitted objects(by expression).<br/>
 usage: ```collection | omit: expression```<br/>
 **example 1:**
@@ -589,7 +595,7 @@ $scope.collection = [
 <!--result:
 id: 1, name: foo
 ```
-###pick
+### pick
 return collection composed of the picked objects(by expression).<br/>
 usage: ```collection | pick: expression```<br/>
 **example 1:**
@@ -622,7 +628,7 @@ id: 2, name: bar
 id:3, name: baz
 ```
 
-###remove
+### remove
 Returns a new collection of removed elements.
 ```js
 $scope.foo = { name: 'foo' };
@@ -639,7 +645,7 @@ $scope.collection = [
 <!-- result:
   { "name": "bar" }
 ```
-###removeWith
+### removeWith
 comparison for each element in a collection to the given properties object,<br/>
 returning an array without all elements that have equivalent property values.
 ```js
@@ -664,7 +670,7 @@ returning an array without all elements that have equivalent property values.
   bar
   baz
 ```
-###searchField
+### searchField
 if you want to use the filter in angular and want to filter for multiple values<br/>
 so searchField filter return new collection with property called searchField<br/>
 **support nested properties with dot notation i.e:** ``` collection | searchField: 'prop': 'nested.prop' ```
@@ -682,7 +688,7 @@ $scope.users = [
 </th>
 <!-- so now you can search by full name -->
 ```
-###after
+### after
 get a collection(array or object) and specified count, and returns all of the items
 in the collection after the specified count.
 ```js
@@ -703,7 +709,7 @@ $scope.collection = [
 -->
 
 ```
-###afterWhere
+### afterWhere
 get a collection and properties object, and returns all of the items,
 in the collection after the first that found with the given properties, including it.
 ```js
@@ -726,7 +732,7 @@ $scope.orders = [
 -->
 ```
 
-###before
+### before
 get a collection(array or object) and specified count, and returns all of the items
 in the collection before the specified count.
 ```js
@@ -748,7 +754,7 @@ $scope.collection = [
 
 ```
 
-###beforeWhere
+### beforeWhere
 get a collection and properties object, and returns all of the items,
 in the collection before the first that found with the given properties, including it.
 ```js
@@ -771,7 +777,7 @@ $scope.orders = [
 -->
 ```
 
-###reverse
+### reverse
 Reverse the order of the elements in a collection
 
 ```js
@@ -792,7 +798,7 @@ $scope.users = [
 -->
 ```
 
-###isEmpty
+### isEmpty
 get collection or string and return if it empty[Boolean]
 
 ```html
@@ -804,7 +810,7 @@ get collection or string and return if it empty[Boolean]
   no content to show
 </tr>
 ```
-###contains
+### contains
 Checks if given expression(or value) is present in one or more object in the collection<br/>
 **Usage:** ```collection | contains: 'expression'```<br/>
 **Aliases:** some<br/>
@@ -827,7 +833,7 @@ $scope.collection = [
 <th ng-show="{{ collection | some: '!(user.id % 2) && user.name.indexOf(\'b\') === 0' }}">...</th>
 <!--result: true
 ```
-###every
+### every
 Checks if given expression(or value) return truthy value for all members of a collection<br/>
 **Usage:** ```collection | every: 'expression'```<br/>
 example 1:
@@ -847,11 +853,11 @@ $scope.collection = [
 ];
 ```
 ```html
-<th ng-show="{{ collection | every: !(user.id % 2) }}">...</th>
+<th ng-show="{{ collection | every: '!(user.id % 2)' }}">...</th>
 <!--result: true
 ```
 
-###xor
+### xor
 Exclusive or between two collections<br/>
 **Usage:** ```collection1 | xor: collection2: expression[optional]```<br/>
 
@@ -888,7 +894,7 @@ $scope.users2 = [
 <!--result:
 2, foo bag
 ```
-###toArray
+### toArray
 Convert objects into stable arrays. <br/>
 **Usage:** ```object | toArray: addKey[optional]```<br/>
 if 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
@@ -897,7 +903,7 @@ if addKey set to true, the filter also attaches a new property $key to the value
   {{ elm.name }}
 </th>
 ```
-###map
+### map
 Returns a new collection of the results of each expression execution. <br/>
 **Usage:** ```collection | map: expression``` <br/>
 Example1:
@@ -913,7 +919,7 @@ $scope.divide = function(elm) {
 <!--result:
 0.5, 1, 1.5, 2, 2.5
 ```
-###pluck
+### pluck
 Used map
 ```js
 $scope.users = [
@@ -931,22 +937,49 @@ Foo
 Bar
 Baz
 ```
-###range
-Return a new collection from a given length<br/>
-**Usage:** ```collection | range: length```<br/>
+### range
+Return a new collection from a given length, start, increment, and callback<br/>
+By default start is 0, increment is 1, and callback is null.
+**Usage:** ```collection | range: length:start:increment:callback```<br/>
 ```html
-<th ng-repeat="i in [] | range: 3">
-  {{ i }}
-</th>
+[<span ng-repeat="i in [] | range: 3">{{i}},</span>]
+<!--result:
+[0,1,2,]
+-->
+```
+```html
+[<span ng-repeat="i in [] | range: 10:10">{{i}},</span>]
+<!--result:
+[10,11,12,13,14,15,16,17,18,19,]
+-->
+```
+```html
+[<span ng-repeat="i in [] | range: 10:5:2">{{ i }},</span>]
+<!--result:
+[5, 7, 9, 11, 13, 15, 17, 19, 21, 23]
+-->
+```
+```html
+[<span ng-repeat="i in [] | range: 11:4:2">{{ i }},</span>]
+<!--result:
+[4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]
+-->
+```
+```js
+$scope.double = function(i) {
+  return i * 2;
+}
+```
+```html
+[<span ng-repeat="i in [] | range: 11:4:2:double">{{ i }},</span>]
 <!--result:
-0
-1
-2
+[8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48]
+-->
 ```
 
-#String
+## String
 
-###ucfirst
+### ucfirst
 
 ucfirstFilter get string as parameter and return it capitalized
 
@@ -959,21 +992,21 @@ Foo Bar Baz
 -->
 ```
 
-###uriEncode
+### uriEncode
 get string as parameter and return encoded uri
 
 ```html
 <a ng-href="http://domain.com/fetch/{{ data.name | uriEncode }}">Link</a>
 ```
 
-###uriComponentEncode
+### uriComponentEncode
 get string as parameter and return encoded uri component
 
 ```html
 <a ng-href="http://domain.com/fetch/{{ 'Some&strange=chars' | uriComponentEncode }}">Link</a>
 ```
 
-###slugify
+### slugify
 Transform text into a URL slug. Replaces whitespaces, with dash("-"), or given argument
 
 ```html
@@ -988,7 +1021,7 @@ result:
 -->
 ```
 
-###latinize
+### latinize
 Remove accents/diacritics from a string
 
 ```html
@@ -998,7 +1031,7 @@ result:
   Some strIng with Accents
 -->
 ```
-###startsWith
+### startsWith
 return whether string starts with the starts parameter.<br/>
 usage: ```string | startsWith: 'start': case-sensitive[optional]```<br/>
 ```html
@@ -1008,7 +1041,7 @@ usage: ```string | startsWith: 'start': case-sensitive[optional]```<br/>
   true
   false
 ```
-###endsWith
+### endsWith
 return whether string ends with the ends parameter.<br/>
 usage: ```string | endsWith: 'ends': case-sensitive[optional]```<br/>
 ```html
@@ -1018,7 +1051,7 @@ usage: ```string | endsWith: 'ends': case-sensitive[optional]```<br/>
   true
   false
 ```
-###stripTags
+### stripTags
 strip out html tags from string<br/>
 **Important: this filter jobs it's not to replace ng-bind-html directive, it's only for tiny plain text
 
@@ -1031,7 +1064,7 @@ $scope.text = '<p class="paragraph">Lorem Ipsum is simply dummy text of the prin
 Lorem Ipsum is simply dummy text of the printing...
 -->
 ```
-###stringular
+### stringular
 get string with {n} and replace match with enumeration values
 
 ```html
@@ -1047,7 +1080,17 @@ get string with {n} and replace match with enumeration values
 <!--result:
 <p>lorem {0} dolor sit amet</p>
 ```
-###truncate
+
+### phoneUS
+Format a string or a number into a us-style phone number  
+```html
+<p>{{ 1234567890 | phoneUS }}</p>
+
+<!--result:
+<p>(123) 456-7890</p>
+```
+
+### truncate
 truncates a string given a specified length, providing a custom string to denote an omission.<br/>
 usage: ``` | truncate: [length]: [suffix-optional]: [preserve-optinal]```<br/>
 ```js
@@ -1067,7 +1110,23 @@ lorem ipsum...
 lorem ipsum d...
 lorem ipsum dolor sit amet
 ```
-###reverse
+### split
+truncates a string given a specified length, providing a custom string to denote an omission.<br/>
+usage: ``` | split: [delimiter]: [skip-optional]```<br/>
+```js
+$scope.text = 'lorem ipsum dolor sit amet';
+```
+```html
+
+<p>{{ text | split: ' ' }}</p>
+
+<p>{{ text | split: ' ': 2}}</p>
+
+<!--result:
+['lorem', 'ipsum', 'dolor', 'sit', 'amet']
+['lorem ipsum dolor', 'sit', 'amet']
+```
+### reverse
 Reverses a string
 ```js
 $scope.text = 'lorem ipsum dolor sit amet';
@@ -1077,7 +1136,7 @@ $scope.text = 'lorem ipsum dolor sit amet';
 <!--result:
 tema tis rolod muspi merol
 ```
-###wrap
+### wrap
 Wrap a string with another string<br/>
 usage: ```string | wrap: string: string[optional]```
 ```html
@@ -1087,7 +1146,7 @@ usage: ```string | wrap: string: string[optional]```
 /foo/
 {{foo}}
 ```
-###trim
+### trim
 Strip whitespace (or other characters) from the beginning and end of a string<br/>
 usage: ```string | trim: chars[optional]```
 ```html
@@ -1097,7 +1156,7 @@ usage: ```string | trim: chars[optional]```
 foo
 bar
 ```
-###ltrim
+### ltrim
 Strip whitespace (or other characters) from the beginning of a string<br/>
 usage: ```string | ltrim: chars[optional]```
 ```html
@@ -1105,7 +1164,7 @@ usage: ```string | ltrim: chars[optional]```
 <!--result:
 foobar
 ```
-###rtrim
+### rtrim
 Strip whitespace (or other characters) from the end of a string<br/>
 usage: ```string | rtrim: chars[optional]```
 ```html
@@ -1113,7 +1172,7 @@ usage: ```string | rtrim: chars[optional]```
 <!--result:
 barfoo
 ```
-###repeat
+### repeat
 Repeats a string n times<br/>
 **Usage:** ```string | repeat: n: separator[optional]```
 ```html
@@ -1121,7 +1180,7 @@ Repeats a string n times<br/>
 <!--repeat:
 foo-foo-foo
 ```
-###test
+### test
 Test if a string match a pattern<br/>
 **Usage:** ```string | test: pattern: flag[optional]```
 ```html
@@ -1131,7 +1190,7 @@ Test if a string match a pattern<br/>
 true
 true
 ```
-###match
+### match
 Return an array of matched element in a string<br/>
 **Usage:** ```string | match: pattern: flag[optional]```
 ```html
@@ -1139,9 +1198,10 @@ Return an array of matched element in a string<br/>
 <!--result:
 ['15', '12', '2003']
 ```
-#Math
 
-###max
+## Math
+
+### max
 max find and return the largest number in a given array.
 if an `expression` is provided, will return max value by expression.
 **Usage:** ```array | max: expression[optional]```
@@ -1162,7 +1222,7 @@ result:
 * { user: { rank : 988999 } }
 ```
 
-###min
+### min
 min find and return the lowest number in a given array.
 if an `expression` is provided, will return min value by expression.
 **Usage:** ```array | min: expression[optional]```
@@ -1181,7 +1241,19 @@ result:
 * 1
 * { user: { score: 123414 } }
 ```
-###percent
+### abs
+Returns the absolute value of a number
+**Usage:** ```number | string```
+```html
+<div ng-repeat="val in [-2.2, 1.3, '-3.4', '4.5']">The absolute value of {{val}} is {{val | abs}}</div>
+<!--
+result:
+* The absolute value of -1.2 is 1.2
+* The absolute value of 2.3 is 2.3
+* The absolute value of -3.4 is 3.4
+* The absolute value of '4.5' is 4.5
+```
+### percent
 Percentage between two numbers<br/>
 **Usage:** ``` number | percent: total: round[optional]```, round by default false.
 ```html
@@ -1191,7 +1263,7 @@ Percentage between two numbers<br/>
 4.6
 4
 ```
-###radix
+### radix
 Converting decimal numbers to different bases(radix)<br/>
 **Usage:** ```number | radix: base```
 ```html
@@ -1201,7 +1273,7 @@ Converting decimal numbers to different bases(radix)<br/>
 1000
 7F4A
 ```
-###sum
+### sum
 Sum up all values within an array<br/>
 **Usage:** ```array | sum: initial-value[optional]```
 ```html
@@ -1211,7 +1283,7 @@ Sum up all values within an array<br/>
 10
 20
 ```
-###degrees
+### degrees
 Converts radians into degrees<br/>
 **Usage:** ```radians | degrees: round-to-decimal```,
 ```html
@@ -1221,7 +1293,7 @@ Converts radians into degrees<br/>
 45
 -89.954
 ```
-###radians
+### radians
 Converts degrees into radians<br/>
 **Usage:** ```degrees | radians: round-to-decimal```,
 ```html
@@ -1231,7 +1303,7 @@ Converts degrees into radians<br/>
 0.79
 3.14159
 ```
-###shortFmt
+### shortFmt
 Converts numbers into formatted display<br/>
 **Usage:** ```number | shortFmt: round-to-decimal```,
 ```html
@@ -1241,7 +1313,7 @@ Converts numbers into formatted display<br/>
 45 k
 18.2 m
 ```
-###byteFmt
+### byteFmt
 Converts bytes into formatted display<br/>
 **Usage:** ```number | byteFmt: round-to-decimal```,
 ```html
@@ -1251,7 +1323,7 @@ Converts bytes into formatted display<br/>
 1.95 KB
 1.24726 GB
 ```
-###kbFmt
+### kbFmt
 Converts kilobytes into formatted display<br/>
 **Usage:** ```number | kbFmt: round-to-decimal```,
 ```html
@@ -1262,10 +1334,10 @@ Converts kilobytes into formatted display<br/>
 1.00126 GB
 
 ```
-#Boolean
+## Boolean
 >Used for boolean expression in chaining filters
 
-###isGreaterThan
+### isGreaterThan
 **aliases:** `>`
 ```html
 <div ng-show="{{ array | map | sum | isGreaterThan: num }}"></div>
@@ -1273,7 +1345,7 @@ Converts kilobytes into formatted display<br/>
 <div ng-show="{{ array | map | sum | >: num }}"></div>
 ```
 
-###isGreaterThanOrEqualTo
+### isGreaterThanOrEqualTo
 **aliases:** `>=`
 ```html
 <div ng-show="{{ array | map | sum | isGreaterThanOrEqualTo: num }}"></div>
@@ -1281,7 +1353,7 @@ Converts kilobytes into formatted display<br/>
 <div ng-show="{{ array | map | sum | >=: num }}"></div>
 ```
 
-###isLessThan
+### isLessThan
 **aliases:** `<`
 ```html
 <div ng-show="{{ array | map | sum | isLessThan: num }}"></div>
@@ -1289,7 +1361,7 @@ Converts kilobytes into formatted display<br/>
 <div ng-show="{{ array | map | sum | <: num }}"></div>
 ```
 
-###isLessThanOrEqualTo
+### isLessThanOrEqualTo
 **aliases:** `<=`
 ```html
 <div ng-show="{{ array | map | sum | isLessThanOrEqualTo: num }}"></div>
@@ -1297,7 +1369,7 @@ Converts kilobytes into formatted display<br/>
 <div ng-show="{{ array | map | sum | <=: num }}"></div>
 ```
 
-###isEqualTo
+### isEqualTo
 **aliases:** `==`
 ```html
 <div ng-show="{{ array | map | sum | isEqualTo: num }}"></div>
@@ -1305,7 +1377,7 @@ Converts kilobytes into formatted display<br/>
 <div ng-show="{{ array | map | sum | ==: num }}"></div>
 ```
 
-###isNotEqualTo
+### isNotEqualTo
 **aliases:** `!=`
 ```html
 <div ng-show="{{ array | map | sum | isNotEqualTo: num }}"></div>
@@ -1313,7 +1385,7 @@ Converts kilobytes into formatted display<br/>
 <div ng-show="{{ array | map | sum | !=: num }}"></div>
 ```
 
-###isIdenticalTo
+### isIdenticalTo
 **aliases:** `===`
 ```html
 <div ng-show="{{ array | map | sum | isIdenticalTo: num }}"></div>
@@ -1321,52 +1393,52 @@ Converts kilobytes into formatted display<br/>
 <div ng-show="{{ array | map | sum | ===: num }}"></div>
 ```
 
-###isNotIdenticalTo
+### isNotIdenticalTo
 **aliases:** `!==`
 ```html
 <div ng-show="{{ array | map | sum | isNotIdenticalTo: num }}"></div>
 <!--or: -->
 <div ng-show="{{ array | map | sum | !==: num }}"></div>
 ```
-#Changelog
-###0.5.7
+## Changelog
+### 0.5.7
 * fix issue #119
 
-###0.5.6
+### 0.5.6
 * fix issue #145
 
-###0.5.5
+### 0.5.5
 * add `range` and `chunk-by` filters
 * fix issue #139
 
-###0.5.4
+### 0.5.4
 * add `match` and `test` filters
 
-###0.5.3
+### 0.5.3
 * add `latinize` filter
 
-###0.5.1
+### 0.5.1
 * `min` and `max` can get a property as an argument.
 * improve `slugify` filter.
 * refactor `filterWatcher`(memoize), now it works like a charm.
 * refactor `groupBy` now it can get be chain with other filters
 
-###0.4.9
+### 0.4.9
 * fix issue #38 with [reverseFilter](#reverse)
 
-###0.4.8
+### 0.4.8
 * add [defaultsFilter](#defaults)
 * improve docs, tests
 
-###0.4.7
+### 0.4.7
 * add [condition filters](#Boolean) set.
 <br/>
 <br/>
 
-#TODO
+## TODO
 - Add project website on branch gh-pages, see **[Github-help](https://help.github.com/articles/creating-project-pages-manually)**
 
-#Contributing
+## Contributing
 * If you planning add some feature please **create issue before**.
 * Don't forget about tests.
 
@@ -1380,13 +1452,7 @@ Run the tests:
 ```bash
 $ grunt test
 ```
-**Deploy:**<br/>
-Run the build task, update version before(bower,package)
-```bash
-$ grunt build
-$ git tag v0.*.*
-$ git push origin master --tags
-```
+
 [npm-image]: https://img.shields.io/npm/v/angular-filter.svg?style=flat-square
 [npm-url]: https://npmjs.org/package/angular-filter
 [travis-image]: https://img.shields.io/travis/a8m/angular-filter.svg?style=flat-square
diff --git a/bower.json b/bower.json
index 99299ba..727e7c2 100644
--- a/bower.json
+++ b/bower.json
@@ -2,19 +2,18 @@
   "name": "angular-filter",
   "main": "dist/angular-filter.js",
   "description": "Bunch of useful filters for angularJS(with no external dependencies!)",
+  "version": "0.5.17",
+  "license": "MIT",
   "repository": {
     "type": "git",
     "url": "https://github.com/a8m/angular-filter.git"
   },
   "dependencies": {
-    "angular": "*"
+    "angular": ">=1.4.3"
   },
   "devDependencies": {
-    "angular-mocks": "*"
+    "angular-mocks": "1.4.3"
   },
-  "main":[
-    "./dist/angular-filter.min.js"
-  ],
   "ignore": [
     "node_modules",
     "bower_components",
diff --git a/dist/angular-filter.js b/dist/angular-filter.js
index f50d9f9..3b797da 100644
--- a/dist/angular-filter.js
+++ b/dist/angular-filter.js
@@ -1,6 +1,6 @@
 /**
  * Bunch of useful filters for angularJS(with no external dependencies!)
- * @version v0.5.7 - 2015-10-04 * @link https://github.com/a8m/angular-filter
+ * @version v0.5.17 - 2017-09-22 * @link https://github.com/a8m/angular-filter
  * @author Ariel Mashraki <ariel@mashraki.co.il>
  * @license MIT License, http://www.opensource.org/licenses/MIT
  */
@@ -67,15 +67,23 @@ function objectContains(partial, object) {
  * @returns {*}
  */
 function hasApproxPattern(word, pattern) {
-  if(pattern === '')
-    return word;
-
-  var index = word.indexOf(pattern.charAt(0));
-
-  if(index === -1)
-    return false;
-
-  return hasApproxPattern(word.substr(index+1), pattern.substr(1))
+  // cheaper version of indexOf; instead of creating each
+  // iteration new str.
+  function indexOf(word, p, c) {
+    var j = 0;
+    while ((p + j) <= word.length) {
+      if (word.charAt(p + j) == c) return j;
+      j++;
+    }
+    return -1;
+  }
+  var p = 0;
+  for (var i = 0; i <= pattern.length; i++) {
+    var index = indexOf(word, p, pattern.charAt(i));
+    if (index == -1) return false;
+    p += index + 1;
+  }
+  return true
 }
 
 /**
@@ -109,11 +117,10 @@ if (!String.prototype.contains) {
 /**
  * @param num {Number}
  * @param decimal {Number}
- * @param $math
  * @returns {Number}
  */
-function convertToDecimal(num, decimal, $math){
-  return $math.round(num * $math.pow(10,decimal)) / ($math.pow(10,decimal));
+function convertToDecimal(num, decimal){
+  return Math.round(num * Math.pow(10,decimal)) / (Math.pow(10, decimal));
 }
 
 /**
@@ -504,7 +511,7 @@ function containsFilter($parse) {
       }
 
       return collection.some(function(elm) {
-        return (isObject(elm) || isFunction(expression))
+        return ((isString(expression) && isObject(elm)) || isFunction(expression))
           ? $parse(expression)(elm)
           : elm === expression;
       });
@@ -622,7 +629,7 @@ angular.module('a8m.every', [])
  */
 angular.module('a8m.filter-by', [])
   .filter('filterBy', ['$parse', function( $parse ) {
-    return function(collection, properties, search) {
+    return function(collection, properties, search, strict) {
       var comparator;
 
       search = (isString(search) || isNumber(search)) ?
@@ -646,16 +653,19 @@ angular.module('a8m.filter-by', [])
           if(!~prop.indexOf('+')) {
             comparator = $parse(prop)(elm)
           } else {
-            var propList = prop.replace(new RegExp('\\s', 'g'), '').split('+');
-            comparator = propList.reduce(function(prev, cur, index) {
-              return (index === 1) ? $parse(prev)(elm) + ' ' + $parse(cur)(elm) :
-                prev + ' ' + $parse(cur)(elm);
-            });
+            var propList = prop.replace(/\s+/g, '').split('+');
+            comparator = propList
+              .map(function(prop) { return $parse(prop)(elm); })
+              .join(' ');
           }
 
-          return (isString(comparator) || isNumber(comparator))
-            ? String(comparator).toLowerCase().contains(search)
-            : false;
+          if (!isString(comparator) && !isNumber(comparator)) {
+            return false;
+          }
+
+          comparator = String(comparator).toLowerCase();
+
+          return strict ? comparator === search : comparator.contains(search);
         });
       });
     }
@@ -1052,12 +1062,15 @@ angular.module('a8m.pick', [])
  */
 angular.module('a8m.range', [])
   .filter('range', function () {
-    return function (input, total) {
+    return function (input, total, start, increment, cb) {
+      start = start || 0;
+      increment = increment || 1;
       for (var i = 0; i < parseInt(total); i++) {
-        input.push(i);
+        var j = start + i * increment;
+        input.push(isFunction(cb) ? cb(j) : j);
       }
       return input;
-	  };
+    };
   });
 /**
  * @ngdoc filter
@@ -1318,6 +1331,21 @@ angular.module('a8m.xor', [])
     }
   }]);
 
+/**
+ * @ngdoc filter
+ * @name abs
+ * @kind function
+ *
+ * @description
+ * Will return the absolute value of a number
+ */
+angular.module('a8m.math.abs', [])
+  .filter('abs', function () {
+    return function (input) {
+      return Math.abs(input);
+    }
+  });
+
 /**
  * @ngdoc filter
  * @name formatBytes
@@ -1327,26 +1355,24 @@ angular.module('a8m.xor', [])
  * Convert bytes into appropriate display 
  * 1024 bytes => 1 KB
  */
-angular.module('a8m.math.byteFmt', ['a8m.math'])
-  .filter('byteFmt', ['$math', function ($math) {
+angular.module('a8m.math.byteFmt', [])
+  .filter('byteFmt', function () {
+    var compared = [{str: 'B', val: 1024}];
+    ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'].forEach(function(el, i) {
+      compared.push({str: el, val: compared[i].val * 1024 });
+    });
     return function (bytes, decimal) {
-
       if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
         isNumber(bytes) && isFinite(bytes)) {
-        if(bytes < 1024) { // within 1 KB so B
-          return convertToDecimal(bytes, decimal, $math) + ' B';
-        } else if(bytes < 1048576) { // within 1 MB so KB
-          return convertToDecimal((bytes / 1024), decimal, $math) + ' KB';
-        } else if(bytes < 1073741824){ // within 1 GB so MB
-          return convertToDecimal((bytes / 1048576), decimal, $math) + ' MB';
-        } else { // GB or more
-          return convertToDecimal((bytes / 1073741824), decimal, $math) + ' GB';
-        }
-
+        var i = 0;
+        while (i < compared.length-1 && bytes >= compared[i].val) i++;
+        bytes /= i > 0 ? compared[i-1].val : 1;
+        return convertToDecimal(bytes, decimal) + ' ' + compared[i].str;
       }
-      return "NaN";
+      return 'NaN';
     }
-  }]);
+  });
+
 /**
  * @ngdoc filter
  * @name degrees
@@ -1355,20 +1381,20 @@ angular.module('a8m.math.byteFmt', ['a8m.math'])
  * @description
  * Convert angle from radians to degrees
  */
-angular.module('a8m.math.degrees', ['a8m.math'])
-  .filter('degrees', ['$math', function ($math) {
+angular.module('a8m.math.degrees', [])
+  .filter('degrees', function () {
     return function (radians, decimal) {
       // if decimal is not an integer greater than -1, we cannot do. quit with error "NaN"
       // if degrees is not a real number, we cannot do also. quit with error "NaN"
       if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
         isNumber(radians) && isFinite(radians)) {
-        var degrees = (radians * 180) / $math.PI;
-        return $math.round(degrees * $math.pow(10,decimal)) / ($math.pow(10,decimal));
+        var degrees = (radians * 180) / Math.PI;
+        return Math.round(degrees * Math.pow(10,decimal)) / (Math.pow(10,decimal));
       } else {
-        return "NaN";
+        return 'NaN';
       }
     }
-  }]);
+  });
 
  
  
@@ -1381,34 +1407,23 @@ angular.module('a8m.math.degrees', ['a8m.math'])
  * Convert bytes into appropriate display 
  * 1024 kilobytes => 1 MB
  */
-angular.module('a8m.math.kbFmt', ['a8m.math'])
-  .filter('kbFmt', ['$math', function ($math) {
+angular.module('a8m.math.kbFmt', [])
+  .filter('kbFmt', function () {
+    var compared = [{str: 'KB', val: 1024}];
+    ['MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'].forEach(function(el, i) {
+      compared.push({str: el, val: compared[i].val * 1024 });
+    });
     return function (bytes, decimal) {
-
       if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
         isNumber(bytes) && isFinite(bytes)) {
-        if(bytes < 1024) { // within 1 MB so KB
-          return convertToDecimal(bytes, decimal, $math) + ' KB';
-        } else if(bytes < 1048576) { // within 1 GB so MB
-          return convertToDecimal((bytes / 1024), decimal, $math) + ' MB';
-        } else {
-          return convertToDecimal((bytes / 1048576), decimal, $math) + ' GB';
-        }
+        var i = 0;
+        while (i < compared.length-1 && bytes >= compared[i].val) i++;
+        bytes /= i > 0 ? compared[i-1].val : 1;
+        return convertToDecimal(bytes, decimal) + ' ' + compared[i].str;
       }
-      return "NaN";
+      return 'NaN';
     }
-  }]);
-/**
- * @ngdoc module
- * @name math
- * @description
- * reference to global Math object
- */
-angular.module('a8m.math', [])
-  .factory('$math', ['$window', function ($window) {
-    return $window.Math;
-  }]);
-
+  });
 /**
  * @ngdoc filter
  * @name max
@@ -1418,15 +1433,15 @@ angular.module('a8m.math', [])
  * Math.max will get an array and return the max value. if an expression
  * is provided, will return max value by expression.
  */
-angular.module('a8m.math.max', ['a8m.math'])
-  .filter('max', ['$math', '$parse', function ($math, $parse) {
+angular.module('a8m.math.max', [])
+  .filter('max', ['$parse', function ($parse) {
     return function (input, expression) {
 
       if(!isArray(input)) {
         return input;
       }
       return isUndefined(expression)
-        ? $math.max.apply($math, input)
+        ? Math.max.apply(Math, input)
         : input[indexByMax(input, expression)];
     };
 
@@ -1440,7 +1455,7 @@ angular.module('a8m.math.max', ['a8m.math'])
       var mappedArray = array.map(function(elm){
         return $parse(exp)(elm);
       });
-      return mappedArray.indexOf($math.max.apply($math, mappedArray));
+      return mappedArray.indexOf(Math.max.apply(Math, mappedArray));
     }
   }]);
 /**
@@ -1452,15 +1467,15 @@ angular.module('a8m.math.max', ['a8m.math'])
  * Math.min will get an array and return the min value. if an expression
  * is provided, will return min value by expression.
  */
-angular.module('a8m.math.min', ['a8m.math'])
-  .filter('min', ['$math', '$parse', function ($math, $parse) {
+angular.module('a8m.math.min', [])
+  .filter('min', ['$parse', function ($parse) {
     return function (input, expression) {
 
       if(!isArray(input)) {
         return input;
       }
       return isUndefined(expression)
-        ? $math.min.apply($math, input)
+        ? Math.min.apply(Math, input)
         : input[indexByMin(input, expression)];
     };
 
@@ -1474,7 +1489,7 @@ angular.module('a8m.math.min', ['a8m.math'])
       var mappedArray = array.map(function(elm){
         return $parse(exp)(elm);
       });
-      return mappedArray.indexOf($math.min.apply($math, mappedArray));
+      return mappedArray.indexOf(Math.min.apply(Math, mappedArray));
     }
   }]);
 /**
@@ -1485,21 +1500,21 @@ angular.module('a8m.math.min', ['a8m.math'])
  * @description
  * percentage between two numbers
  */
-angular.module('a8m.math.percent', ['a8m.math'])
-  .filter('percent', ['$math', '$window', function ($math, $window) {
+angular.module('a8m.math.percent', [])
+  .filter('percent', function () {
     return function (input, divided, round) {
 
-      var divider = isString(input) ? $window.Number(input) : input;
+      var divider = isString(input) ? Number(input) : input;
       divided = divided || 100;
       round = round || false;
 
-      if (!isNumber(divider) || $window.isNaN(divider)) return input;
+      if (!isNumber(divider) || isNaN(divider)) return input;
 
       return round
-        ? $math.round((divider / divided) * 100)
+        ? Math.round((divider / divided) * 100)
         : (divider / divided) * 100;
     }
-  }]);
+  });
 
 /**
  * @ngdoc filter
@@ -1509,19 +1524,19 @@ angular.module('a8m.math.percent', ['a8m.math'])
  * @description
  * Convert angle from degrees to radians
  */
-angular.module('a8m.math.radians', ['a8m.math'])
-  .filter('radians', ['$math', function ($math) {
+angular.module('a8m.math.radians', [])
+  .filter('radians', function() {
     return function (degrees, decimal) {
       // if decimal is not an integer greater than -1, we cannot do. quit with error "NaN"
       // if degrees is not a real number, we cannot do also. quit with error "NaN"
       if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
         isNumber(degrees) && isFinite(degrees)) {
         var radians = (degrees * 3.14159265359) / 180;
-        return $math.round(radians * $math.pow(10,decimal)) / ($math.pow(10,decimal));
+        return Math.round(radians * Math.pow(10,decimal)) / (Math.pow(10,decimal));
       }
-      return "NaN";
+      return 'NaN';
     }
-  }]);
+  });
 
  
  
@@ -1556,25 +1571,25 @@ angular.module('a8m.math.radix', [])
  * i.e: K for one thousand, M for Million, B for billion
  * e.g: number of users:235,221, decimal:1 => 235.2 K
  */
-angular.module('a8m.math.shortFmt', ['a8m.math'])
-  .filter('shortFmt', ['$math', function ($math) {
+angular.module('a8m.math.shortFmt', [])
+  .filter('shortFmt', function () {
     return function (number, decimal) {
       if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
         isNumber(number) && isFinite(number)){
         if(number < 1e3) {
-          return number;
+          return '' + number;  // Coerce to string
         } else if(number < 1e6) {
-          return convertToDecimal((number / 1e3), decimal, $math) + ' K';
+          return convertToDecimal((number / 1e3), decimal) + ' K';
         } else if(number < 1e9){
-          return convertToDecimal((number / 1e6), decimal, $math) + ' M';
+          return convertToDecimal((number / 1e6), decimal) + ' M';
         } else {
-          return convertToDecimal((number / 1e9), decimal, $math) + ' B';
+          return convertToDecimal((number / 1e9), decimal) + ' B';
         }
 
       }
-      return "NaN";
+      return 'NaN';
     }
-  }]);
+  });
 /**
  * @ngdoc filter
  * @name sum
@@ -1783,6 +1798,23 @@ angular.module('a8m.match', [])
     }
   });
 
+/**
+ * @ngdoc filter
+ * @name phone-us
+ * @kind function
+ *
+ * @description
+ * format a string or a number into a us-style
+ * phone number in the form (***) ***-****
+ */
+angular.module('a8m.phoneUS', [])
+  .filter('phoneUS', function () {
+    return function(num) {
+      num += '';
+      return '(' + num.slice(0, 3) + ') ' + num.slice(3, 6) + '-' + num.slice(6);
+    }
+  });
+
 /**
  * @ngdoc filter
  * @name repeat
@@ -1860,6 +1892,47 @@ angular.module('a8m.slugify', [])
     }
   }]);
 
+/**
+ * @ngdoc filter
+ * @name split
+ * @kind function
+ *
+ * @description
+ * split a string by a provided delimiter (none '' by default) and skip first n-delimiters
+ */
+angular.module('a8m.split', [])
+  .filter('split', function () {
+    function escapeRegExp(str) {
+      return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+    }
+
+    return function (input, delimiter, skip) {
+      var _regexp, _matches, _splitted, _temp;
+
+      if (isUndefined(input) || !isString(input)) {
+        return null;
+      }
+      if (isUndefined(delimiter)) delimiter = '';
+      if (isNaN(skip)) skip = 0;
+
+      _regexp = new RegExp(escapeRegExp(delimiter), 'g');
+      _matches = input.match(_regexp);
+      
+      if (isNull(_matches) || skip >= _matches.length) {
+        return [input];
+      }
+
+      if (skip === 0) return input.split(delimiter);
+      
+      _splitted = input.split(delimiter);
+      _temp = _splitted.splice(0, skip + 1);
+      _splitted.unshift(_temp.join(delimiter));
+    
+      return _splitted;
+    };
+  })
+;
+
 /**
  * @ngdoc filter
  * @name startWith
@@ -1994,18 +2067,23 @@ angular.module('a8m.truncate', [])
  * ucfirst
  */
 angular.module('a8m.ucfirst', [])
-  .filter('ucfirst', [function() {
-    return function(input) {
-      return isString(input)
-        ? input
-            .split(' ')
-            .map(function (ch) {
-              return ch.charAt(0).toUpperCase() + ch.substring(1);
-            })
-            .join(' ')
-        : input;
-    }
-  }]);
+  .filter({
+    ucfirst: ucfirstFilter,
+    titleize: ucfirstFilter
+  });
+
+function ucfirstFilter() {
+  return function (input) {
+    return isString(input)
+      ? input
+      .split(' ')
+      .map(function (ch) {
+        return ch.charAt(0).toUpperCase() + ch.substring(1);
+      })
+      .join(' ')
+      : input;
+  }
+}
 
 /**
  * @ngdoc filter
@@ -2233,6 +2311,8 @@ angular.module('angular.filter', [
   'a8m.repeat',
   'a8m.test',
   'a8m.match',
+  'a8m.split',
+  'a8m.phoneUS',
 
   'a8m.to-array',
   'a8m.concat',
@@ -2265,10 +2345,10 @@ angular.module('angular.filter', [
   'a8m.flatten',
   'a8m.join',
   'a8m.range',
-  
-  'a8m.math',
+
   'a8m.math.max',
   'a8m.math.min',
+  'a8m.math.abs',
   'a8m.math.percent',
   'a8m.math.radix',
   'a8m.math.sum',
diff --git a/dist/angular-filter.min.js b/dist/angular-filter.min.js
index 11714a5..7d8bd41 100644
--- a/dist/angular-filter.min.js
+++ b/dist/angular-filter.min.js
@@ -1,6 +1,6 @@
 /**
  * Bunch of useful filters for angularJS(with no external dependencies!)
- * @version v0.5.7 - 2015-10-04 * @link https://github.com/a8m/angular-filter
+ * @version v0.5.17 - 2017-09-22 * @link https://github.com/a8m/angular-filter
  * @author Ariel Mashraki <ariel@mashraki.co.il>
  * @license MIT License, http://www.opensource.org/licenses/MIT
- */!function(a,b,c){"use strict";function d(a){return D(a)?a:Object.keys(a).map(function(b){return a[b]})}function e(a){return null===a}function f(a,b){var d=Object.keys(a);return-1==d.map(function(d){return b[d]!==c&&b[d]==a[d]}).indexOf(!1)}function g(a,b){if(""===b)return a;var c=a.indexOf(b.charAt(0));return-1===c?!1:g(a.substr(c+1),b.substr(1))}function h(a,b,c){var d=0;return a.filter(function(a){var e=x(c)?b>d&&c(a):b>d;return d=e?d+1:d,e})}function i(a,b,c){return c.round(a*c.pow(10,b))/c.pow(10,b)}function j(a,b,c){b=b||[];var d=Object.keys(a);return d.forEach(function(d){if(C(a[d])&&!D(a[d])){var e=c?c+"."+d:c;j(a[d],b,e||d)}else{var f=c?c+"."+d:d;b.push(f)}}),b}function k(a){return a&&a.$evalAsync&&a.$watch}function l(){return function(a,b){return a>b}}function m(){return function(a,b){return a>=b}}function n(){return function(a,b){return b>a}}function o(){return function(a,b){return b>=a}}function p(){return function(a,b){return a==b}}function q(){return function(a,b){return a!=b}}function r(){return function(a,b){return a===b}}function s(){return function(a,b){return a!==b}}function t(a){return function(b,c){return b=C(b)?d(b):b,!D(b)||y(c)?!1:b.some(function(b){return C(b)||z(c)?a(c)(b):b===c})}}function u(a,b){return b=b||0,b>=a.length?a:D(a[b])?u(a.slice(0,b).concat(a[b],a.slice(b+1)),b):u(a,b+1)}function v(a){return function(b,c){function e(a,b){return y(b)?!1:a.some(function(a){return H(a,b)})}if(b=C(b)?d(b):b,!D(b))return b;var f=[],g=a(c);return y(c)?b.filter(function(a,b,c){return c.indexOf(a)===b}):b.filter(function(a){var b=g(a);return e(f,b)?!1:(f.push(b),!0)})}}function w(a,b,c){return b?a+c+w(a,--b,c):a}var x=b.isDefined,y=b.isUndefined,z=b.isFunction,A=b.isString,B=b.isNumber,C=b.isObject,D=b.isArray,E=b.forEach,F=b.extend,G=b.copy,H=b.equals;String.prototype.contains||(String.prototype.contains=function(){return-1!==String.prototype.indexOf.apply(this,arguments)}),b.module("a8m.angular",[]).filter("isUndefined",function(){return function(a){return b.isUndefined(a)}}).filter("isDefined",function(){return function(a){return b.isDefined(a)}}).filter("isFunction",function(){return function(a){return b.isFunction(a)}}).filter("isString",function(){return function(a){return b.isString(a)}}).filter("isNumber",function(){return function(a){return b.isNumber(a)}}).filter("isArray",function(){return function(a){return b.isArray(a)}}).filter("isObject",function(){return function(a){return b.isObject(a)}}).filter("isEqual",function(){return function(a,c){return b.equals(a,c)}}),b.module("a8m.conditions",[]).filter({isGreaterThan:l,">":l,isGreaterThanOrEqualTo:m,">=":m,isLessThan:n,"<":n,isLessThanOrEqualTo:o,"<=":o,isEqualTo:p,"==":p,isNotEqualTo:q,"!=":q,isIdenticalTo:r,"===":r,isNotIdenticalTo:s,"!==":s}),b.module("a8m.is-null",[]).filter("isNull",function(){return function(a){return e(a)}}),b.module("a8m.after-where",[]).filter("afterWhere",function(){return function(a,b){if(a=C(a)?d(a):a,!D(a)||y(b))return a;var c=a.map(function(a){return f(b,a)}).indexOf(!0);return a.slice(-1===c?0:c)}}),b.module("a8m.after",[]).filter("after",function(){return function(a,b){return a=C(a)?d(a):a,D(a)?a.slice(b):a}}),b.module("a8m.before-where",[]).filter("beforeWhere",function(){return function(a,b){if(a=C(a)?d(a):a,!D(a)||y(b))return a;var c=a.map(function(a){return f(b,a)}).indexOf(!0);return a.slice(0,-1===c?a.length:++c)}}),b.module("a8m.before",[]).filter("before",function(){return function(a,b){return a=C(a)?d(a):a,D(a)?a.slice(0,b?--b:b):a}}),b.module("a8m.chunk-by",["a8m.filter-watcher"]).filter("chunkBy",["filterWatcher",function(a){return function(b,c,d){function e(a,b){for(var c=[];a--;)c[a]=b;return c}function f(a,b,c){return D(a)?a.map(function(a,d,f){return d*=b,a=f.slice(d,d+b),!y(c)&&a.length<b?a.concat(e(b-a.length,c)):a}).slice(0,Math.ceil(a.length/b)):a}return a.isMemoized("chunkBy",arguments)||a.memoize("chunkBy",arguments,this,f(b,c,d))}}]),b.module("a8m.concat",[]).filter("concat",[function(){return function(a,b){if(y(b))return a;if(D(a))return C(b)?a.concat(d(b)):a.concat(b);if(C(a)){var c=d(a);return C(b)?c.concat(d(b)):c.concat(b)}return a}}]),b.module("a8m.contains",[]).filter({contains:["$parse",t],some:["$parse",t]}),b.module("a8m.count-by",[]).filter("countBy",["$parse",function(a){return function(b,c){var e,f={},g=a(c);return b=C(b)?d(b):b,!D(b)||y(c)?b:(b.forEach(function(a){e=g(a),f[e]||(f[e]=0),f[e]++}),f)}}]),b.module("a8m.defaults",[]).filter("defaults",["$parse",function(a){return function(b,c){if(b=C(b)?d(b):b,!D(b)||!C(c))return b;var e=j(c);return b.forEach(function(b){e.forEach(function(d){var e=a(d),f=e.assign;y(e(b))&&f(b,e(c))})}),b}}]),b.module("a8m.every",[]).filter("every",["$parse",function(a){return function(b,c){return b=C(b)?d(b):b,!D(b)||y(c)?!0:b.every(function(b){return C(b)||z(c)?a(c)(b):b===c})}}]),b.module("a8m.filter-by",[]).filter("filterBy",["$parse",function(a){return function(b,e,f){var g;return f=A(f)||B(f)?String(f).toLowerCase():c,b=C(b)?d(b):b,!D(b)||y(f)?b:b.filter(function(b){return e.some(function(c){if(~c.indexOf("+")){var d=c.replace(new RegExp("\\s","g"),"").split("+");g=d.reduce(function(c,d,e){return 1===e?a(c)(b)+" "+a(d)(b):c+" "+a(d)(b)})}else g=a(c)(b);return A(g)||B(g)?String(g).toLowerCase().contains(f):!1})})}}]),b.module("a8m.first",[]).filter("first",["$parse",function(a){return function(b){var e,f,g;return b=C(b)?d(b):b,D(b)?(g=Array.prototype.slice.call(arguments,1),e=B(g[0])?g[0]:1,f=B(g[0])?B(g[1])?c:g[1]:g[0],g.length?h(b,e,f?a(f):f):b[0]):b}}]),b.module("a8m.flatten",[]).filter("flatten",function(){return function(a,b){return b=b||!1,a=C(a)?d(a):a,D(a)?b?[].concat.apply([],a):u(a,0):a}}),b.module("a8m.fuzzy-by",[]).filter("fuzzyBy",["$parse",function(a){return function(b,c,e,f){var h,i,j=f||!1;return b=C(b)?d(b):b,!D(b)||y(c)||y(e)?b:(i=a(c),b.filter(function(a){return h=i(a),A(h)?(h=j?h:h.toLowerCase(),e=j?e:e.toLowerCase(),g(h,e)!==!1):!1}))}}]),b.module("a8m.fuzzy",[]).filter("fuzzy",function(){return function(a,b,c){function e(a,b){var c,d,e=Object.keys(a);return 0<e.filter(function(e){return c=a[e],d?!0:A(c)?(c=f?c:c.toLowerCase(),d=g(c,b)!==!1):!1}).length}var f=c||!1;return a=C(a)?d(a):a,!D(a)||y(b)?a:(b=f?b:b.toLowerCase(),a.filter(function(a){return A(a)?(a=f?a:a.toLowerCase(),g(a,b)!==!1):C(a)?e(a,b):!1}))}}),b.module("a8m.group-by",["a8m.filter-watcher"]).filter("groupBy",["$parse","filterWatcher",function(a,b){return function(c,d){function e(a,b){var c,d={};return E(a,function(a){c=b(a),d[c]||(d[c]=[]),d[c].push(a)}),d}return!C(c)||y(d)?c:b.isMemoized("groupBy",arguments)||b.memoize("groupBy",arguments,this,e(c,a(d)))}}]),b.module("a8m.is-empty",[]).filter("isEmpty",function(){return function(a){return C(a)?!d(a).length:!a.length}}),b.module("a8m.join",[]).filter("join",function(){return function(a,b){return y(a)||!D(a)?a:(y(b)&&(b=" "),a.join(b))}}),b.module("a8m.last",[]).filter("last",["$parse",function(a){return function(b){var e,f,g,i=G(b);return i=C(i)?d(i):i,D(i)?(g=Array.prototype.slice.call(arguments,1),e=B(g[0])?g[0]:1,f=B(g[0])?B(g[1])?c:g[1]:g[0],g.length?h(i.reverse(),e,f?a(f):f).reverse():i[i.length-1]):i}}]),b.module("a8m.map",[]).filter("map",["$parse",function(a){return function(b,c){return b=C(b)?d(b):b,!D(b)||y(c)?b:b.map(function(b){return a(c)(b)})}}]),b.module("a8m.omit",[]).filter("omit",["$parse",function(a){return function(b,c){return b=C(b)?d(b):b,!D(b)||y(c)?b:b.filter(function(b){return!a(c)(b)})}}]),b.module("a8m.pick",[]).filter("pick",["$parse",function(a){return function(b,c){return b=C(b)?d(b):b,!D(b)||y(c)?b:b.filter(function(b){return a(c)(b)})}}]),b.module("a8m.range",[]).filter("range",function(){return function(a,b){for(var c=0;c<parseInt(b);c++)a.push(c);return a}}),b.module("a8m.remove-with",[]).filter("removeWith",function(){return function(a,b){return y(b)?a:(a=C(a)?d(a):a,a.filter(function(a){return!f(b,a)}))}}),b.module("a8m.remove",[]).filter("remove",function(){return function(a){a=C(a)?d(a):a;var b=Array.prototype.slice.call(arguments,1);return D(a)?a.filter(function(a){return!b.some(function(b){return H(b,a)})}):a}}),b.module("a8m.reverse",[]).filter("reverse",[function(){return function(a){return a=C(a)?d(a):a,A(a)?a.split("").reverse().join(""):D(a)?a.slice().reverse():a}}]),b.module("a8m.search-field",[]).filter("searchField",["$parse",function(a){return function(b){var c,e;b=C(b)?d(b):b;var f=Array.prototype.slice.call(arguments,1);return D(b)&&f.length?b.map(function(b){return e=f.map(function(d){return(c=a(d))(b)}).join(" "),F(b,{searchField:e})}):b}}]),b.module("a8m.to-array",[]).filter("toArray",function(){return function(a,b){return C(a)?b?Object.keys(a).map(function(b){return F(a[b],{$key:b})}):d(a):a}}),b.module("a8m.unique",[]).filter({unique:["$parse",v],uniq:["$parse",v]}),b.module("a8m.where",[]).filter("where",function(){return function(a,b){return y(b)?a:(a=C(a)?d(a):a,a.filter(function(a){return f(b,a)}))}}),b.module("a8m.xor",[]).filter("xor",["$parse",function(a){return function(b,c,e){function f(b,c){var d=a(e);return c.some(function(a){return e?H(d(a),d(b)):H(a,b)})}return e=e||!1,b=C(b)?d(b):b,c=C(c)?d(c):c,D(b)&&D(c)?b.concat(c).filter(function(a){return!(f(a,b)&&f(a,c))}):b}}]),b.module("a8m.math.byteFmt",["a8m.math"]).filter("byteFmt",["$math",function(a){return function(b,c){return B(c)&&isFinite(c)&&c%1===0&&c>=0&&B(b)&&isFinite(b)?1024>b?i(b,c,a)+" B":1048576>b?i(b/1024,c,a)+" KB":1073741824>b?i(b/1048576,c,a)+" MB":i(b/1073741824,c,a)+" GB":"NaN"}}]),b.module("a8m.math.degrees",["a8m.math"]).filter("degrees",["$math",function(a){return function(b,c){if(B(c)&&isFinite(c)&&c%1===0&&c>=0&&B(b)&&isFinite(b)){var d=180*b/a.PI;return a.round(d*a.pow(10,c))/a.pow(10,c)}return"NaN"}}]),b.module("a8m.math.kbFmt",["a8m.math"]).filter("kbFmt",["$math",function(a){return function(b,c){return B(c)&&isFinite(c)&&c%1===0&&c>=0&&B(b)&&isFinite(b)?1024>b?i(b,c,a)+" KB":1048576>b?i(b/1024,c,a)+" MB":i(b/1048576,c,a)+" GB":"NaN"}}]),b.module("a8m.math",[]).factory("$math",["$window",function(a){return a.Math}]),b.module("a8m.math.max",["a8m.math"]).filter("max",["$math","$parse",function(a,b){function c(c,d){var e=c.map(function(a){return b(d)(a)});return e.indexOf(a.max.apply(a,e))}return function(b,d){return D(b)?y(d)?a.max.apply(a,b):b[c(b,d)]:b}}]),b.module("a8m.math.min",["a8m.math"]).filter("min",["$math","$parse",function(a,b){function c(c,d){var e=c.map(function(a){return b(d)(a)});return e.indexOf(a.min.apply(a,e))}return function(b,d){return D(b)?y(d)?a.min.apply(a,b):b[c(b,d)]:b}}]),b.module("a8m.math.percent",["a8m.math"]).filter("percent",["$math","$window",function(a,b){return function(c,d,e){var f=A(c)?b.Number(c):c;return d=d||100,e=e||!1,!B(f)||b.isNaN(f)?c:e?a.round(f/d*100):f/d*100}}]),b.module("a8m.math.radians",["a8m.math"]).filter("radians",["$math",function(a){return function(b,c){if(B(c)&&isFinite(c)&&c%1===0&&c>=0&&B(b)&&isFinite(b)){var d=3.14159265359*b/180;return a.round(d*a.pow(10,c))/a.pow(10,c)}return"NaN"}}]),b.module("a8m.math.radix",[]).filter("radix",function(){return function(a,b){var c=/^[2-9]$|^[1-2]\d$|^3[0-6]$/;return B(a)&&c.test(b)?a.toString(b).toUpperCase():a}}),b.module("a8m.math.shortFmt",["a8m.math"]).filter("shortFmt",["$math",function(a){return function(b,c){return B(c)&&isFinite(c)&&c%1===0&&c>=0&&B(b)&&isFinite(b)?1e3>b?b:1e6>b?i(b/1e3,c,a)+" K":1e9>b?i(b/1e6,c,a)+" M":i(b/1e9,c,a)+" B":"NaN"}}]),b.module("a8m.math.sum",[]).filter("sum",function(){return function(a,b){return D(a)?a.reduce(function(a,b){return a+b},b||0):a}}),b.module("a8m.ends-with",[]).filter("endsWith",function(){return function(a,b,c){var d,e=c||!1;return!A(a)||y(b)?a:(a=e?a:a.toLowerCase(),d=a.length-b.length,-1!==a.indexOf(e?b:b.toLowerCase(),d))}}),b.module("a8m.latinize",[]).filter("latinize",[function(){function a(a){return a.replace(/[^\u0000-\u007E]/g,function(a){return c[a]||a})}for(var b=[{base:"A",letters:"AⒶＡÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ"},{base:"AA",letters:"Ꜳ"},{base:"AE",letters:"ÆǼǢ"},{base:"AO",letters:"Ꜵ"},{base:"AU",letters:"Ꜷ"},{base:"AV",letters:"ꜸꜺ"},{base:"AY",letters:"Ꜽ"},{base:"B",letters:"BⒷＢḂḄḆɃƂƁ"},{base:"C",letters:"CⒸＣĆĈĊČÇḈƇȻꜾ"},{base:"D",letters:"DⒹＤḊĎḌḐḒḎĐƋƊƉꝹ"},{base:"DZ",letters:"ǱǄ"},{base:"Dz",letters:"ǲǅ"},{base:"E",letters:"EⒺＥÈÉÊỀẾỄỂẼĒḔḖĔĖËẺĚȄȆẸỆȨḜĘḘḚƐƎ"},{base:"F",letters:"FⒻＦḞƑꝻ"},{base:"G",letters:"GⒼＧǴĜḠĞĠǦĢǤƓꞠꝽꝾ"},{base:"H",letters:"HⒽＨĤḢḦȞḤḨḪĦⱧⱵꞍ"},{base:"I",letters:"IⒾＩÌÍÎĨĪĬİÏḮỈǏȈȊỊĮḬƗ"},{base:"J",letters:"JⒿＪĴɈ"},{base:"K",letters:"KⓀＫḰǨḲĶḴƘⱩꝀꝂꝄꞢ"},{base:"L",letters:"LⓁＬĿĹĽḶḸĻḼḺŁȽⱢⱠꝈꝆꞀ"},{base:"LJ",letters:"Ǉ"},{base:"Lj",letters:"ǈ"},{base:"M",letters:"MⓂＭḾṀṂⱮƜ"},{base:"N",letters:"NⓃＮǸŃÑṄŇṆŅṊṈȠƝꞐꞤ"},{base:"NJ",letters:"Ǌ"},{base:"Nj",letters:"ǋ"},{base:"O",letters:"OⓄＯÒÓÔỒỐỖỔÕṌȬṎŌṐṒŎȮȰÖȪỎŐǑȌȎƠỜỚỠỞỢỌỘǪǬØǾƆƟꝊꝌ"},{base:"OI",letters:"Ƣ"},{base:"OO",letters:"Ꝏ"},{base:"OU",letters:"Ȣ"},{base:"OE",letters:"Œ"},{base:"oe",letters:"œ"},{base:"P",letters:"PⓅＰṔṖƤⱣꝐꝒꝔ"},{base:"Q",letters:"QⓆＱꝖꝘɊ"},{base:"R",letters:"RⓇＲŔṘŘȐȒṚṜŖṞɌⱤꝚꞦꞂ"},{base:"S",letters:"SⓈＳẞŚṤŜṠŠṦṢṨȘŞⱾꞨꞄ"},{base:"T",letters:"TⓉＴṪŤṬȚŢṰṮŦƬƮȾꞆ"},{base:"TZ",letters:"Ꜩ"},{base:"U",letters:"UⓊＵÙÚÛŨṸŪṺŬÜǛǗǕǙỦŮŰǓȔȖƯỪỨỮỬỰỤṲŲṶṴɄ"},{base:"V",letters:"VⓋＶṼṾƲꝞɅ"},{base:"VY",letters:"Ꝡ"},{base:"W",letters:"WⓌＷẀẂŴẆẄẈⱲ"},{base:"X",letters:"XⓍＸẊẌ"},{base:"Y",letters:"YⓎＹỲÝŶỸȲẎŸỶỴƳɎỾ"},{base:"Z",letters:"ZⓏＺŹẐŻŽẒẔƵȤⱿⱫꝢ"},{base:"a",letters:"aⓐａẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐ"},{base:"aa",letters:"ꜳ"},{base:"ae",letters:"æǽǣ"},{base:"ao",letters:"ꜵ"},{base:"au",letters:"ꜷ"},{base:"av",letters:"ꜹꜻ"},{base:"ay",letters:"ꜽ"},{base:"b",letters:"bⓑｂḃḅḇƀƃɓ"},{base:"c",letters:"cⓒｃćĉċčçḉƈȼꜿↄ"},{base:"d",letters:"dⓓｄḋďḍḑḓḏđƌɖɗꝺ"},{base:"dz",letters:"ǳǆ"},{base:"e",letters:"eⓔｅèéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛɇɛǝ"},{base:"f",letters:"fⓕｆḟƒꝼ"},{base:"g",letters:"gⓖｇǵĝḡğġǧģǥɠꞡᵹꝿ"},{base:"h",letters:"hⓗｈĥḣḧȟḥḩḫẖħⱨⱶɥ"},{base:"hv",letters:"ƕ"},{base:"i",letters:"iⓘｉìíîĩīĭïḯỉǐȉȋịįḭɨı"},{base:"j",letters:"jⓙｊĵǰɉ"},{base:"k",letters:"kⓚｋḱǩḳķḵƙⱪꝁꝃꝅꞣ"},{base:"l",letters:"lⓛｌŀĺľḷḹļḽḻſłƚɫⱡꝉꞁꝇ"},{base:"lj",letters:"ǉ"},{base:"m",letters:"mⓜｍḿṁṃɱɯ"},{base:"n",letters:"nⓝｎǹńñṅňṇņṋṉƞɲŉꞑꞥ"},{base:"nj",letters:"ǌ"},{base:"o",letters:"oⓞｏòóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộǫǭøǿɔꝋꝍɵ"},{base:"oi",letters:"ƣ"},{base:"ou",letters:"ȣ"},{base:"oo",letters:"ꝏ"},{base:"p",letters:"pⓟｐṕṗƥᵽꝑꝓꝕ"},{base:"q",letters:"qⓠｑɋꝗꝙ"},{base:"r",letters:"rⓡｒŕṙřȑȓṛṝŗṟɍɽꝛꞧꞃ"},{base:"s",letters:"sⓢｓßśṥŝṡšṧṣṩșşȿꞩꞅẛ"},{base:"t",letters:"tⓣｔṫẗťṭțţṱṯŧƭʈⱦꞇ"},{base:"tz",letters:"ꜩ"},{base:"u",letters:"uⓤｕùúûũṹūṻŭüǜǘǖǚủůűǔȕȗưừứữửựụṳųṷṵʉ"},{base:"v",letters:"vⓥｖṽṿʋꝟʌ"},{base:"vy",letters:"ꝡ"},{base:"w",letters:"wⓦｗẁẃŵẇẅẘẉⱳ"},{base:"x",letters:"xⓧｘẋẍ"},{base:"y",letters:"yⓨｙỳýŷỹȳẏÿỷẙỵƴɏỿ"},{base:"z",letters:"zⓩｚźẑżžẓẕƶȥɀⱬꝣ"}],c={},d=0;d<b.length;d++)for(var e=b[d].letters.split(""),f=0;f<e.length;f++)c[e[f]]=b[d].base;return function(b){return A(b)?a(b):b}}]),b.module("a8m.ltrim",[]).filter("ltrim",function(){return function(a,b){var c=b||"\\s";return A(a)?a.replace(new RegExp("^"+c+"+"),""):a}}),b.module("a8m.match",[]).filter("match",function(){return function(a,b,c){var d=new RegExp(b,c);return A(a)?a.match(d):null}}),b.module("a8m.repeat",[]).filter("repeat",[function(){return function(a,b,c){var d=~~b;return A(a)&&d?w(a,--b,c||""):a}}]),b.module("a8m.rtrim",[]).filter("rtrim",function(){return function(a,b){var c=b||"\\s";return A(a)?a.replace(new RegExp(c+"+$"),""):a}}),b.module("a8m.slugify",[]).filter("slugify",[function(){return function(a,b){var c=y(b)?"-":b;return A(a)?a.toLowerCase().replace(/\s+/g,c):a}}]),b.module("a8m.starts-with",[]).filter("startsWith",function(){return function(a,b,c){var d=c||!1;return!A(a)||y(b)?a:(a=d?a:a.toLowerCase(),!a.indexOf(d?b:b.toLowerCase()))}}),b.module("a8m.stringular",[]).filter("stringular",function(){return function(a){var b=Array.prototype.slice.call(arguments,1);return a.replace(/{(\d+)}/g,function(a,c){return y(b[c])?a:b[c]})}}),b.module("a8m.strip-tags",[]).filter("stripTags",function(){return function(a){return A(a)?a.replace(/<\S[^><]*>/g,""):a}}),b.module("a8m.test",[]).filter("test",function(){return function(a,b,c){var d=new RegExp(b,c);return A(a)?d.test(a):a}}),b.module("a8m.trim",[]).filter("trim",function(){return function(a,b){var c=b||"\\s";return A(a)?a.replace(new RegExp("^"+c+"+|"+c+"+$","g"),""):a}}),b.module("a8m.truncate",[]).filter("truncate",function(){return function(a,b,c,d){return b=y(b)?a.length:b,d=d||!1,c=c||"",!A(a)||a.length<=b?a:a.substring(0,d?-1===a.indexOf(" ",b)?a.length:a.indexOf(" ",b):b)+c}}),b.module("a8m.ucfirst",[]).filter("ucfirst",[function(){return function(a){return A(a)?a.split(" ").map(function(a){return a.charAt(0).toUpperCase()+a.substring(1)}).join(" "):a}}]),b.module("a8m.uri-component-encode",[]).filter("uriComponentEncode",["$window",function(a){return function(b){return A(b)?a.encodeURIComponent(b):b}}]),b.module("a8m.uri-encode",[]).filter("uriEncode",["$window",function(a){return function(b){return A(b)?a.encodeURI(b):b}}]),b.module("a8m.wrap",[]).filter("wrap",function(){return function(a,b,c){return A(a)&&x(b)?[b,a,c||b].join(""):a}}),b.module("a8m.filter-watcher",[]).provider("filterWatcher",function(){this.$get=["$window","$rootScope",function(a,b){function c(b,c){function d(){var b=[];return function(c,d){if(C(d)&&!e(d)){if(~b.indexOf(d))return"[Circular]";b.push(d)}return a==d?"$WINDOW":a.document==d?"$DOCUMENT":k(d)?"$SCOPE":d}}return[b,JSON.stringify(c,d())].join("#").replace(/"/g,"")}function d(a){var b=a.targetScope.$id;E(l[b],function(a){delete j[a]}),delete l[b]}function f(){m(function(){b.$$phase||(j={})},2e3)}function g(a,b){var c=a.$id;return y(l[c])&&(a.$on("$destroy",d),l[c]=[]),l[c].push(b)}function h(a,b){var d=c(a,b);return j[d]}function i(a,b,d,e){var h=c(a,b);return j[h]=e,k(d)?g(d,h):f(),e}var j={},l={},m=a.setTimeout;return{isMemoized:h,memoize:i}}]}),b.module("angular.filter",["a8m.ucfirst","a8m.uri-encode","a8m.uri-component-encode","a8m.slugify","a8m.latinize","a8m.strip-tags","a8m.stringular","a8m.truncate","a8m.starts-with","a8m.ends-with","a8m.wrap","a8m.trim","a8m.ltrim","a8m.rtrim","a8m.repeat","a8m.test","a8m.match","a8m.to-array","a8m.concat","a8m.contains","a8m.unique","a8m.is-empty","a8m.after","a8m.after-where","a8m.before","a8m.before-where","a8m.defaults","a8m.where","a8m.reverse","a8m.remove","a8m.remove-with","a8m.group-by","a8m.count-by","a8m.chunk-by","a8m.search-field","a8m.fuzzy-by","a8m.fuzzy","a8m.omit","a8m.pick","a8m.every","a8m.filter-by","a8m.xor","a8m.map","a8m.first","a8m.last","a8m.flatten","a8m.join","a8m.range","a8m.math","a8m.math.max","a8m.math.min","a8m.math.percent","a8m.math.radix","a8m.math.sum","a8m.math.degrees","a8m.math.radians","a8m.math.byteFmt","a8m.math.kbFmt","a8m.math.shortFmt","a8m.angular","a8m.conditions","a8m.is-null","a8m.filter-watcher"])}(window,window.angular);
\ No newline at end of file
+ */!function(a,b,c){"use strict";function d(a){return E(a)?a:Object.keys(a).map(function(b){return a[b]})}function e(a){return null===a}function f(a,b){var d=Object.keys(a);return d.map(function(d){return b[d]!==c&&b[d]==a[d]}).indexOf(!1)==-1}function g(a,b){function c(a,b,c){for(var d=0;b+d<=a.length;){if(a.charAt(b+d)==c)return d;d++}return-1}for(var d=0,e=0;e<=b.length;e++){var f=c(a,d,b.charAt(e));if(f==-1)return!1;d+=f+1}return!0}function h(a,b,c){var d=0;return a.filter(function(a){var e=y(c)?d<b&&c(a):d<b;return d=e?d+1:d,e})}function i(a,b){return Math.round(a*Math.pow(10,b))/Math.pow(10,b)}function j(a,b,c){b=b||[];var d=Object.keys(a);return d.forEach(function(d){if(D(a[d])&&!E(a[d])){var e=c?c+"."+d:c;j(a[d],b,e||d)}else{var f=c?c+"."+d:d;b.push(f)}}),b}function k(a){return a&&a.$evalAsync&&a.$watch}function l(){return function(a,b){return a>b}}function m(){return function(a,b){return a>=b}}function n(){return function(a,b){return a<b}}function o(){return function(a,b){return a<=b}}function p(){return function(a,b){return a==b}}function q(){return function(a,b){return a!=b}}function r(){return function(a,b){return a===b}}function s(){return function(a,b){return a!==b}}function t(a){return function(b,c){return b=D(b)?d(b):b,!(!E(b)||z(c))&&b.some(function(b){return B(c)&&D(b)||A(c)?a(c)(b):b===c})}}function u(a,b){return b=b||0,b>=a.length?a:E(a[b])?u(a.slice(0,b).concat(a[b],a.slice(b+1)),b):u(a,b+1)}function v(a){return function(b,c){function e(a,b){return!z(b)&&a.some(function(a){return I(a,b)})}if(b=D(b)?d(b):b,!E(b))return b;var f=[],g=a(c);return z(c)?b.filter(function(a,b,c){return c.indexOf(a)===b}):b.filter(function(a){var b=g(a);return!e(f,b)&&(f.push(b),!0)})}}function w(a,b,c){return b?a+c+w(a,--b,c):a}function x(){return function(a){return B(a)?a.split(" ").map(function(a){return a.charAt(0).toUpperCase()+a.substring(1)}).join(" "):a}}var y=b.isDefined,z=b.isUndefined,A=b.isFunction,B=b.isString,C=b.isNumber,D=b.isObject,E=b.isArray,F=b.forEach,G=b.extend,H=b.copy,I=b.equals;String.prototype.contains||(String.prototype.contains=function(){return String.prototype.indexOf.apply(this,arguments)!==-1}),b.module("a8m.angular",[]).filter("isUndefined",function(){return function(a){return b.isUndefined(a)}}).filter("isDefined",function(){return function(a){return b.isDefined(a)}}).filter("isFunction",function(){return function(a){return b.isFunction(a)}}).filter("isString",function(){return function(a){return b.isString(a)}}).filter("isNumber",function(){return function(a){return b.isNumber(a)}}).filter("isArray",function(){return function(a){return b.isArray(a)}}).filter("isObject",function(){return function(a){return b.isObject(a)}}).filter("isEqual",function(){return function(a,c){return b.equals(a,c)}}),b.module("a8m.conditions",[]).filter({isGreaterThan:l,">":l,isGreaterThanOrEqualTo:m,">=":m,isLessThan:n,"<":n,isLessThanOrEqualTo:o,"<=":o,isEqualTo:p,"==":p,isNotEqualTo:q,"!=":q,isIdenticalTo:r,"===":r,isNotIdenticalTo:s,"!==":s}),b.module("a8m.is-null",[]).filter("isNull",function(){return function(a){return e(a)}}),b.module("a8m.after-where",[]).filter("afterWhere",function(){return function(a,b){if(a=D(a)?d(a):a,!E(a)||z(b))return a;var c=a.map(function(a){return f(b,a)}).indexOf(!0);return a.slice(c===-1?0:c)}}),b.module("a8m.after",[]).filter("after",function(){return function(a,b){return a=D(a)?d(a):a,E(a)?a.slice(b):a}}),b.module("a8m.before-where",[]).filter("beforeWhere",function(){return function(a,b){if(a=D(a)?d(a):a,!E(a)||z(b))return a;var c=a.map(function(a){return f(b,a)}).indexOf(!0);return a.slice(0,c===-1?a.length:++c)}}),b.module("a8m.before",[]).filter("before",function(){return function(a,b){return a=D(a)?d(a):a,E(a)?a.slice(0,b?--b:b):a}}),b.module("a8m.chunk-by",["a8m.filter-watcher"]).filter("chunkBy",["filterWatcher",function(a){return function(b,c,d){function e(a,b){for(var c=[];a--;)c[a]=b;return c}function f(a,b,c){return E(a)?a.map(function(a,d,f){return d*=b,a=f.slice(d,d+b),!z(c)&&a.length<b?a.concat(e(b-a.length,c)):a}).slice(0,Math.ceil(a.length/b)):a}return a.isMemoized("chunkBy",arguments)||a.memoize("chunkBy",arguments,this,f(b,c,d))}}]),b.module("a8m.concat",[]).filter("concat",[function(){return function(a,b){if(z(b))return a;if(E(a))return D(b)?a.concat(d(b)):a.concat(b);if(D(a)){var c=d(a);return D(b)?c.concat(d(b)):c.concat(b)}return a}}]),b.module("a8m.contains",[]).filter({contains:["$parse",t],some:["$parse",t]}),b.module("a8m.count-by",[]).filter("countBy",["$parse",function(a){return function(b,c){var e,f={},g=a(c);return b=D(b)?d(b):b,!E(b)||z(c)?b:(b.forEach(function(a){e=g(a),f[e]||(f[e]=0),f[e]++}),f)}}]),b.module("a8m.defaults",[]).filter("defaults",["$parse",function(a){return function(b,c){if(b=D(b)?d(b):b,!E(b)||!D(c))return b;var e=j(c);return b.forEach(function(b){e.forEach(function(d){var e=a(d),f=e.assign;z(e(b))&&f(b,e(c))})}),b}}]),b.module("a8m.every",[]).filter("every",["$parse",function(a){return function(b,c){return b=D(b)?d(b):b,!(E(b)&&!z(c))||b.every(function(b){return D(b)||A(c)?a(c)(b):b===c})}}]),b.module("a8m.filter-by",[]).filter("filterBy",["$parse",function(a){return function(b,e,f,g){var h;return f=B(f)||C(f)?String(f).toLowerCase():c,b=D(b)?d(b):b,!E(b)||z(f)?b:b.filter(function(b){return e.some(function(c){if(~c.indexOf("+")){var d=c.replace(/\s+/g,"").split("+");h=d.map(function(c){return a(c)(b)}).join(" ")}else h=a(c)(b);return!(!B(h)&&!C(h))&&(h=String(h).toLowerCase(),g?h===f:h.contains(f))})})}}]),b.module("a8m.first",[]).filter("first",["$parse",function(a){return function(b){var e,f,g;return b=D(b)?d(b):b,E(b)?(g=Array.prototype.slice.call(arguments,1),e=C(g[0])?g[0]:1,f=C(g[0])?C(g[1])?c:g[1]:g[0],g.length?h(b,e,f?a(f):f):b[0]):b}}]),b.module("a8m.flatten",[]).filter("flatten",function(){return function(a,b){return b=b||!1,a=D(a)?d(a):a,E(a)?b?[].concat.apply([],a):u(a,0):a}}),b.module("a8m.fuzzy-by",[]).filter("fuzzyBy",["$parse",function(a){return function(b,c,e,f){var h,i,j=f||!1;return b=D(b)?d(b):b,!E(b)||z(c)||z(e)?b:(i=a(c),b.filter(function(a){return h=i(a),!!B(h)&&(h=j?h:h.toLowerCase(),e=j?e:e.toLowerCase(),g(h,e)!==!1)}))}}]),b.module("a8m.fuzzy",[]).filter("fuzzy",function(){return function(a,b,c){function e(a,b){var c,d,e=Object.keys(a);return 0<e.filter(function(e){return c=a[e],!!d||!!B(c)&&(c=f?c:c.toLowerCase(),d=g(c,b)!==!1)}).length}var f=c||!1;return a=D(a)?d(a):a,!E(a)||z(b)?a:(b=f?b:b.toLowerCase(),a.filter(function(a){return B(a)?(a=f?a:a.toLowerCase(),g(a,b)!==!1):!!D(a)&&e(a,b)}))}}),b.module("a8m.group-by",["a8m.filter-watcher"]).filter("groupBy",["$parse","filterWatcher",function(a,b){return function(c,d){function e(a,b){var c,d={};return F(a,function(a){c=b(a),d[c]||(d[c]=[]),d[c].push(a)}),d}return!D(c)||z(d)?c:b.isMemoized("groupBy",arguments)||b.memoize("groupBy",arguments,this,e(c,a(d)))}}]),b.module("a8m.is-empty",[]).filter("isEmpty",function(){return function(a){return D(a)?!d(a).length:!a.length}}),b.module("a8m.join",[]).filter("join",function(){return function(a,b){return z(a)||!E(a)?a:(z(b)&&(b=" "),a.join(b))}}),b.module("a8m.last",[]).filter("last",["$parse",function(a){return function(b){var e,f,g,i=H(b);return i=D(i)?d(i):i,E(i)?(g=Array.prototype.slice.call(arguments,1),e=C(g[0])?g[0]:1,f=C(g[0])?C(g[1])?c:g[1]:g[0],g.length?h(i.reverse(),e,f?a(f):f).reverse():i[i.length-1]):i}}]),b.module("a8m.map",[]).filter("map",["$parse",function(a){return function(b,c){return b=D(b)?d(b):b,!E(b)||z(c)?b:b.map(function(b){return a(c)(b)})}}]),b.module("a8m.omit",[]).filter("omit",["$parse",function(a){return function(b,c){return b=D(b)?d(b):b,!E(b)||z(c)?b:b.filter(function(b){return!a(c)(b)})}}]),b.module("a8m.pick",[]).filter("pick",["$parse",function(a){return function(b,c){return b=D(b)?d(b):b,!E(b)||z(c)?b:b.filter(function(b){return a(c)(b)})}}]),b.module("a8m.range",[]).filter("range",function(){return function(a,b,c,d,e){c=c||0,d=d||1;for(var f=0;f<parseInt(b);f++){var g=c+f*d;a.push(A(e)?e(g):g)}return a}}),b.module("a8m.remove-with",[]).filter("removeWith",function(){return function(a,b){return z(b)?a:(a=D(a)?d(a):a,a.filter(function(a){return!f(b,a)}))}}),b.module("a8m.remove",[]).filter("remove",function(){return function(a){a=D(a)?d(a):a;var b=Array.prototype.slice.call(arguments,1);return E(a)?a.filter(function(a){return!b.some(function(b){return I(b,a)})}):a}}),b.module("a8m.reverse",[]).filter("reverse",[function(){return function(a){return a=D(a)?d(a):a,B(a)?a.split("").reverse().join(""):E(a)?a.slice().reverse():a}}]),b.module("a8m.search-field",[]).filter("searchField",["$parse",function(a){return function(b){var c,e;b=D(b)?d(b):b;var f=Array.prototype.slice.call(arguments,1);return E(b)&&f.length?b.map(function(b){return e=f.map(function(d){return(c=a(d))(b)}).join(" "),G(b,{searchField:e})}):b}}]),b.module("a8m.to-array",[]).filter("toArray",function(){return function(a,b){return D(a)?b?Object.keys(a).map(function(b){return G(a[b],{$key:b})}):d(a):a}}),b.module("a8m.unique",[]).filter({unique:["$parse",v],uniq:["$parse",v]}),b.module("a8m.where",[]).filter("where",function(){return function(a,b){return z(b)?a:(a=D(a)?d(a):a,a.filter(function(a){return f(b,a)}))}}),b.module("a8m.xor",[]).filter("xor",["$parse",function(a){return function(b,c,e){function f(b,c){var d=a(e);return c.some(function(a){return e?I(d(a),d(b)):I(a,b)})}return e=e||!1,b=D(b)?d(b):b,c=D(c)?d(c):c,E(b)&&E(c)?b.concat(c).filter(function(a){return!(f(a,b)&&f(a,c))}):b}}]),b.module("a8m.math.abs",[]).filter("abs",function(){return function(a){return Math.abs(a)}}),b.module("a8m.math.byteFmt",[]).filter("byteFmt",function(){var a=[{str:"B",val:1024}];return["KB","MB","GB","TB","PB","EB","ZB","YB"].forEach(function(b,c){a.push({str:b,val:1024*a[c].val})}),function(b,c){if(C(c)&&isFinite(c)&&c%1===0&&c>=0&&C(b)&&isFinite(b)){for(var d=0;d<a.length-1&&b>=a[d].val;)d++;return b/=d>0?a[d-1].val:1,i(b,c)+" "+a[d].str}return"NaN"}}),b.module("a8m.math.degrees",[]).filter("degrees",function(){return function(a,b){if(C(b)&&isFinite(b)&&b%1===0&&b>=0&&C(a)&&isFinite(a)){var c=180*a/Math.PI;return Math.round(c*Math.pow(10,b))/Math.pow(10,b)}return"NaN"}}),b.module("a8m.math.kbFmt",[]).filter("kbFmt",function(){var a=[{str:"KB",val:1024}];return["MB","GB","TB","PB","EB","ZB","YB"].forEach(function(b,c){a.push({str:b,val:1024*a[c].val})}),function(b,c){if(C(c)&&isFinite(c)&&c%1===0&&c>=0&&C(b)&&isFinite(b)){for(var d=0;d<a.length-1&&b>=a[d].val;)d++;return b/=d>0?a[d-1].val:1,i(b,c)+" "+a[d].str}return"NaN"}}),b.module("a8m.math.max",[]).filter("max",["$parse",function(a){function b(b,c){var d=b.map(function(b){return a(c)(b)});return d.indexOf(Math.max.apply(Math,d))}return function(a,c){return E(a)?z(c)?Math.max.apply(Math,a):a[b(a,c)]:a}}]),b.module("a8m.math.min",[]).filter("min",["$parse",function(a){function b(b,c){var d=b.map(function(b){return a(c)(b)});return d.indexOf(Math.min.apply(Math,d))}return function(a,c){return E(a)?z(c)?Math.min.apply(Math,a):a[b(a,c)]:a}}]),b.module("a8m.math.percent",[]).filter("percent",function(){return function(a,b,c){var d=B(a)?Number(a):a;return b=b||100,c=c||!1,!C(d)||isNaN(d)?a:c?Math.round(d/b*100):d/b*100}}),b.module("a8m.math.radians",[]).filter("radians",function(){return function(a,b){if(C(b)&&isFinite(b)&&b%1===0&&b>=0&&C(a)&&isFinite(a)){var c=3.14159265359*a/180;return Math.round(c*Math.pow(10,b))/Math.pow(10,b)}return"NaN"}}),b.module("a8m.math.radix",[]).filter("radix",function(){return function(a,b){var c=/^[2-9]$|^[1-2]\d$|^3[0-6]$/;return C(a)&&c.test(b)?a.toString(b).toUpperCase():a}}),b.module("a8m.math.shortFmt",[]).filter("shortFmt",function(){return function(a,b){return C(b)&&isFinite(b)&&b%1===0&&b>=0&&C(a)&&isFinite(a)?a<1e3?""+a:a<1e6?i(a/1e3,b)+" K":a<1e9?i(a/1e6,b)+" M":i(a/1e9,b)+" B":"NaN"}}),b.module("a8m.math.sum",[]).filter("sum",function(){return function(a,b){return E(a)?a.reduce(function(a,b){return a+b},b||0):a}}),b.module("a8m.ends-with",[]).filter("endsWith",function(){return function(a,b,c){var d,e=c||!1;return!B(a)||z(b)?a:(a=e?a:a.toLowerCase(),d=a.length-b.length,a.indexOf(e?b:b.toLowerCase(),d)!==-1)}}),b.module("a8m.latinize",[]).filter("latinize",[function(){function a(a){return a.replace(/[^\u0000-\u007E]/g,function(a){return c[a]||a})}for(var b=[{base:"A",letters:"AⒶＡÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ"},{base:"AA",letters:"Ꜳ"},{base:"AE",letters:"ÆǼǢ"},{base:"AO",letters:"Ꜵ"},{base:"AU",letters:"Ꜷ"},{base:"AV",letters:"ꜸꜺ"},{base:"AY",letters:"Ꜽ"},{base:"B",letters:"BⒷＢḂḄḆɃƂƁ"},{base:"C",letters:"CⒸＣĆĈĊČÇḈƇȻꜾ"},{base:"D",letters:"DⒹＤḊĎḌḐḒḎĐƋƊƉꝹ"},{base:"DZ",letters:"ǱǄ"},{base:"Dz",letters:"ǲǅ"},{base:"E",letters:"EⒺＥÈÉÊỀẾỄỂẼĒḔḖĔĖËẺĚȄȆẸỆȨḜĘḘḚƐƎ"},{base:"F",letters:"FⒻＦḞƑꝻ"},{base:"G",letters:"GⒼＧǴĜḠĞĠǦĢǤƓꞠꝽꝾ"},{base:"H",letters:"HⒽＨĤḢḦȞḤḨḪĦⱧⱵꞍ"},{base:"I",letters:"IⒾＩÌÍÎĨĪĬİÏḮỈǏȈȊỊĮḬƗ"},{base:"J",letters:"JⒿＪĴɈ"},{base:"K",letters:"KⓀＫḰǨḲĶḴƘⱩꝀꝂꝄꞢ"},{base:"L",letters:"LⓁＬĿĹĽḶḸĻḼḺŁȽⱢⱠꝈꝆꞀ"},{base:"LJ",letters:"Ǉ"},{base:"Lj",letters:"ǈ"},{base:"M",letters:"MⓂＭḾṀṂⱮƜ"},{base:"N",letters:"NⓃＮǸŃÑṄŇṆŅṊṈȠƝꞐꞤ"},{base:"NJ",letters:"Ǌ"},{base:"Nj",letters:"ǋ"},{base:"O",letters:"OⓄＯÒÓÔỒỐỖỔÕṌȬṎŌṐṒŎȮȰÖȪỎŐǑȌȎƠỜỚỠỞỢỌỘǪǬØǾƆƟꝊꝌ"},{base:"OI",letters:"Ƣ"},{base:"OO",letters:"Ꝏ"},{base:"OU",letters:"Ȣ"},{base:"OE",letters:"Œ"},{base:"oe",letters:"œ"},{base:"P",letters:"PⓅＰṔṖƤⱣꝐꝒꝔ"},{base:"Q",letters:"QⓆＱꝖꝘɊ"},{base:"R",letters:"RⓇＲŔṘŘȐȒṚṜŖṞɌⱤꝚꞦꞂ"},{base:"S",letters:"SⓈＳẞŚṤŜṠŠṦṢṨȘŞⱾꞨꞄ"},{base:"T",letters:"TⓉＴṪŤṬȚŢṰṮŦƬƮȾꞆ"},{base:"TZ",letters:"Ꜩ"},{base:"U",letters:"UⓊＵÙÚÛŨṸŪṺŬÜǛǗǕǙỦŮŰǓȔȖƯỪỨỮỬỰỤṲŲṶṴɄ"},{base:"V",letters:"VⓋＶṼṾƲꝞɅ"},{base:"VY",letters:"Ꝡ"},{base:"W",letters:"WⓌＷẀẂŴẆẄẈⱲ"},{base:"X",letters:"XⓍＸẊẌ"},{base:"Y",letters:"YⓎＹỲÝŶỸȲẎŸỶỴƳɎỾ"},{base:"Z",letters:"ZⓏＺŹẐŻŽẒẔƵȤⱿⱫꝢ"},{base:"a",letters:"aⓐａẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐ"},{base:"aa",letters:"ꜳ"},{base:"ae",letters:"æǽǣ"},{base:"ao",letters:"ꜵ"},{base:"au",letters:"ꜷ"},{base:"av",letters:"ꜹꜻ"},{base:"ay",letters:"ꜽ"},{base:"b",letters:"bⓑｂḃḅḇƀƃɓ"},{base:"c",letters:"cⓒｃćĉċčçḉƈȼꜿↄ"},{base:"d",letters:"dⓓｄḋďḍḑḓḏđƌɖɗꝺ"},{base:"dz",letters:"ǳǆ"},{base:"e",letters:"eⓔｅèéêềếễểẽēḕḗĕėëẻěȅȇẹệȩḝęḙḛɇɛǝ"},{base:"f",letters:"fⓕｆḟƒꝼ"},{base:"g",letters:"gⓖｇǵĝḡğġǧģǥɠꞡᵹꝿ"},{base:"h",letters:"hⓗｈĥḣḧȟḥḩḫẖħⱨⱶɥ"},{base:"hv",letters:"ƕ"},{base:"i",letters:"iⓘｉìíîĩīĭïḯỉǐȉȋịįḭɨı"},{base:"j",letters:"jⓙｊĵǰɉ"},{base:"k",letters:"kⓚｋḱǩḳķḵƙⱪꝁꝃꝅꞣ"},{base:"l",letters:"lⓛｌŀĺľḷḹļḽḻſłƚɫⱡꝉꞁꝇ"},{base:"lj",letters:"ǉ"},{base:"m",letters:"mⓜｍḿṁṃɱɯ"},{base:"n",letters:"nⓝｎǹńñṅňṇņṋṉƞɲŉꞑꞥ"},{base:"nj",letters:"ǌ"},{base:"o",letters:"oⓞｏòóôồốỗổõṍȭṏōṑṓŏȯȱöȫỏőǒȍȏơờớỡởợọộǫǭøǿɔꝋꝍɵ"},{base:"oi",letters:"ƣ"},{base:"ou",letters:"ȣ"},{base:"oo",letters:"ꝏ"},{base:"p",letters:"pⓟｐṕṗƥᵽꝑꝓꝕ"},{base:"q",letters:"qⓠｑɋꝗꝙ"},{base:"r",letters:"rⓡｒŕṙřȑȓṛṝŗṟɍɽꝛꞧꞃ"},{base:"s",letters:"sⓢｓßśṥŝṡšṧṣṩșşȿꞩꞅẛ"},{base:"t",letters:"tⓣｔṫẗťṭțţṱṯŧƭʈⱦꞇ"},{base:"tz",letters:"ꜩ"},{base:"u",letters:"uⓤｕùúûũṹūṻŭüǜǘǖǚủůűǔȕȗưừứữửựụṳųṷṵʉ"},{base:"v",letters:"vⓥｖṽṿʋꝟʌ"},{base:"vy",letters:"ꝡ"},{base:"w",letters:"wⓦｗẁẃŵẇẅẘẉⱳ"},{base:"x",letters:"xⓧｘẋẍ"},{base:"y",letters:"yⓨｙỳýŷỹȳẏÿỷẙỵƴɏỿ"},{base:"z",letters:"zⓩｚźẑżžẓẕƶȥɀⱬꝣ"}],c={},d=0;d<b.length;d++)for(var e=b[d].letters.split(""),f=0;f<e.length;f++)c[e[f]]=b[d].base;return function(b){return B(b)?a(b):b}}]),b.module("a8m.ltrim",[]).filter("ltrim",function(){return function(a,b){var c=b||"\\s";return B(a)?a.replace(new RegExp("^"+c+"+"),""):a}}),b.module("a8m.match",[]).filter("match",function(){return function(a,b,c){var d=new RegExp(b,c);return B(a)?a.match(d):null}}),b.module("a8m.phoneUS",[]).filter("phoneUS",function(){return function(a){return a+="","("+a.slice(0,3)+") "+a.slice(3,6)+"-"+a.slice(6)}}),b.module("a8m.repeat",[]).filter("repeat",[function(){return function(a,b,c){var d=~~b;return B(a)&&d?w(a,--b,c||""):a}}]),b.module("a8m.rtrim",[]).filter("rtrim",function(){return function(a,b){var c=b||"\\s";return B(a)?a.replace(new RegExp(c+"+$"),""):a}}),b.module("a8m.slugify",[]).filter("slugify",[function(){return function(a,b){var c=z(b)?"-":b;return B(a)?a.toLowerCase().replace(/\s+/g,c):a}}]),b.module("a8m.split",[]).filter("split",function(){function a(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}return function(b,c,d){var f,g,h,i;return z(b)||!B(b)?null:(z(c)&&(c=""),isNaN(d)&&(d=0),f=new RegExp(a(c),"g"),g=b.match(f),e(g)||d>=g.length?[b]:0===d?b.split(c):(h=b.split(c),i=h.splice(0,d+1),h.unshift(i.join(c)),h))}}),b.module("a8m.starts-with",[]).filter("startsWith",function(){return function(a,b,c){var d=c||!1;return!B(a)||z(b)?a:(a=d?a:a.toLowerCase(),!a.indexOf(d?b:b.toLowerCase()))}}),b.module("a8m.stringular",[]).filter("stringular",function(){return function(a){var b=Array.prototype.slice.call(arguments,1);return a.replace(/{(\d+)}/g,function(a,c){return z(b[c])?a:b[c]})}}),b.module("a8m.strip-tags",[]).filter("stripTags",function(){return function(a){return B(a)?a.replace(/<\S[^><]*>/g,""):a}}),b.module("a8m.test",[]).filter("test",function(){return function(a,b,c){var d=new RegExp(b,c);return B(a)?d.test(a):a}}),b.module("a8m.trim",[]).filter("trim",function(){return function(a,b){var c=b||"\\s";return B(a)?a.replace(new RegExp("^"+c+"+|"+c+"+$","g"),""):a}}),b.module("a8m.truncate",[]).filter("truncate",function(){return function(a,b,c,d){return b=z(b)?a.length:b,d=d||!1,c=c||"",!B(a)||a.length<=b?a:a.substring(0,d?a.indexOf(" ",b)===-1?a.length:a.indexOf(" ",b):b)+c}}),b.module("a8m.ucfirst",[]).filter({ucfirst:x,titleize:x}),b.module("a8m.uri-component-encode",[]).filter("uriComponentEncode",["$window",function(a){return function(b){return B(b)?a.encodeURIComponent(b):b}}]),b.module("a8m.uri-encode",[]).filter("uriEncode",["$window",function(a){return function(b){return B(b)?a.encodeURI(b):b}}]),b.module("a8m.wrap",[]).filter("wrap",function(){return function(a,b,c){return B(a)&&y(b)?[b,a,c||b].join(""):a}}),b.module("a8m.filter-watcher",[]).provider("filterWatcher",function(){this.$get=["$window","$rootScope",function(a,b){function c(b,c){function d(){var b=[];return function(c,d){if(D(d)&&!e(d)){if(~b.indexOf(d))return"[Circular]";b.push(d)}return a==d?"$WINDOW":a.document==d?"$DOCUMENT":k(d)?"$SCOPE":d}}return[b,JSON.stringify(c,d())].join("#").replace(/"/g,"")}function d(a){var b=a.targetScope.$id;F(l[b],function(a){delete j[a]}),delete l[b]}function f(){m(function(){b.$$phase||(j={})},2e3)}function g(a,b){var c=a.$id;return z(l[c])&&(a.$on("$destroy",d),l[c]=[]),l[c].push(b)}function h(a,b){var d=c(a,b);return j[d]}function i(a,b,d,e){var h=c(a,b);return j[h]=e,k(d)?g(d,h):f(),e}var j={},l={},m=a.setTimeout;return{isMemoized:h,memoize:i}}]}),b.module("angular.filter",["a8m.ucfirst","a8m.uri-encode","a8m.uri-component-encode","a8m.slugify","a8m.latinize","a8m.strip-tags","a8m.stringular","a8m.truncate","a8m.starts-with","a8m.ends-with","a8m.wrap","a8m.trim","a8m.ltrim","a8m.rtrim","a8m.repeat","a8m.test","a8m.match","a8m.split","a8m.phoneUS","a8m.to-array","a8m.concat","a8m.contains","a8m.unique","a8m.is-empty","a8m.after","a8m.after-where","a8m.before","a8m.before-where","a8m.defaults","a8m.where","a8m.reverse","a8m.remove","a8m.remove-with","a8m.group-by","a8m.count-by","a8m.chunk-by","a8m.search-field","a8m.fuzzy-by","a8m.fuzzy","a8m.omit","a8m.pick","a8m.every","a8m.filter-by","a8m.xor","a8m.map","a8m.first","a8m.last","a8m.flatten","a8m.join","a8m.range","a8m.math.max","a8m.math.min","a8m.math.abs","a8m.math.percent","a8m.math.radix","a8m.math.sum","a8m.math.degrees","a8m.math.radians","a8m.math.byteFmt","a8m.math.kbFmt","a8m.math.shortFmt","a8m.angular","a8m.conditions","a8m.is-null","a8m.filter-watcher"])}(window,window.angular);
\ No newline at end of file
diff --git a/dist/angular-filter.zip b/dist/angular-filter.zip
index 7f18b4d..a6e75df 100644
Binary files a/dist/angular-filter.zip and b/dist/angular-filter.zip differ
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..4677447
--- /dev/null
+++ b/index.js
@@ -0,0 +1,2 @@
+require('./dist/angular-filter.js');
+module.exports = 'angular.filter';
diff --git a/package.json b/package.json
index 447d93a..d16a2ba 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,15 @@
 {
   "name": "angular-filter",
   "description": "Bunch of useful filters for angularJS(with no external dependencies!)",
-  "version": "0.5.8",
+  "version": "0.5.17",
   "filename": "angular-filter.min.js",
-  "main": "dist/angular-filter.min.js",
+  "main": "index.js",
+  "files": [
+    "dist/*.js",
+    "index.js",
+    "src"
+  ],
+  "browser": "index.js",
   "homepage": "https://github.com/a8m/angular-filter",
   "author": "Ariel Mashraki <ariel@mashraki.co.il>",
   "repository": {
@@ -26,9 +32,9 @@
     "angular": "*"
   },
   "devDependencies": {
-    "coveralls": "~2.11.1",
-    "grunt": "^0.4.1",
-    "grunt-bower": "*",
+    "coveralls": "^2.11.11",
+    "grunt": "^0.4.5",
+    "grunt-bower": "^0.21.2",
     "grunt-bower-task": "*",
     "grunt-cli": ">= 0.1.7",
     "grunt-contrib-concat": "*",
@@ -39,12 +45,14 @@
     "grunt-karma": "^0.12.0",
     "grunt-karma-coveralls": "~2.5.1",
     "grunt-zip": "*",
-    "karma": "^0.13.8",
+    "karma": "^0.13.22",
     "karma-chrome-launcher": "~0.1.2",
-    "karma-coverage": "~0.2.4",
+    "karma-coverage": "^0.2.7",
     "karma-firefox-launcher": "~0.1.3",
-    "karma-jasmine": "~0.1.5",
-    "karma-phantomjs-launcher": "~0.1.4"
+    "karma-jasmine": "^0.1.6",
+    "karma-phantomjs-launcher": "1.0.0",
+    "phantomjs": "^2.1.7",
+    "phantomjs-prebuilt": "^2.1.13"
   },
   "scripts": {
     "test": "grunt test --verbose"
diff --git a/src/_common.js b/src/_common.js
index 20de683..2141b89 100644
--- a/src/_common.js
+++ b/src/_common.js
@@ -60,15 +60,23 @@ function objectContains(partial, object) {
  * @returns {*}
  */
 function hasApproxPattern(word, pattern) {
-  if(pattern === '')
-    return word;
-
-  var index = word.indexOf(pattern.charAt(0));
-
-  if(index === -1)
-    return false;
-
-  return hasApproxPattern(word.substr(index+1), pattern.substr(1))
+  // cheaper version of indexOf; instead of creating each
+  // iteration new str.
+  function indexOf(word, p, c) {
+    var j = 0;
+    while ((p + j) <= word.length) {
+      if (word.charAt(p + j) == c) return j;
+      j++;
+    }
+    return -1;
+  }
+  var p = 0;
+  for (var i = 0; i <= pattern.length; i++) {
+    var index = indexOf(word, p, pattern.charAt(i));
+    if (index == -1) return false;
+    p += index + 1;
+  }
+  return true
 }
 
 /**
@@ -102,11 +110,10 @@ if (!String.prototype.contains) {
 /**
  * @param num {Number}
  * @param decimal {Number}
- * @param $math
  * @returns {Number}
  */
-function convertToDecimal(num, decimal, $math){
-  return $math.round(num * $math.pow(10,decimal)) / ($math.pow(10,decimal));
+function convertToDecimal(num, decimal){
+  return Math.round(num * Math.pow(10,decimal)) / (Math.pow(10, decimal));
 }
 
 /**
diff --git a/src/_filter/collection/contains.js b/src/_filter/collection/contains.js
index 2290422..d564b18 100644
--- a/src/_filter/collection/contains.js
+++ b/src/_filter/collection/contains.js
@@ -22,7 +22,7 @@ function containsFilter($parse) {
       }
 
       return collection.some(function(elm) {
-        return (isObject(elm) || isFunction(expression))
+        return ((isString(expression) && isObject(elm)) || isFunction(expression))
           ? $parse(expression)(elm)
           : elm === expression;
       });
diff --git a/src/_filter/collection/range.js b/src/_filter/collection/range.js
index dd99700..867926f 100644
--- a/src/_filter/collection/range.js
+++ b/src/_filter/collection/range.js
@@ -8,10 +8,13 @@
  */
 angular.module('a8m.range', [])
   .filter('range', function () {
-    return function (input, total) {
+    return function (input, total, start, increment, cb) {
+      start = start || 0;
+      increment = increment || 1;
       for (var i = 0; i < parseInt(total); i++) {
-        input.push(i);
+        var j = start + i * increment;
+        input.push(isFunction(cb) ? cb(j) : j);
       }
       return input;
-	  };
+    };
   });
\ No newline at end of file
diff --git a/src/_filter/math/abs.js b/src/_filter/math/abs.js
new file mode 100644
index 0000000..f9e6747
--- /dev/null
+++ b/src/_filter/math/abs.js
@@ -0,0 +1,14 @@
+/**
+ * @ngdoc filter
+ * @name abs
+ * @kind function
+ *
+ * @description
+ * Will return the absolute value of a number
+ */
+angular.module('a8m.math.abs', [])
+  .filter('abs', function () {
+    return function (input) {
+      return Math.abs(input);
+    }
+  });
diff --git a/src/_filter/math/byte-fmt.js b/src/_filter/math/byte-fmt.js
index f0d4a35..504dc4f 100644
--- a/src/_filter/math/byte-fmt.js
+++ b/src/_filter/math/byte-fmt.js
@@ -7,23 +7,20 @@
  * Convert bytes into appropriate display 
  * 1024 bytes => 1 KB
  */
-angular.module('a8m.math.byteFmt', ['a8m.math'])
-  .filter('byteFmt', ['$math', function ($math) {
+angular.module('a8m.math.byteFmt', [])
+  .filter('byteFmt', function () {
+    var compared = [{str: 'B', val: 1024}];
+    ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'].forEach(function(el, i) {
+      compared.push({str: el, val: compared[i].val * 1024 });
+    });
     return function (bytes, decimal) {
-
       if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
         isNumber(bytes) && isFinite(bytes)) {
-        if(bytes < 1024) { // within 1 KB so B
-          return convertToDecimal(bytes, decimal, $math) + ' B';
-        } else if(bytes < 1048576) { // within 1 MB so KB
-          return convertToDecimal((bytes / 1024), decimal, $math) + ' KB';
-        } else if(bytes < 1073741824){ // within 1 GB so MB
-          return convertToDecimal((bytes / 1048576), decimal, $math) + ' MB';
-        } else { // GB or more
-          return convertToDecimal((bytes / 1073741824), decimal, $math) + ' GB';
-        }
-
+        var i = 0;
+        while (i < compared.length-1 && bytes >= compared[i].val) i++;
+        bytes /= i > 0 ? compared[i-1].val : 1;
+        return convertToDecimal(bytes, decimal) + ' ' + compared[i].str;
       }
-      return "NaN";
+      return 'NaN';
     }
-  }]);
\ No newline at end of file
+  });
diff --git a/src/_filter/math/degrees.js b/src/_filter/math/degrees.js
index d8cff8b..0507013 100644
--- a/src/_filter/math/degrees.js
+++ b/src/_filter/math/degrees.js
@@ -6,20 +6,20 @@
  * @description
  * Convert angle from radians to degrees
  */
-angular.module('a8m.math.degrees', ['a8m.math'])
-  .filter('degrees', ['$math', function ($math) {
+angular.module('a8m.math.degrees', [])
+  .filter('degrees', function () {
     return function (radians, decimal) {
       // if decimal is not an integer greater than -1, we cannot do. quit with error "NaN"
       // if degrees is not a real number, we cannot do also. quit with error "NaN"
       if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
         isNumber(radians) && isFinite(radians)) {
-        var degrees = (radians * 180) / $math.PI;
-        return $math.round(degrees * $math.pow(10,decimal)) / ($math.pow(10,decimal));
+        var degrees = (radians * 180) / Math.PI;
+        return Math.round(degrees * Math.pow(10,decimal)) / (Math.pow(10,decimal));
       } else {
-        return "NaN";
+        return 'NaN';
       }
     }
-  }]);
+  });
 
  
  
\ No newline at end of file
diff --git a/src/_filter/math/kb-fmt.js b/src/_filter/math/kb-fmt.js
index 4fbfd44..96eb70b 100644
--- a/src/_filter/math/kb-fmt.js
+++ b/src/_filter/math/kb-fmt.js
@@ -7,20 +7,20 @@
  * Convert bytes into appropriate display 
  * 1024 kilobytes => 1 MB
  */
-angular.module('a8m.math.kbFmt', ['a8m.math'])
-  .filter('kbFmt', ['$math', function ($math) {
+angular.module('a8m.math.kbFmt', [])
+  .filter('kbFmt', function () {
+    var compared = [{str: 'KB', val: 1024}];
+    ['MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'].forEach(function(el, i) {
+      compared.push({str: el, val: compared[i].val * 1024 });
+    });
     return function (bytes, decimal) {
-
       if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
         isNumber(bytes) && isFinite(bytes)) {
-        if(bytes < 1024) { // within 1 MB so KB
-          return convertToDecimal(bytes, decimal, $math) + ' KB';
-        } else if(bytes < 1048576) { // within 1 GB so MB
-          return convertToDecimal((bytes / 1024), decimal, $math) + ' MB';
-        } else {
-          return convertToDecimal((bytes / 1048576), decimal, $math) + ' GB';
-        }
+        var i = 0;
+        while (i < compared.length-1 && bytes >= compared[i].val) i++;
+        bytes /= i > 0 ? compared[i-1].val : 1;
+        return convertToDecimal(bytes, decimal) + ' ' + compared[i].str;
       }
-      return "NaN";
+      return 'NaN';
     }
-  }]);
\ No newline at end of file
+  });
\ No newline at end of file
diff --git a/src/_filter/math/math.js b/src/_filter/math/math.js
deleted file mode 100644
index 091e750..0000000
--- a/src/_filter/math/math.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/**
- * @ngdoc module
- * @name math
- * @description
- * reference to global Math object
- */
-angular.module('a8m.math', [])
-  .factory('$math', ['$window', function ($window) {
-    return $window.Math;
-  }]);
diff --git a/src/_filter/math/max.js b/src/_filter/math/max.js
index c4946f8..32b9de2 100644
--- a/src/_filter/math/max.js
+++ b/src/_filter/math/max.js
@@ -7,15 +7,15 @@
  * Math.max will get an array and return the max value. if an expression
  * is provided, will return max value by expression.
  */
-angular.module('a8m.math.max', ['a8m.math'])
-  .filter('max', ['$math', '$parse', function ($math, $parse) {
+angular.module('a8m.math.max', [])
+  .filter('max', ['$parse', function ($parse) {
     return function (input, expression) {
 
       if(!isArray(input)) {
         return input;
       }
       return isUndefined(expression)
-        ? $math.max.apply($math, input)
+        ? Math.max.apply(Math, input)
         : input[indexByMax(input, expression)];
     };
 
@@ -29,6 +29,6 @@ angular.module('a8m.math.max', ['a8m.math'])
       var mappedArray = array.map(function(elm){
         return $parse(exp)(elm);
       });
-      return mappedArray.indexOf($math.max.apply($math, mappedArray));
+      return mappedArray.indexOf(Math.max.apply(Math, mappedArray));
     }
   }]);
\ No newline at end of file
diff --git a/src/_filter/math/min.js b/src/_filter/math/min.js
index b9f8334..807ff70 100644
--- a/src/_filter/math/min.js
+++ b/src/_filter/math/min.js
@@ -7,15 +7,15 @@
  * Math.min will get an array and return the min value. if an expression
  * is provided, will return min value by expression.
  */
-angular.module('a8m.math.min', ['a8m.math'])
-  .filter('min', ['$math', '$parse', function ($math, $parse) {
+angular.module('a8m.math.min', [])
+  .filter('min', ['$parse', function ($parse) {
     return function (input, expression) {
 
       if(!isArray(input)) {
         return input;
       }
       return isUndefined(expression)
-        ? $math.min.apply($math, input)
+        ? Math.min.apply(Math, input)
         : input[indexByMin(input, expression)];
     };
 
@@ -29,6 +29,6 @@ angular.module('a8m.math.min', ['a8m.math'])
       var mappedArray = array.map(function(elm){
         return $parse(exp)(elm);
       });
-      return mappedArray.indexOf($math.min.apply($math, mappedArray));
+      return mappedArray.indexOf(Math.min.apply(Math, mappedArray));
     }
   }]);
\ No newline at end of file
diff --git a/src/_filter/math/percent.js b/src/_filter/math/percent.js
index 329f256..f1778dd 100644
--- a/src/_filter/math/percent.js
+++ b/src/_filter/math/percent.js
@@ -6,18 +6,18 @@
  * @description
  * percentage between two numbers
  */
-angular.module('a8m.math.percent', ['a8m.math'])
-  .filter('percent', ['$math', '$window', function ($math, $window) {
+angular.module('a8m.math.percent', [])
+  .filter('percent', function () {
     return function (input, divided, round) {
 
-      var divider = isString(input) ? $window.Number(input) : input;
+      var divider = isString(input) ? Number(input) : input;
       divided = divided || 100;
       round = round || false;
 
-      if (!isNumber(divider) || $window.isNaN(divider)) return input;
+      if (!isNumber(divider) || isNaN(divider)) return input;
 
       return round
-        ? $math.round((divider / divided) * 100)
+        ? Math.round((divider / divided) * 100)
         : (divider / divided) * 100;
     }
-  }]);
+  });
diff --git a/src/_filter/math/radians.js b/src/_filter/math/radians.js
index 3133e05..e98f684 100644
--- a/src/_filter/math/radians.js
+++ b/src/_filter/math/radians.js
@@ -6,19 +6,19 @@
  * @description
  * Convert angle from degrees to radians
  */
-angular.module('a8m.math.radians', ['a8m.math'])
-  .filter('radians', ['$math', function ($math) {
+angular.module('a8m.math.radians', [])
+  .filter('radians', function() {
     return function (degrees, decimal) {
       // if decimal is not an integer greater than -1, we cannot do. quit with error "NaN"
       // if degrees is not a real number, we cannot do also. quit with error "NaN"
       if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
         isNumber(degrees) && isFinite(degrees)) {
         var radians = (degrees * 3.14159265359) / 180;
-        return $math.round(radians * $math.pow(10,decimal)) / ($math.pow(10,decimal));
+        return Math.round(radians * Math.pow(10,decimal)) / (Math.pow(10,decimal));
       }
-      return "NaN";
+      return 'NaN';
     }
-  }]);
+  });
 
  
  
\ No newline at end of file
diff --git a/src/_filter/math/short-fmt.js b/src/_filter/math/short-fmt.js
index ac481df..0377383 100644
--- a/src/_filter/math/short-fmt.js
+++ b/src/_filter/math/short-fmt.js
@@ -8,22 +8,22 @@
  * i.e: K for one thousand, M for Million, B for billion
  * e.g: number of users:235,221, decimal:1 => 235.2 K
  */
-angular.module('a8m.math.shortFmt', ['a8m.math'])
-  .filter('shortFmt', ['$math', function ($math) {
+angular.module('a8m.math.shortFmt', [])
+  .filter('shortFmt', function () {
     return function (number, decimal) {
       if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
         isNumber(number) && isFinite(number)){
         if(number < 1e3) {
-          return number;
+          return '' + number;  // Coerce to string
         } else if(number < 1e6) {
-          return convertToDecimal((number / 1e3), decimal, $math) + ' K';
+          return convertToDecimal((number / 1e3), decimal) + ' K';
         } else if(number < 1e9){
-          return convertToDecimal((number / 1e6), decimal, $math) + ' M';
+          return convertToDecimal((number / 1e6), decimal) + ' M';
         } else {
-          return convertToDecimal((number / 1e9), decimal, $math) + ' B';
+          return convertToDecimal((number / 1e9), decimal) + ' B';
         }
 
       }
-      return "NaN";
+      return 'NaN';
     }
-  }]);
\ No newline at end of file
+  });
\ No newline at end of file
diff --git a/src/_filter/string/phone-us.js b/src/_filter/string/phone-us.js
new file mode 100644
index 0000000..bef4f55
--- /dev/null
+++ b/src/_filter/string/phone-us.js
@@ -0,0 +1,16 @@
+/**
+ * @ngdoc filter
+ * @name phone-us
+ * @kind function
+ *
+ * @description
+ * format a string or a number into a us-style
+ * phone number in the form (***) ***-****
+ */
+angular.module('a8m.phoneUS', [])
+  .filter('phoneUS', function () {
+    return function(num) {
+      num += '';
+      return '(' + num.slice(0, 3) + ') ' + num.slice(3, 6) + '-' + num.slice(6);
+    }
+  });
diff --git a/src/_filter/string/split.js b/src/_filter/string/split.js
new file mode 100644
index 0000000..b5d5f39
--- /dev/null
+++ b/src/_filter/string/split.js
@@ -0,0 +1,40 @@
+/**
+ * @ngdoc filter
+ * @name split
+ * @kind function
+ *
+ * @description
+ * split a string by a provided delimiter (none '' by default) and skip first n-delimiters
+ */
+angular.module('a8m.split', [])
+  .filter('split', function () {
+    function escapeRegExp(str) {
+      return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+    }
+
+    return function (input, delimiter, skip) {
+      var _regexp, _matches, _splitted, _temp;
+
+      if (isUndefined(input) || !isString(input)) {
+        return null;
+      }
+      if (isUndefined(delimiter)) delimiter = '';
+      if (isNaN(skip)) skip = 0;
+
+      _regexp = new RegExp(escapeRegExp(delimiter), 'g');
+      _matches = input.match(_regexp);
+      
+      if (isNull(_matches) || skip >= _matches.length) {
+        return [input];
+      }
+
+      if (skip === 0) return input.split(delimiter);
+      
+      _splitted = input.split(delimiter);
+      _temp = _splitted.splice(0, skip + 1);
+      _splitted.unshift(_temp.join(delimiter));
+    
+      return _splitted;
+    };
+  })
+;
diff --git a/src/_filter/string/ucfirst.js b/src/_filter/string/ucfirst.js
index 2a40dc7..d81fa61 100644
--- a/src/_filter/string/ucfirst.js
+++ b/src/_filter/string/ucfirst.js
@@ -7,15 +7,20 @@
  * ucfirst
  */
 angular.module('a8m.ucfirst', [])
-  .filter('ucfirst', [function() {
-    return function(input) {
-      return isString(input)
-        ? input
-            .split(' ')
-            .map(function (ch) {
-              return ch.charAt(0).toUpperCase() + ch.substring(1);
-            })
-            .join(' ')
-        : input;
-    }
-  }]);
+  .filter({
+    ucfirst: ucfirstFilter,
+    titleize: ucfirstFilter
+  });
+
+function ucfirstFilter() {
+  return function (input) {
+    return isString(input)
+      ? input
+      .split(' ')
+      .map(function (ch) {
+        return ch.charAt(0).toUpperCase() + ch.substring(1);
+      })
+      .join(' ')
+      : input;
+  }
+}
diff --git a/src/filters.js b/src/filters.js
index 19f5ddb..7964080 100644
--- a/src/filters.js
+++ b/src/filters.js
@@ -24,6 +24,8 @@ angular.module('angular.filter', [
   'a8m.repeat',
   'a8m.test',
   'a8m.match',
+  'a8m.split',
+  'a8m.phoneUS',
 
   'a8m.to-array',
   'a8m.concat',
@@ -56,10 +58,10 @@ angular.module('angular.filter', [
   'a8m.flatten',
   'a8m.join',
   'a8m.range',
-  
-  'a8m.math',
+
   'a8m.math.max',
   'a8m.math.min',
+  'a8m.math.abs',
   'a8m.math.percent',
   'a8m.math.radix',
   'a8m.math.sum',
diff --git a/test/karma.conf.js b/test/karma.conf.js
index 7a46d09..bd94762 100644
--- a/test/karma.conf.js
+++ b/test/karma.conf.js
@@ -19,18 +19,19 @@ module.exports = function(config) {
     reporters: ['coverage'],
     //files to coverage
     preprocessors: {
-      "src/**/*js": "coverage"
+      "src/**/*js": 'coverage'
     },
 
     coverageReporter: {
-      type: "lcov",
-      dir: "test/coverage/"
+      type: 'lcov',
+      dir: 'test/coverage/'
     },
 
     // list of files / patterns to load in the browser
     files: [
       'bower_components/angular/angular.js',
       'bower_components/angular-mocks/angular-mocks.js',
+      'src/*.js',
       'src/**/*.js',
       'src/**/**/*.js',
       'test/spec/**/*.js',
@@ -41,7 +42,11 @@ module.exports = function(config) {
     exclude: [],
 
     // web server port
-    port: 8080,
+    port: 9876,
+
+
+    // cli runner port
+    runnerPort: 9100,
 
     // Start these browsers, currently available:
     // - Chrome
@@ -72,11 +77,12 @@ module.exports = function(config) {
     // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
     logLevel: config.LOG_INFO,
 
-    // Uncomment the following lines if you are using grunt's server to run the tests
-    // proxies: {
-    //   '/': 'http://localhost:9000/'
-    // },
-    // URL root prevent conflicts with the site root
-    // urlRoot: '_karma_'
+    // If browser does not capture in given timeout [ms], kill it
+    captureTimeout: 60000,
+
+    phantomjsLauncher: {
+      // Have phantomjs exit if a ResourceError is encountered (useful if karma exits without killing phantom)
+      exitOnResourceError: true
+    }
   });
 };
diff --git a/test/spec/filter/collection/contains.js b/test/spec/filter/collection/contains.js
index 10d03e9..55457cf 100644
--- a/test/spec/filter/collection/contains.js
+++ b/test/spec/filter/collection/contains.js
@@ -8,6 +8,13 @@ describe('containsFilter', function() {
   beforeEach(inject(function ($filter) {
     filter = $filter('contains');
   }));
+  
+  it('should find elements which are objects', function() {
+    var needle = {};
+    var haystack = [needle];
+    
+    expect(filter(haystack, needle)).toBeTruthy();
+  });
 
   it('should get collection of primitives and use strict comparison(===)', function() {
     expect(filter(['foo', 'bar'], 'bar')).toBeTruthy();
diff --git a/test/spec/filter/collection/range.js b/test/spec/filter/collection/range.js
index b50678d..b1f33ec 100644
--- a/test/spec/filter/collection/range.js
+++ b/test/spec/filter/collection/range.js
@@ -12,4 +12,21 @@ describe('rangeFilter', function() {
     expect(filter([], 10)).toEqual([0,1,2,3,4,5,6,7,8,9]);
     expect(filter([], 10).length).toEqual(10);
   });
+
+  it('should return 10 items starting at 10 incrementing by 1', function() {
+    expect(filter([], 10, 10)).toEqual([10,11,12,13,14,15,16,17,18,19]);
+    expect(filter([], 10).length).toEqual(10);
+  });
+
+  it('should return 10 items starting at 10 incrementing by 10 ', function() {
+    expect(filter([], 10, 10, 10)).toEqual([10,20,30,40,50,60,70,80,90,100]);
+    expect(filter([], 10).length).toEqual(10);
+  });
+
+  it('should return 10 items starting at 10 incrementing by 10 and multiplied by 2.', function() {
+    expect(filter([], 10, 10, 10, function(n) { return 2 * n; }))
+      .toEqual([20,40,60,80,100,120,140,160,180,200]);
+    expect(filter([], 10).length).toEqual(10);
+  });
+
 });
\ No newline at end of file
diff --git a/test/spec/filter/math/abs.js b/test/spec/filter/math/abs.js
new file mode 100644
index 0000000..fbb72b1
--- /dev/null
+++ b/test/spec/filter/math/abs.js
@@ -0,0 +1,19 @@
+'use strict';
+
+describe('absFilter', function () {
+
+  var filter;
+
+  beforeEach(module('a8m.math.abs'));
+
+  beforeEach(inject(function ($filter) {
+    filter = $filter('abs');
+  }));
+
+  it('should return absolute values of any numbers inputted', function() {
+    expect(filter(-123.45)).toEqual(123.45);
+    expect(filter(123.45)).toEqual(123.45);
+    expect(filter('-123.45')).toEqual(123.45);
+    expect(filter('123.45')).toEqual(123.45);
+  });
+});
diff --git a/test/spec/filter/math/byte-fmt.js b/test/spec/filter/math/byte-fmt.js
index dbc51b9..e286377 100644
--- a/test/spec/filter/math/byte-fmt.js
+++ b/test/spec/filter/math/byte-fmt.js
@@ -18,8 +18,12 @@ describe('byteFmtFilter', function () {
     expect(filter(1049901,5)).toEqual("1.00126 MB"); 
     expect(filter(909234901,1)).toEqual("867.1 MB"); 
     expect(filter(1339234901,5)).toEqual("1.24726 GB"); 
-    expect(filter(23423234234,2)).toEqual("21.81 GB"); 
-
+    expect(filter(23423234234,2)).toEqual("21.81 GB");
+    expect(filter(23985391855616,2)).toEqual("21.81 TB");
+    expect(filter(95340189555097611,1)).toEqual("84.7 PB");
+    expect(filter(2249548013871562752,3)).toEqual("1.951 EB");
+    expect(filter(5180591620717411303425,2)).toEqual("4.39 ZB");
+    expect(filter(5123980591620717411303425,2)).toEqual("4.24 YB");
   });
 
   it('should return NaN if bytes is not a number', function(){
diff --git a/test/spec/filter/math/kb-fmt.js b/test/spec/filter/math/kb-fmt.js
index 767cea1..ba56915 100644
--- a/test/spec/filter/math/kb-fmt.js
+++ b/test/spec/filter/math/kb-fmt.js
@@ -16,8 +16,14 @@ describe('kbFmtFilter', function () {
     expect(filter(1024,0)).toEqual("1 MB");
     expect(filter(1998,2)).toEqual("1.95 MB");
     expect(filter(1049901,5)).toEqual("1.00126 GB"); 
-    expect(filter(909234901,1)).toEqual("867.1 GB");  
-    
+    expect(filter(909234901,1)).toEqual("867.1 GB");
+    expect(filter(1339234901,5)).toEqual("1.24726 TB");
+    expect(filter(23423234234,2)).toEqual("21.81 TB");
+    expect(filter(23985391855616,2)).toEqual("21.81 PB");
+    expect(filter(95340189555097611,1)).toEqual("84.7 EB");
+    expect(filter(2249548013871562752,3)).toEqual("1.951 ZB");
+    expect(filter(5180591620717411303425,2)).toEqual("4.39 YB");
+    expect(filter(5123980591620717411303425,2)).toEqual("4340.18 YB");
   });
   
   it('should return NaN if kilobytes is not a number', function(){
diff --git a/test/spec/filter/math/math.js b/test/spec/filter/math/math.js
deleted file mode 100644
index 5ebb031..0000000
--- a/test/spec/filter/math/math.js
+++ /dev/null
@@ -1,19 +0,0 @@
-'use strict';
-
-describe('$mathFactory', function () {
-
-  var $math,
-    $window;
-
-  beforeEach(module('a8m.math'));
-
-  beforeEach(inject(function (_$math_, _$window_) {
-    $math = _$math_;
-    $window = _$window_;
-  }));
-
-  it('should return a reference to global Math Object', function() {
-    expect($math).toEqual($window.Math);
-  });
-
-});
diff --git a/test/spec/filter/math/short-fmt.js b/test/spec/filter/math/short-fmt.js
index 3308a8c..96217d7 100644
--- a/test/spec/filter/math/short-fmt.js
+++ b/test/spec/filter/math/short-fmt.js
@@ -11,8 +11,8 @@ describe('shortFmtFilter', function () {
   }));
 
   it('should return the correct display from the number', function() {
-    expect(filter(0,2)).toEqual(0);
-    expect(filter(5,2)).toEqual(5);
+    expect(filter(0,2)).toEqual('0');
+    expect(filter(5,2)).toEqual('5');
     expect(filter(1024,0)).toEqual("1 K");
     expect(filter(1993,2)).toEqual("1.99 K");
     expect(filter(1049901,5)).toEqual("1.0499 M"); 
@@ -21,18 +21,18 @@ describe('shortFmtFilter', function () {
   });
   
   it('should return NaN if bytes is not a number', function(){
-	expect(filter("0",2)).toEqual("NaN");
-	expect(filter([0],2)).toEqual("NaN");
-	expect(filter({number:0},0)).toEqual("NaN");
+	  expect(filter("0",2)).toEqual("NaN");
+	  expect(filter([0],2)).toEqual("NaN");
+	  expect(filter({number:0},0)).toEqual("NaN");
   });
   
   it('should return NaN if decimal point is less than zero or not a number', function(){
-	expect(filter(0.45,-1)).toEqual("NaN");
-	expect(filter(-0.25,-101)).toEqual("NaN");
-	expect(filter(0.45,1.3)).toEqual("NaN");
-	expect(filter(0.45,"0")).toEqual("NaN");
-	expect(filter(0.45,[3])).toEqual("NaN");
-	expect(filter(0.45,{num : 4})).toEqual("NaN");	
+    expect(filter(0.45,-1)).toEqual("NaN");
+	  expect(filter(-0.25,-101)).toEqual("NaN");
+	  expect(filter(0.45,1.3)).toEqual("NaN");
+	  expect(filter(0.45,"0")).toEqual("NaN");
+	  expect(filter(0.45,[3])).toEqual("NaN");
+	  expect(filter(0.45,{num : 4})).toEqual("NaN");	
   });
   
 });
diff --git a/test/spec/filter/string/phone-us.js b/test/spec/filter/string/phone-us.js
new file mode 100644
index 0000000..fa9adee
--- /dev/null
+++ b/test/spec/filter/string/phone-us.js
@@ -0,0 +1,21 @@
+'use strict';
+
+describe('phoneUSFilter', function () {
+
+  var filter;
+
+  beforeEach(module('a8m.phoneUS'));
+
+  beforeEach(inject(function ($filter) {
+    filter = $filter('phoneUS');
+  }));
+
+  it('should format a number as a US-style phone number', function () {
+    expect(filter(1234567890)).toEqual('(123) 456-7890');
+  });
+
+  it('should format a string as a US-style phone number', function () {
+    expect(filter('1234567890')).toEqual('(123) 456-7890');
+  });
+
+});
diff --git a/test/spec/filter/string/split.js b/test/spec/filter/string/split.js
new file mode 100644
index 0000000..c0c05be
--- /dev/null
+++ b/test/spec/filter/string/split.js
@@ -0,0 +1,28 @@
+'use strict';
+
+describe('splitFilter', function () {
+
+  var filter, sentence = "Today is a beautiful and sunny day!";
+
+  beforeEach(module('a8m.split'));
+
+  beforeEach(inject(function ($filter) {
+    filter = $filter('split');
+  }));
+
+  it('should test a string with given pattern', function() {
+
+    expect(filter(sentence, ' ', 3)).toEqual(['Today is a beautiful', 'and', 'sunny', 'day!']);
+    expect(angular.equals(filter(sentence, '.'), [sentence])).toBeTruthy();
+    expect(filter(sentence, ' ')).toEqual(['Today', 'is', 'a', 'beautiful', 'and', 'sunny', 'day!']);
+
+  });
+
+  it('should get a !string and return null', function() {
+    expect(filter({})).toEqual(null);
+    expect(filter([])).toEqual(null);
+    expect(filter(1)).toEqual(null);
+    expect(filter(!1)).toBeFalsy(null);
+  });
+
+});
