61 | * ```
62 | *
63 | * ## Reusing and Overriding Messages
64 | * In addition to prioritization, ngMessages also allows for including messages from a remote or an inline
65 | * template. This allows for generic collection of messages to be reused across multiple parts of an
66 | * application.
67 | *
68 | * ```html
69 | *
73 | *
74 | * ```
75 | *
76 | * However, including generic messages may not be useful enough to match all input fields, therefore,
77 | * `ngMessages` provides the ability to override messages defined in the remote template by redefining
78 | * then within the directive container.
79 | *
80 | * ```html
81 | *
82 | *
86 | *
87 | *
103 | * ```
104 | *
105 | * In the example HTML code above the message that is set on required will override the corresponding
106 | * required message defined within the remote template. Therefore, with particular input fields (such
107 | * email addresses, date fields, autocomplete inputs, etc...), specialized error messages can be applied
108 | * while more generic messages can be used to handle other, more general input errors.
109 | *
110 | * ## Animations
111 | * If the `ngAnimate` module is active within the application then both the `ngMessages` and
112 | * `ngMessage` directives will trigger animations whenever any messages are added and removed
113 | * from the DOM by the `ngMessages` directive.
114 | *
115 | * Whenever the `ngMessages` directive contains one or more visible messages then the `.ng-active` CSS
116 | * class will be added to the element. The `.ng-inactive` CSS class will be applied when there are no
117 | * animations present. Therefore, CSS transitions and keyframes as well as JavaScript animations can
118 | * hook into the animations whenever these classes are added/removed.
119 | *
120 | * Let's say that our HTML code for our messages container looks like so:
121 | *
122 | * ```html
123 | *
124 | *
...
125 | *
...
126 | *
127 | * ```
128 | *
129 | * Then the CSS animation code for the message container looks like so:
130 | *
131 | * ```css
132 | * .my-messages {
133 | * transition:1s linear all;
134 | * }
135 | * .my-messages.ng-active {
136 | * // messages are visible
137 | * }
138 | * .my-messages.ng-inactive {
139 | * // messages are hidden
140 | * }
141 | * ```
142 | *
143 | * Whenever an inner message is attached (becomes visible) or removed (becomes hidden) then the enter
144 | * and leave animation is triggered for each particular element bound to the `ngMessage` directive.
145 | *
146 | * Therefore, the CSS code for the inner messages looks like so:
147 | *
148 | * ```css
149 | * .some-message {
150 | * transition:1s linear all;
151 | * }
152 | *
153 | * .some-message.ng-enter {}
154 | * .some-message.ng-enter.ng-enter-active {}
155 | *
156 | * .some-message.ng-leave {}
157 | * .some-message.ng-leave.ng-leave-active {}
158 | * ```
159 | *
160 | * {@link ngAnimate Click here} to learn how to use JavaScript animations or to learn more about ngAnimate.
161 | */
162 | angular.module('ngMessages', [])
163 |
164 | /**
165 | * @ngdoc directive
166 | * @module ngMessages
167 | * @name ngMessages
168 | * @restrict AE
169 | *
170 | * @description
171 | * `ngMessages` is a directive that is designed to show and hide messages based on the state
172 | * of a key/value object that is listens on. The directive itself compliments error message
173 | * reporting with the `ngModel` $error object (which stores a key/value state of validation errors).
174 | *
175 | * `ngMessages` manages the state of internal messages within its container element. The internal
176 | * messages use the `ngMessage` directive and will be inserted/removed from the page depending
177 | * on if they're present within the key/value object. By default, only one message will be displayed
178 | * at a time and this depends on the prioritization of the messages within the template. (This can
179 | * be changed by using the ng-messages-multiple on the directive container.)
180 | *
181 | * A remote template can also be used to promote message reuseability and messages can also be
182 | * overridden.
183 | *
184 | * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
185 | *
186 | * @usage
187 | * ```html
188 | *
189 | *
190 | * ...
191 | * ...
192 | * ...
193 | *
194 | *
195 | *
196 | *
197 | * ...
198 | * ...
199 | * ...
200 | *
201 | * ```
202 | *
203 | * @param {string} ngMessages an angular expression evaluating to a key/value object
204 | * (this is typically the $error object on an ngModel instance).
205 | * @param {string=} ngMessagesMultiple|multiple when set, all messages will be displayed with true
206 | * @param {string=} ngMessagesInclude|include when set, the specified template will be included into the ng-messages container
207 | *
208 | * @example
209 | *
212 | *
213 | *
230 | *
231 | *
232 | * angular.module('ngMessagesExample', ['ngMessages']);
233 | *
234 | *
235 | */
236 | .directive('ngMessages', ['$compile', '$animate', '$http', '$templateCache',
237 | function($compile, $animate, $http, $templateCache) {
238 | var ACTIVE_CLASS = 'ng-active';
239 | var INACTIVE_CLASS = 'ng-inactive';
240 |
241 | return {
242 | restrict: 'AE',
243 | controller: ['$scope', function($scope) {
244 | this.$renderNgMessageClasses = angular.noop;
245 |
246 | var messages = [];
247 | this.registerMessage = function(index, message) {
248 | for(var i = 0; i < messages.length; i++) {
249 | if(messages[i].type == message.type) {
250 | if(index != i) {
251 | var temp = messages[index];
252 | messages[index] = messages[i];
253 | if(index < messages.length) {
254 | messages[i] = temp;
255 | } else {
256 | messages.splice(0, i); //remove the old one (and shift left)
257 | }
258 | }
259 | return;
260 | }
261 | }
262 | messages.splice(index, 0, message); //add the new one (and shift right)
263 | };
264 |
265 | this.renderMessages = function(values, multiple) {
266 | values = values || {};
267 |
268 | var found;
269 | angular.forEach(messages, function(message) {
270 | if((!found || multiple) && truthyVal(values[message.type])) {
271 | message.attach();
272 | found = true;
273 | } else {
274 | message.detach();
275 | }
276 | });
277 |
278 | this.renderElementClasses(found);
279 |
280 | function truthyVal(value) {
281 | return value !== null && value !== false && value;
282 | }
283 | };
284 | }],
285 | require: 'ngMessages',
286 | link: function($scope, element, $attrs, ctrl) {
287 | ctrl.renderElementClasses = function(bool) {
288 | bool ? $animate.setClass(element, ACTIVE_CLASS, INACTIVE_CLASS)
289 | : $animate.setClass(element, INACTIVE_CLASS, ACTIVE_CLASS);
290 | };
291 |
292 | //JavaScript treats empty strings as false, but ng-message-multiple by itself is an empty string
293 | var multiple = angular.isString($attrs.ngMessagesMultiple) ||
294 | angular.isString($attrs.multiple);
295 |
296 | var cachedValues, watchAttr = $attrs.ngMessages || $attrs['for']; //for is a reserved keyword
297 | $scope.$watchCollection(watchAttr, function(values) {
298 | cachedValues = values;
299 | ctrl.renderMessages(values, multiple);
300 | });
301 |
302 | var tpl = $attrs.ngMessagesInclude || $attrs.include;
303 | if(tpl) {
304 | $http.get(tpl, { cache: $templateCache })
305 | .success(function processTemplate(html) {
306 | var after, container = angular.element('').html(html);
307 | angular.forEach(container.children(), function(elm) {
308 | elm = angular.element(elm);
309 | after ? after.after(elm)
310 | : element.prepend(elm); //start of the container
311 | after = elm;
312 | $compile(elm)($scope);
313 | });
314 | ctrl.renderMessages(cachedValues, multiple);
315 | });
316 | }
317 | }
318 | };
319 | }])
320 |
321 |
322 | /**
323 | * @ngdoc directive
324 | * @name ngMessage
325 | * @restrict AE
326 | * @scope
327 | *
328 | * @description
329 | * `ngMessage` is a directive with the purpose to show and hide a particular message.
330 | * For `ngMessage` to operate, a parent `ngMessages` directive on a parent DOM element
331 | * must be situated since it determines which messages are visible based on the state
332 | * of the provided key/value map that `ngMessages` listens on.
333 | *
334 | * @usage
335 | * ```html
336 | *
337 | *
338 | * ...
339 | * ...
340 | * ...
341 | *
342 | *
343 | *
344 | *
345 | * ...
346 | * ...
347 | * ...
348 | *
349 | * ```
350 | *
351 | * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
352 | *
353 | * @param {string} ngMessage a string value corresponding to the message key.
354 | */
355 | .directive('ngMessage', ['$animate', function($animate) {
356 | var COMMENT_NODE = 8;
357 | return {
358 | require: '^ngMessages',
359 | transclude: 'element',
360 | terminal: true,
361 | restrict: 'AE',
362 | link: function($scope, $element, $attrs, ngMessages, $transclude) {
363 | var index, element;
364 |
365 | var commentNode = $element[0];
366 | var parentNode = commentNode.parentNode;
367 | for(var i = 0, j = 0; i < parentNode.childNodes.length; i++) {
368 | var node = parentNode.childNodes[i];
369 | if(node.nodeType == COMMENT_NODE && node.nodeValue.indexOf('ngMessage') >= 0) {
370 | if(node === commentNode) {
371 | index = j;
372 | break;
373 | }
374 | j++;
375 | }
376 | }
377 |
378 | ngMessages.registerMessage(index, {
379 | type : $attrs.ngMessage || $attrs.when,
380 | attach : function() {
381 | if(!element) {
382 | $transclude($scope, function(clone) {
383 | $animate.enter(clone, null, $element);
384 | element = clone;
385 | });
386 | }
387 | },
388 | detach : function(now) {
389 | if(element) {
390 | $animate.leave(element);
391 | element = null;
392 | }
393 | }
394 | });
395 | }
396 | };
397 | }]);
398 |
399 |
400 | })(window, window.angular);
401 |
--------------------------------------------------------------------------------
/frontend/vendor/js/underscore.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.6.0
2 | // http://underscorejs.org
3 | // (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
4 | // Underscore may be freely distributed under the MIT license.
5 |
6 | (function() {
7 |
8 | // Baseline setup
9 | // --------------
10 |
11 | // Establish the root object, `window` in the browser, or `exports` on the server.
12 | var root = this;
13 |
14 | // Save the previous value of the `_` variable.
15 | var previousUnderscore = root._;
16 |
17 | // Establish the object that gets returned to break out of a loop iteration.
18 | var breaker = {};
19 |
20 | // Save bytes in the minified (but not gzipped) version:
21 | var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
22 |
23 | // Create quick reference variables for speed access to core prototypes.
24 | var
25 | push = ArrayProto.push,
26 | slice = ArrayProto.slice,
27 | concat = ArrayProto.concat,
28 | toString = ObjProto.toString,
29 | hasOwnProperty = ObjProto.hasOwnProperty;
30 |
31 | // All **ECMAScript 5** native function implementations that we hope to use
32 | // are declared here.
33 | var
34 | nativeForEach = ArrayProto.forEach,
35 | nativeMap = ArrayProto.map,
36 | nativeReduce = ArrayProto.reduce,
37 | nativeReduceRight = ArrayProto.reduceRight,
38 | nativeFilter = ArrayProto.filter,
39 | nativeEvery = ArrayProto.every,
40 | nativeSome = ArrayProto.some,
41 | nativeIndexOf = ArrayProto.indexOf,
42 | nativeLastIndexOf = ArrayProto.lastIndexOf,
43 | nativeIsArray = Array.isArray,
44 | nativeKeys = Object.keys,
45 | nativeBind = FuncProto.bind;
46 |
47 | // Create a safe reference to the Underscore object for use below.
48 | var _ = function(obj) {
49 | if (obj instanceof _) return obj;
50 | if (!(this instanceof _)) return new _(obj);
51 | this._wrapped = obj;
52 | };
53 |
54 | // Export the Underscore object for **Node.js**, with
55 | // backwards-compatibility for the old `require()` API. If we're in
56 | // the browser, add `_` as a global object via a string identifier,
57 | // for Closure Compiler "advanced" mode.
58 | if (typeof exports !== 'undefined') {
59 | if (typeof module !== 'undefined' && module.exports) {
60 | exports = module.exports = _;
61 | }
62 | exports._ = _;
63 | } else {
64 | root._ = _;
65 | }
66 |
67 | // Current version.
68 | _.VERSION = '1.6.0';
69 |
70 | // Collection Functions
71 | // --------------------
72 |
73 | // The cornerstone, an `each` implementation, aka `forEach`.
74 | // Handles objects with the built-in `forEach`, arrays, and raw objects.
75 | // Delegates to **ECMAScript 5**'s native `forEach` if available.
76 | var each = _.each = _.forEach = function(obj, iterator, context) {
77 | if (obj == null) return obj;
78 | if (nativeForEach && obj.forEach === nativeForEach) {
79 | obj.forEach(iterator, context);
80 | } else if (obj.length === +obj.length) {
81 | for (var i = 0, length = obj.length; i < length; i++) {
82 | if (iterator.call(context, obj[i], i, obj) === breaker) return;
83 | }
84 | } else {
85 | var keys = _.keys(obj);
86 | for (var i = 0, length = keys.length; i < length; i++) {
87 | if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
88 | }
89 | }
90 | return obj;
91 | };
92 |
93 | // Return the results of applying the iterator to each element.
94 | // Delegates to **ECMAScript 5**'s native `map` if available.
95 | _.map = _.collect = function(obj, iterator, context) {
96 | var results = [];
97 | if (obj == null) return results;
98 | if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
99 | each(obj, function(value, index, list) {
100 | results.push(iterator.call(context, value, index, list));
101 | });
102 | return results;
103 | };
104 |
105 | var reduceError = 'Reduce of empty array with no initial value';
106 |
107 | // **Reduce** builds up a single result from a list of values, aka `inject`,
108 | // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
109 | _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
110 | var initial = arguments.length > 2;
111 | if (obj == null) obj = [];
112 | if (nativeReduce && obj.reduce === nativeReduce) {
113 | if (context) iterator = _.bind(iterator, context);
114 | return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
115 | }
116 | each(obj, function(value, index, list) {
117 | if (!initial) {
118 | memo = value;
119 | initial = true;
120 | } else {
121 | memo = iterator.call(context, memo, value, index, list);
122 | }
123 | });
124 | if (!initial) throw new TypeError(reduceError);
125 | return memo;
126 | };
127 |
128 | // The right-associative version of reduce, also known as `foldr`.
129 | // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
130 | _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
131 | var initial = arguments.length > 2;
132 | if (obj == null) obj = [];
133 | if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
134 | if (context) iterator = _.bind(iterator, context);
135 | return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
136 | }
137 | var length = obj.length;
138 | if (length !== +length) {
139 | var keys = _.keys(obj);
140 | length = keys.length;
141 | }
142 | each(obj, function(value, index, list) {
143 | index = keys ? keys[--length] : --length;
144 | if (!initial) {
145 | memo = obj[index];
146 | initial = true;
147 | } else {
148 | memo = iterator.call(context, memo, obj[index], index, list);
149 | }
150 | });
151 | if (!initial) throw new TypeError(reduceError);
152 | return memo;
153 | };
154 |
155 | // Return the first value which passes a truth test. Aliased as `detect`.
156 | _.find = _.detect = function(obj, predicate, context) {
157 | var result;
158 | any(obj, function(value, index, list) {
159 | if (predicate.call(context, value, index, list)) {
160 | result = value;
161 | return true;
162 | }
163 | });
164 | return result;
165 | };
166 |
167 | // Return all the elements that pass a truth test.
168 | // Delegates to **ECMAScript 5**'s native `filter` if available.
169 | // Aliased as `select`.
170 | _.filter = _.select = function(obj, predicate, context) {
171 | var results = [];
172 | if (obj == null) return results;
173 | if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);
174 | each(obj, function(value, index, list) {
175 | if (predicate.call(context, value, index, list)) results.push(value);
176 | });
177 | return results;
178 | };
179 |
180 | // Return all the elements for which a truth test fails.
181 | _.reject = function(obj, predicate, context) {
182 | return _.filter(obj, function(value, index, list) {
183 | return !predicate.call(context, value, index, list);
184 | }, context);
185 | };
186 |
187 | // Determine whether all of the elements match a truth test.
188 | // Delegates to **ECMAScript 5**'s native `every` if available.
189 | // Aliased as `all`.
190 | _.every = _.all = function(obj, predicate, context) {
191 | predicate || (predicate = _.identity);
192 | var result = true;
193 | if (obj == null) return result;
194 | if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context);
195 | each(obj, function(value, index, list) {
196 | if (!(result = result && predicate.call(context, value, index, list))) return breaker;
197 | });
198 | return !!result;
199 | };
200 |
201 | // Determine if at least one element in the object matches a truth test.
202 | // Delegates to **ECMAScript 5**'s native `some` if available.
203 | // Aliased as `any`.
204 | var any = _.some = _.any = function(obj, predicate, context) {
205 | predicate || (predicate = _.identity);
206 | var result = false;
207 | if (obj == null) return result;
208 | if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);
209 | each(obj, function(value, index, list) {
210 | if (result || (result = predicate.call(context, value, index, list))) return breaker;
211 | });
212 | return !!result;
213 | };
214 |
215 | // Determine if the array or object contains a given value (using `===`).
216 | // Aliased as `include`.
217 | _.contains = _.include = function(obj, target) {
218 | if (obj == null) return false;
219 | if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
220 | return any(obj, function(value) {
221 | return value === target;
222 | });
223 | };
224 |
225 | // Invoke a method (with arguments) on every item in a collection.
226 | _.invoke = function(obj, method) {
227 | var args = slice.call(arguments, 2);
228 | var isFunc = _.isFunction(method);
229 | return _.map(obj, function(value) {
230 | return (isFunc ? method : value[method]).apply(value, args);
231 | });
232 | };
233 |
234 | // Convenience version of a common use case of `map`: fetching a property.
235 | _.pluck = function(obj, key) {
236 | return _.map(obj, _.property(key));
237 | };
238 |
239 | // Convenience version of a common use case of `filter`: selecting only objects
240 | // containing specific `key:value` pairs.
241 | _.where = function(obj, attrs) {
242 | return _.filter(obj, _.matches(attrs));
243 | };
244 |
245 | // Convenience version of a common use case of `find`: getting the first object
246 | // containing specific `key:value` pairs.
247 | _.findWhere = function(obj, attrs) {
248 | return _.find(obj, _.matches(attrs));
249 | };
250 |
251 | // Return the maximum element or (element-based computation).
252 | // Can't optimize arrays of integers longer than 65,535 elements.
253 | // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
254 | _.max = function(obj, iterator, context) {
255 | if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
256 | return Math.max.apply(Math, obj);
257 | }
258 | var result = -Infinity, lastComputed = -Infinity;
259 | each(obj, function(value, index, list) {
260 | var computed = iterator ? iterator.call(context, value, index, list) : value;
261 | if (computed > lastComputed) {
262 | result = value;
263 | lastComputed = computed;
264 | }
265 | });
266 | return result;
267 | };
268 |
269 | // Return the minimum element (or element-based computation).
270 | _.min = function(obj, iterator, context) {
271 | if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
272 | return Math.min.apply(Math, obj);
273 | }
274 | var result = Infinity, lastComputed = Infinity;
275 | each(obj, function(value, index, list) {
276 | var computed = iterator ? iterator.call(context, value, index, list) : value;
277 | if (computed < lastComputed) {
278 | result = value;
279 | lastComputed = computed;
280 | }
281 | });
282 | return result;
283 | };
284 |
285 | // Shuffle an array, using the modern version of the
286 | // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
287 | _.shuffle = function(obj) {
288 | var rand;
289 | var index = 0;
290 | var shuffled = [];
291 | each(obj, function(value) {
292 | rand = _.random(index++);
293 | shuffled[index - 1] = shuffled[rand];
294 | shuffled[rand] = value;
295 | });
296 | return shuffled;
297 | };
298 |
299 | // Sample **n** random values from a collection.
300 | // If **n** is not specified, returns a single random element.
301 | // The internal `guard` argument allows it to work with `map`.
302 | _.sample = function(obj, n, guard) {
303 | if (n == null || guard) {
304 | if (obj.length !== +obj.length) obj = _.values(obj);
305 | return obj[_.random(obj.length - 1)];
306 | }
307 | return _.shuffle(obj).slice(0, Math.max(0, n));
308 | };
309 |
310 | // An internal function to generate lookup iterators.
311 | var lookupIterator = function(value) {
312 | if (value == null) return _.identity;
313 | if (_.isFunction(value)) return value;
314 | return _.property(value);
315 | };
316 |
317 | // Sort the object's values by a criterion produced by an iterator.
318 | _.sortBy = function(obj, iterator, context) {
319 | iterator = lookupIterator(iterator);
320 | return _.pluck(_.map(obj, function(value, index, list) {
321 | return {
322 | value: value,
323 | index: index,
324 | criteria: iterator.call(context, value, index, list)
325 | };
326 | }).sort(function(left, right) {
327 | var a = left.criteria;
328 | var b = right.criteria;
329 | if (a !== b) {
330 | if (a > b || a === void 0) return 1;
331 | if (a < b || b === void 0) return -1;
332 | }
333 | return left.index - right.index;
334 | }), 'value');
335 | };
336 |
337 | // An internal function used for aggregate "group by" operations.
338 | var group = function(behavior) {
339 | return function(obj, iterator, context) {
340 | var result = {};
341 | iterator = lookupIterator(iterator);
342 | each(obj, function(value, index) {
343 | var key = iterator.call(context, value, index, obj);
344 | behavior(result, key, value);
345 | });
346 | return result;
347 | };
348 | };
349 |
350 | // Groups the object's values by a criterion. Pass either a string attribute
351 | // to group by, or a function that returns the criterion.
352 | _.groupBy = group(function(result, key, value) {
353 | _.has(result, key) ? result[key].push(value) : result[key] = [value];
354 | });
355 |
356 | // Indexes the object's values by a criterion, similar to `groupBy`, but for
357 | // when you know that your index values will be unique.
358 | _.indexBy = group(function(result, key, value) {
359 | result[key] = value;
360 | });
361 |
362 | // Counts instances of an object that group by a certain criterion. Pass
363 | // either a string attribute to count by, or a function that returns the
364 | // criterion.
365 | _.countBy = group(function(result, key) {
366 | _.has(result, key) ? result[key]++ : result[key] = 1;
367 | });
368 |
369 | // Use a comparator function to figure out the smallest index at which
370 | // an object should be inserted so as to maintain order. Uses binary search.
371 | _.sortedIndex = function(array, obj, iterator, context) {
372 | iterator = lookupIterator(iterator);
373 | var value = iterator.call(context, obj);
374 | var low = 0, high = array.length;
375 | while (low < high) {
376 | var mid = (low + high) >>> 1;
377 | iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
378 | }
379 | return low;
380 | };
381 |
382 | // Safely create a real, live array from anything iterable.
383 | _.toArray = function(obj) {
384 | if (!obj) return [];
385 | if (_.isArray(obj)) return slice.call(obj);
386 | if (obj.length === +obj.length) return _.map(obj, _.identity);
387 | return _.values(obj);
388 | };
389 |
390 | // Return the number of elements in an object.
391 | _.size = function(obj) {
392 | if (obj == null) return 0;
393 | return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
394 | };
395 |
396 | // Array Functions
397 | // ---------------
398 |
399 | // Get the first element of an array. Passing **n** will return the first N
400 | // values in the array. Aliased as `head` and `take`. The **guard** check
401 | // allows it to work with `_.map`.
402 | _.first = _.head = _.take = function(array, n, guard) {
403 | if (array == null) return void 0;
404 | if ((n == null) || guard) return array[0];
405 | if (n < 0) return [];
406 | return slice.call(array, 0, n);
407 | };
408 |
409 | // Returns everything but the last entry of the array. Especially useful on
410 | // the arguments object. Passing **n** will return all the values in
411 | // the array, excluding the last N. The **guard** check allows it to work with
412 | // `_.map`.
413 | _.initial = function(array, n, guard) {
414 | return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
415 | };
416 |
417 | // Get the last element of an array. Passing **n** will return the last N
418 | // values in the array. The **guard** check allows it to work with `_.map`.
419 | _.last = function(array, n, guard) {
420 | if (array == null) return void 0;
421 | if ((n == null) || guard) return array[array.length - 1];
422 | return slice.call(array, Math.max(array.length - n, 0));
423 | };
424 |
425 | // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
426 | // Especially useful on the arguments object. Passing an **n** will return
427 | // the rest N values in the array. The **guard**
428 | // check allows it to work with `_.map`.
429 | _.rest = _.tail = _.drop = function(array, n, guard) {
430 | return slice.call(array, (n == null) || guard ? 1 : n);
431 | };
432 |
433 | // Trim out all falsy values from an array.
434 | _.compact = function(array) {
435 | return _.filter(array, _.identity);
436 | };
437 |
438 | // Internal implementation of a recursive `flatten` function.
439 | var flatten = function(input, shallow, output) {
440 | if (shallow && _.every(input, _.isArray)) {
441 | return concat.apply(output, input);
442 | }
443 | each(input, function(value) {
444 | if (_.isArray(value) || _.isArguments(value)) {
445 | shallow ? push.apply(output, value) : flatten(value, shallow, output);
446 | } else {
447 | output.push(value);
448 | }
449 | });
450 | return output;
451 | };
452 |
453 | // Flatten out an array, either recursively (by default), or just one level.
454 | _.flatten = function(array, shallow) {
455 | return flatten(array, shallow, []);
456 | };
457 |
458 | // Return a version of the array that does not contain the specified value(s).
459 | _.without = function(array) {
460 | return _.difference(array, slice.call(arguments, 1));
461 | };
462 |
463 | // Split an array into two arrays: one whose elements all satisfy the given
464 | // predicate, and one whose elements all do not satisfy the predicate.
465 | _.partition = function(array, predicate) {
466 | var pass = [], fail = [];
467 | each(array, function(elem) {
468 | (predicate(elem) ? pass : fail).push(elem);
469 | });
470 | return [pass, fail];
471 | };
472 |
473 | // Produce a duplicate-free version of the array. If the array has already
474 | // been sorted, you have the option of using a faster algorithm.
475 | // Aliased as `unique`.
476 | _.uniq = _.unique = function(array, isSorted, iterator, context) {
477 | if (_.isFunction(isSorted)) {
478 | context = iterator;
479 | iterator = isSorted;
480 | isSorted = false;
481 | }
482 | var initial = iterator ? _.map(array, iterator, context) : array;
483 | var results = [];
484 | var seen = [];
485 | each(initial, function(value, index) {
486 | if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
487 | seen.push(value);
488 | results.push(array[index]);
489 | }
490 | });
491 | return results;
492 | };
493 |
494 | // Produce an array that contains the union: each distinct element from all of
495 | // the passed-in arrays.
496 | _.union = function() {
497 | return _.uniq(_.flatten(arguments, true));
498 | };
499 |
500 | // Produce an array that contains every item shared between all the
501 | // passed-in arrays.
502 | _.intersection = function(array) {
503 | var rest = slice.call(arguments, 1);
504 | return _.filter(_.uniq(array), function(item) {
505 | return _.every(rest, function(other) {
506 | return _.contains(other, item);
507 | });
508 | });
509 | };
510 |
511 | // Take the difference between one array and a number of other arrays.
512 | // Only the elements present in just the first array will remain.
513 | _.difference = function(array) {
514 | var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
515 | return _.filter(array, function(value){ return !_.contains(rest, value); });
516 | };
517 |
518 | // Zip together multiple lists into a single array -- elements that share
519 | // an index go together.
520 | _.zip = function() {
521 | var length = _.max(_.pluck(arguments, 'length').concat(0));
522 | var results = new Array(length);
523 | for (var i = 0; i < length; i++) {
524 | results[i] = _.pluck(arguments, '' + i);
525 | }
526 | return results;
527 | };
528 |
529 | // Converts lists into objects. Pass either a single array of `[key, value]`
530 | // pairs, or two parallel arrays of the same length -- one of keys, and one of
531 | // the corresponding values.
532 | _.object = function(list, values) {
533 | if (list == null) return {};
534 | var result = {};
535 | for (var i = 0, length = list.length; i < length; i++) {
536 | if (values) {
537 | result[list[i]] = values[i];
538 | } else {
539 | result[list[i][0]] = list[i][1];
540 | }
541 | }
542 | return result;
543 | };
544 |
545 | // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
546 | // we need this function. Return the position of the first occurrence of an
547 | // item in an array, or -1 if the item is not included in the array.
548 | // Delegates to **ECMAScript 5**'s native `indexOf` if available.
549 | // If the array is large and already in sort order, pass `true`
550 | // for **isSorted** to use binary search.
551 | _.indexOf = function(array, item, isSorted) {
552 | if (array == null) return -1;
553 | var i = 0, length = array.length;
554 | if (isSorted) {
555 | if (typeof isSorted == 'number') {
556 | i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
557 | } else {
558 | i = _.sortedIndex(array, item);
559 | return array[i] === item ? i : -1;
560 | }
561 | }
562 | if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
563 | for (; i < length; i++) if (array[i] === item) return i;
564 | return -1;
565 | };
566 |
567 | // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
568 | _.lastIndexOf = function(array, item, from) {
569 | if (array == null) return -1;
570 | var hasIndex = from != null;
571 | if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
572 | return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
573 | }
574 | var i = (hasIndex ? from : array.length);
575 | while (i--) if (array[i] === item) return i;
576 | return -1;
577 | };
578 |
579 | // Generate an integer Array containing an arithmetic progression. A port of
580 | // the native Python `range()` function. See
581 | // [the Python documentation](http://docs.python.org/library/functions.html#range).
582 | _.range = function(start, stop, step) {
583 | if (arguments.length <= 1) {
584 | stop = start || 0;
585 | start = 0;
586 | }
587 | step = arguments[2] || 1;
588 |
589 | var length = Math.max(Math.ceil((stop - start) / step), 0);
590 | var idx = 0;
591 | var range = new Array(length);
592 |
593 | while(idx < length) {
594 | range[idx++] = start;
595 | start += step;
596 | }
597 |
598 | return range;
599 | };
600 |
601 | // Function (ahem) Functions
602 | // ------------------
603 |
604 | // Reusable constructor function for prototype setting.
605 | var ctor = function(){};
606 |
607 | // Create a function bound to a given object (assigning `this`, and arguments,
608 | // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
609 | // available.
610 | _.bind = function(func, context) {
611 | var args, bound;
612 | if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
613 | if (!_.isFunction(func)) throw new TypeError;
614 | args = slice.call(arguments, 2);
615 | return bound = function() {
616 | if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
617 | ctor.prototype = func.prototype;
618 | var self = new ctor;
619 | ctor.prototype = null;
620 | var result = func.apply(self, args.concat(slice.call(arguments)));
621 | if (Object(result) === result) return result;
622 | return self;
623 | };
624 | };
625 |
626 | // Partially apply a function by creating a version that has had some of its
627 | // arguments pre-filled, without changing its dynamic `this` context. _ acts
628 | // as a placeholder, allowing any combination of arguments to be pre-filled.
629 | _.partial = function(func) {
630 | var boundArgs = slice.call(arguments, 1);
631 | return function() {
632 | var position = 0;
633 | var args = boundArgs.slice();
634 | for (var i = 0, length = args.length; i < length; i++) {
635 | if (args[i] === _) args[i] = arguments[position++];
636 | }
637 | while (position < arguments.length) args.push(arguments[position++]);
638 | return func.apply(this, args);
639 | };
640 | };
641 |
642 | // Bind a number of an object's methods to that object. Remaining arguments
643 | // are the method names to be bound. Useful for ensuring that all callbacks
644 | // defined on an object belong to it.
645 | _.bindAll = function(obj) {
646 | var funcs = slice.call(arguments, 1);
647 | if (funcs.length === 0) throw new Error('bindAll must be passed function names');
648 | each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
649 | return obj;
650 | };
651 |
652 | // Memoize an expensive function by storing its results.
653 | _.memoize = function(func, hasher) {
654 | var memo = {};
655 | hasher || (hasher = _.identity);
656 | return function() {
657 | var key = hasher.apply(this, arguments);
658 | return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
659 | };
660 | };
661 |
662 | // Delays a function for the given number of milliseconds, and then calls
663 | // it with the arguments supplied.
664 | _.delay = function(func, wait) {
665 | var args = slice.call(arguments, 2);
666 | return setTimeout(function(){ return func.apply(null, args); }, wait);
667 | };
668 |
669 | // Defers a function, scheduling it to run after the current call stack has
670 | // cleared.
671 | _.defer = function(func) {
672 | return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
673 | };
674 |
675 | // Returns a function, that, when invoked, will only be triggered at most once
676 | // during a given window of time. Normally, the throttled function will run
677 | // as much as it can, without ever going more than once per `wait` duration;
678 | // but if you'd like to disable the execution on the leading edge, pass
679 | // `{leading: false}`. To disable execution on the trailing edge, ditto.
680 | _.throttle = function(func, wait, options) {
681 | var context, args, result;
682 | var timeout = null;
683 | var previous = 0;
684 | options || (options = {});
685 | var later = function() {
686 | previous = options.leading === false ? 0 : _.now();
687 | timeout = null;
688 | result = func.apply(context, args);
689 | context = args = null;
690 | };
691 | return function() {
692 | var now = _.now();
693 | if (!previous && options.leading === false) previous = now;
694 | var remaining = wait - (now - previous);
695 | context = this;
696 | args = arguments;
697 | if (remaining <= 0) {
698 | clearTimeout(timeout);
699 | timeout = null;
700 | previous = now;
701 | result = func.apply(context, args);
702 | context = args = null;
703 | } else if (!timeout && options.trailing !== false) {
704 | timeout = setTimeout(later, remaining);
705 | }
706 | return result;
707 | };
708 | };
709 |
710 | // Returns a function, that, as long as it continues to be invoked, will not
711 | // be triggered. The function will be called after it stops being called for
712 | // N milliseconds. If `immediate` is passed, trigger the function on the
713 | // leading edge, instead of the trailing.
714 | _.debounce = function(func, wait, immediate) {
715 | var timeout, args, context, timestamp, result;
716 |
717 | var later = function() {
718 | var last = _.now() - timestamp;
719 | if (last < wait) {
720 | timeout = setTimeout(later, wait - last);
721 | } else {
722 | timeout = null;
723 | if (!immediate) {
724 | result = func.apply(context, args);
725 | context = args = null;
726 | }
727 | }
728 | };
729 |
730 | return function() {
731 | context = this;
732 | args = arguments;
733 | timestamp = _.now();
734 | var callNow = immediate && !timeout;
735 | if (!timeout) {
736 | timeout = setTimeout(later, wait);
737 | }
738 | if (callNow) {
739 | result = func.apply(context, args);
740 | context = args = null;
741 | }
742 |
743 | return result;
744 | };
745 | };
746 |
747 | // Returns a function that will be executed at most one time, no matter how
748 | // often you call it. Useful for lazy initialization.
749 | _.once = function(func) {
750 | var ran = false, memo;
751 | return function() {
752 | if (ran) return memo;
753 | ran = true;
754 | memo = func.apply(this, arguments);
755 | func = null;
756 | return memo;
757 | };
758 | };
759 |
760 | // Returns the first function passed as an argument to the second,
761 | // allowing you to adjust arguments, run code before and after, and
762 | // conditionally execute the original function.
763 | _.wrap = function(func, wrapper) {
764 | return _.partial(wrapper, func);
765 | };
766 |
767 | // Returns a function that is the composition of a list of functions, each
768 | // consuming the return value of the function that follows.
769 | _.compose = function() {
770 | var funcs = arguments;
771 | return function() {
772 | var args = arguments;
773 | for (var i = funcs.length - 1; i >= 0; i--) {
774 | args = [funcs[i].apply(this, args)];
775 | }
776 | return args[0];
777 | };
778 | };
779 |
780 | // Returns a function that will only be executed after being called N times.
781 | _.after = function(times, func) {
782 | return function() {
783 | if (--times < 1) {
784 | return func.apply(this, arguments);
785 | }
786 | };
787 | };
788 |
789 | // Object Functions
790 | // ----------------
791 |
792 | // Retrieve the names of an object's properties.
793 | // Delegates to **ECMAScript 5**'s native `Object.keys`
794 | _.keys = function(obj) {
795 | if (!_.isObject(obj)) return [];
796 | if (nativeKeys) return nativeKeys(obj);
797 | var keys = [];
798 | for (var key in obj) if (_.has(obj, key)) keys.push(key);
799 | return keys;
800 | };
801 |
802 | // Retrieve the values of an object's properties.
803 | _.values = function(obj) {
804 | var keys = _.keys(obj);
805 | var length = keys.length;
806 | var values = new Array(length);
807 | for (var i = 0; i < length; i++) {
808 | values[i] = obj[keys[i]];
809 | }
810 | return values;
811 | };
812 |
813 | // Convert an object into a list of `[key, value]` pairs.
814 | _.pairs = function(obj) {
815 | var keys = _.keys(obj);
816 | var length = keys.length;
817 | var pairs = new Array(length);
818 | for (var i = 0; i < length; i++) {
819 | pairs[i] = [keys[i], obj[keys[i]]];
820 | }
821 | return pairs;
822 | };
823 |
824 | // Invert the keys and values of an object. The values must be serializable.
825 | _.invert = function(obj) {
826 | var result = {};
827 | var keys = _.keys(obj);
828 | for (var i = 0, length = keys.length; i < length; i++) {
829 | result[obj[keys[i]]] = keys[i];
830 | }
831 | return result;
832 | };
833 |
834 | // Return a sorted list of the function names available on the object.
835 | // Aliased as `methods`
836 | _.functions = _.methods = function(obj) {
837 | var names = [];
838 | for (var key in obj) {
839 | if (_.isFunction(obj[key])) names.push(key);
840 | }
841 | return names.sort();
842 | };
843 |
844 | // Extend a given object with all the properties in passed-in object(s).
845 | _.extend = function(obj) {
846 | each(slice.call(arguments, 1), function(source) {
847 | if (source) {
848 | for (var prop in source) {
849 | obj[prop] = source[prop];
850 | }
851 | }
852 | });
853 | return obj;
854 | };
855 |
856 | // Return a copy of the object only containing the whitelisted properties.
857 | _.pick = function(obj) {
858 | var copy = {};
859 | var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
860 | each(keys, function(key) {
861 | if (key in obj) copy[key] = obj[key];
862 | });
863 | return copy;
864 | };
865 |
866 | // Return a copy of the object without the blacklisted properties.
867 | _.omit = function(obj) {
868 | var copy = {};
869 | var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
870 | for (var key in obj) {
871 | if (!_.contains(keys, key)) copy[key] = obj[key];
872 | }
873 | return copy;
874 | };
875 |
876 | // Fill in a given object with default properties.
877 | _.defaults = function(obj) {
878 | each(slice.call(arguments, 1), function(source) {
879 | if (source) {
880 | for (var prop in source) {
881 | if (obj[prop] === void 0) obj[prop] = source[prop];
882 | }
883 | }
884 | });
885 | return obj;
886 | };
887 |
888 | // Create a (shallow-cloned) duplicate of an object.
889 | _.clone = function(obj) {
890 | if (!_.isObject(obj)) return obj;
891 | return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
892 | };
893 |
894 | // Invokes interceptor with the obj, and then returns obj.
895 | // The primary purpose of this method is to "tap into" a method chain, in
896 | // order to perform operations on intermediate results within the chain.
897 | _.tap = function(obj, interceptor) {
898 | interceptor(obj);
899 | return obj;
900 | };
901 |
902 | // Internal recursive comparison function for `isEqual`.
903 | var eq = function(a, b, aStack, bStack) {
904 | // Identical objects are equal. `0 === -0`, but they aren't identical.
905 | // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
906 | if (a === b) return a !== 0 || 1 / a == 1 / b;
907 | // A strict comparison is necessary because `null == undefined`.
908 | if (a == null || b == null) return a === b;
909 | // Unwrap any wrapped objects.
910 | if (a instanceof _) a = a._wrapped;
911 | if (b instanceof _) b = b._wrapped;
912 | // Compare `[[Class]]` names.
913 | var className = toString.call(a);
914 | if (className != toString.call(b)) return false;
915 | switch (className) {
916 | // Strings, numbers, dates, and booleans are compared by value.
917 | case '[object String]':
918 | // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
919 | // equivalent to `new String("5")`.
920 | return a == String(b);
921 | case '[object Number]':
922 | // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
923 | // other numeric values.
924 | return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
925 | case '[object Date]':
926 | case '[object Boolean]':
927 | // Coerce dates and booleans to numeric primitive values. Dates are compared by their
928 | // millisecond representations. Note that invalid dates with millisecond representations
929 | // of `NaN` are not equivalent.
930 | return +a == +b;
931 | // RegExps are compared by their source patterns and flags.
932 | case '[object RegExp]':
933 | return a.source == b.source &&
934 | a.global == b.global &&
935 | a.multiline == b.multiline &&
936 | a.ignoreCase == b.ignoreCase;
937 | }
938 | if (typeof a != 'object' || typeof b != 'object') return false;
939 | // Assume equality for cyclic structures. The algorithm for detecting cyclic
940 | // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
941 | var length = aStack.length;
942 | while (length--) {
943 | // Linear search. Performance is inversely proportional to the number of
944 | // unique nested structures.
945 | if (aStack[length] == a) return bStack[length] == b;
946 | }
947 | // Objects with different constructors are not equivalent, but `Object`s
948 | // from different frames are.
949 | var aCtor = a.constructor, bCtor = b.constructor;
950 | if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
951 | _.isFunction(bCtor) && (bCtor instanceof bCtor))
952 | && ('constructor' in a && 'constructor' in b)) {
953 | return false;
954 | }
955 | // Add the first object to the stack of traversed objects.
956 | aStack.push(a);
957 | bStack.push(b);
958 | var size = 0, result = true;
959 | // Recursively compare objects and arrays.
960 | if (className == '[object Array]') {
961 | // Compare array lengths to determine if a deep comparison is necessary.
962 | size = a.length;
963 | result = size == b.length;
964 | if (result) {
965 | // Deep compare the contents, ignoring non-numeric properties.
966 | while (size--) {
967 | if (!(result = eq(a[size], b[size], aStack, bStack))) break;
968 | }
969 | }
970 | } else {
971 | // Deep compare objects.
972 | for (var key in a) {
973 | if (_.has(a, key)) {
974 | // Count the expected number of properties.
975 | size++;
976 | // Deep compare each member.
977 | if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
978 | }
979 | }
980 | // Ensure that both objects contain the same number of properties.
981 | if (result) {
982 | for (key in b) {
983 | if (_.has(b, key) && !(size--)) break;
984 | }
985 | result = !size;
986 | }
987 | }
988 | // Remove the first object from the stack of traversed objects.
989 | aStack.pop();
990 | bStack.pop();
991 | return result;
992 | };
993 |
994 | // Perform a deep comparison to check if two objects are equal.
995 | _.isEqual = function(a, b) {
996 | return eq(a, b, [], []);
997 | };
998 |
999 | // Is a given array, string, or object empty?
1000 | // An "empty" object has no enumerable own-properties.
1001 | _.isEmpty = function(obj) {
1002 | if (obj == null) return true;
1003 | if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
1004 | for (var key in obj) if (_.has(obj, key)) return false;
1005 | return true;
1006 | };
1007 |
1008 | // Is a given value a DOM element?
1009 | _.isElement = function(obj) {
1010 | return !!(obj && obj.nodeType === 1);
1011 | };
1012 |
1013 | // Is a given value an array?
1014 | // Delegates to ECMA5's native Array.isArray
1015 | _.isArray = nativeIsArray || function(obj) {
1016 | return toString.call(obj) == '[object Array]';
1017 | };
1018 |
1019 | // Is a given variable an object?
1020 | _.isObject = function(obj) {
1021 | return obj === Object(obj);
1022 | };
1023 |
1024 | // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
1025 | each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
1026 | _['is' + name] = function(obj) {
1027 | return toString.call(obj) == '[object ' + name + ']';
1028 | };
1029 | });
1030 |
1031 | // Define a fallback version of the method in browsers (ahem, IE), where
1032 | // there isn't any inspectable "Arguments" type.
1033 | if (!_.isArguments(arguments)) {
1034 | _.isArguments = function(obj) {
1035 | return !!(obj && _.has(obj, 'callee'));
1036 | };
1037 | }
1038 |
1039 | // Optimize `isFunction` if appropriate.
1040 | if (typeof (/./) !== 'function') {
1041 | _.isFunction = function(obj) {
1042 | return typeof obj === 'function';
1043 | };
1044 | }
1045 |
1046 | // Is a given object a finite number?
1047 | _.isFinite = function(obj) {
1048 | return isFinite(obj) && !isNaN(parseFloat(obj));
1049 | };
1050 |
1051 | // Is the given value `NaN`? (NaN is the only number which does not equal itself).
1052 | _.isNaN = function(obj) {
1053 | return _.isNumber(obj) && obj != +obj;
1054 | };
1055 |
1056 | // Is a given value a boolean?
1057 | _.isBoolean = function(obj) {
1058 | return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
1059 | };
1060 |
1061 | // Is a given value equal to null?
1062 | _.isNull = function(obj) {
1063 | return obj === null;
1064 | };
1065 |
1066 | // Is a given variable undefined?
1067 | _.isUndefined = function(obj) {
1068 | return obj === void 0;
1069 | };
1070 |
1071 | // Shortcut function for checking if an object has a given property directly
1072 | // on itself (in other words, not on a prototype).
1073 | _.has = function(obj, key) {
1074 | return hasOwnProperty.call(obj, key);
1075 | };
1076 |
1077 | // Utility Functions
1078 | // -----------------
1079 |
1080 | // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
1081 | // previous owner. Returns a reference to the Underscore object.
1082 | _.noConflict = function() {
1083 | root._ = previousUnderscore;
1084 | return this;
1085 | };
1086 |
1087 | // Keep the identity function around for default iterators.
1088 | _.identity = function(value) {
1089 | return value;
1090 | };
1091 |
1092 | _.constant = function(value) {
1093 | return function () {
1094 | return value;
1095 | };
1096 | };
1097 |
1098 | _.property = function(key) {
1099 | return function(obj) {
1100 | return obj[key];
1101 | };
1102 | };
1103 |
1104 | // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
1105 | _.matches = function(attrs) {
1106 | return function(obj) {
1107 | if (obj === attrs) return true; //avoid comparing an object to itself.
1108 | for (var key in attrs) {
1109 | if (attrs[key] !== obj[key])
1110 | return false;
1111 | }
1112 | return true;
1113 | }
1114 | };
1115 |
1116 | // Run a function **n** times.
1117 | _.times = function(n, iterator, context) {
1118 | var accum = Array(Math.max(0, n));
1119 | for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
1120 | return accum;
1121 | };
1122 |
1123 | // Return a random integer between min and max (inclusive).
1124 | _.random = function(min, max) {
1125 | if (max == null) {
1126 | max = min;
1127 | min = 0;
1128 | }
1129 | return min + Math.floor(Math.random() * (max - min + 1));
1130 | };
1131 |
1132 | // A (possibly faster) way to get the current timestamp as an integer.
1133 | _.now = Date.now || function() { return new Date().getTime(); };
1134 |
1135 | // List of HTML entities for escaping.
1136 | var entityMap = {
1137 | escape: {
1138 | '&': '&',
1139 | '<': '<',
1140 | '>': '>',
1141 | '"': '"',
1142 | "'": '''
1143 | }
1144 | };
1145 | entityMap.unescape = _.invert(entityMap.escape);
1146 |
1147 | // Regexes containing the keys and values listed immediately above.
1148 | var entityRegexes = {
1149 | escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
1150 | unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
1151 | };
1152 |
1153 | // Functions for escaping and unescaping strings to/from HTML interpolation.
1154 | _.each(['escape', 'unescape'], function(method) {
1155 | _[method] = function(string) {
1156 | if (string == null) return '';
1157 | return ('' + string).replace(entityRegexes[method], function(match) {
1158 | return entityMap[method][match];
1159 | });
1160 | };
1161 | });
1162 |
1163 | // If the value of the named `property` is a function then invoke it with the
1164 | // `object` as context; otherwise, return it.
1165 | _.result = function(object, property) {
1166 | if (object == null) return void 0;
1167 | var value = object[property];
1168 | return _.isFunction(value) ? value.call(object) : value;
1169 | };
1170 |
1171 | // Add your own custom functions to the Underscore object.
1172 | _.mixin = function(obj) {
1173 | each(_.functions(obj), function(name) {
1174 | var func = _[name] = obj[name];
1175 | _.prototype[name] = function() {
1176 | var args = [this._wrapped];
1177 | push.apply(args, arguments);
1178 | return result.call(this, func.apply(_, args));
1179 | };
1180 | });
1181 | };
1182 |
1183 | // Generate a unique integer id (unique within the entire client session).
1184 | // Useful for temporary DOM ids.
1185 | var idCounter = 0;
1186 | _.uniqueId = function(prefix) {
1187 | var id = ++idCounter + '';
1188 | return prefix ? prefix + id : id;
1189 | };
1190 |
1191 | // By default, Underscore uses ERB-style template delimiters, change the
1192 | // following template settings to use alternative delimiters.
1193 | _.templateSettings = {
1194 | evaluate : /<%([\s\S]+?)%>/g,
1195 | interpolate : /<%=([\s\S]+?)%>/g,
1196 | escape : /<%-([\s\S]+?)%>/g
1197 | };
1198 |
1199 | // When customizing `templateSettings`, if you don't want to define an
1200 | // interpolation, evaluation or escaping regex, we need one that is
1201 | // guaranteed not to match.
1202 | var noMatch = /(.)^/;
1203 |
1204 | // Certain characters need to be escaped so that they can be put into a
1205 | // string literal.
1206 | var escapes = {
1207 | "'": "'",
1208 | '\\': '\\',
1209 | '\r': 'r',
1210 | '\n': 'n',
1211 | '\t': 't',
1212 | '\u2028': 'u2028',
1213 | '\u2029': 'u2029'
1214 | };
1215 |
1216 | var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
1217 |
1218 | // JavaScript micro-templating, similar to John Resig's implementation.
1219 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
1220 | // and correctly escapes quotes within interpolated code.
1221 | _.template = function(text, data, settings) {
1222 | var render;
1223 | settings = _.defaults({}, settings, _.templateSettings);
1224 |
1225 | // Combine delimiters into one regular expression via alternation.
1226 | var matcher = new RegExp([
1227 | (settings.escape || noMatch).source,
1228 | (settings.interpolate || noMatch).source,
1229 | (settings.evaluate || noMatch).source
1230 | ].join('|') + '|$', 'g');
1231 |
1232 | // Compile the template source, escaping string literals appropriately.
1233 | var index = 0;
1234 | var source = "__p+='";
1235 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
1236 | source += text.slice(index, offset)
1237 | .replace(escaper, function(match) { return '\\' + escapes[match]; });
1238 |
1239 | if (escape) {
1240 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
1241 | }
1242 | if (interpolate) {
1243 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
1244 | }
1245 | if (evaluate) {
1246 | source += "';\n" + evaluate + "\n__p+='";
1247 | }
1248 | index = offset + match.length;
1249 | return match;
1250 | });
1251 | source += "';\n";
1252 |
1253 | // If a variable is not specified, place data values in local scope.
1254 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
1255 |
1256 | source = "var __t,__p='',__j=Array.prototype.join," +
1257 | "print=function(){__p+=__j.call(arguments,'');};\n" +
1258 | source + "return __p;\n";
1259 |
1260 | try {
1261 | render = new Function(settings.variable || 'obj', '_', source);
1262 | } catch (e) {
1263 | e.source = source;
1264 | throw e;
1265 | }
1266 |
1267 | if (data) return render(data, _);
1268 | var template = function(data) {
1269 | return render.call(this, data, _);
1270 | };
1271 |
1272 | // Provide the compiled function source as a convenience for precompilation.
1273 | template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
1274 |
1275 | return template;
1276 | };
1277 |
1278 | // Add a "chain" function, which will delegate to the wrapper.
1279 | _.chain = function(obj) {
1280 | return _(obj).chain();
1281 | };
1282 |
1283 | // OOP
1284 | // ---------------
1285 | // If Underscore is called as a function, it returns a wrapped object that
1286 | // can be used OO-style. This wrapper holds altered versions of all the
1287 | // underscore functions. Wrapped objects may be chained.
1288 |
1289 | // Helper function to continue chaining intermediate results.
1290 | var result = function(obj) {
1291 | return this._chain ? _(obj).chain() : obj;
1292 | };
1293 |
1294 | // Add all of the Underscore functions to the wrapper object.
1295 | _.mixin(_);
1296 |
1297 | // Add all mutator Array functions to the wrapper.
1298 | each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1299 | var method = ArrayProto[name];
1300 | _.prototype[name] = function() {
1301 | var obj = this._wrapped;
1302 | method.apply(obj, arguments);
1303 | if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
1304 | return result.call(this, obj);
1305 | };
1306 | });
1307 |
1308 | // Add all accessor Array functions to the wrapper.
1309 | each(['concat', 'join', 'slice'], function(name) {
1310 | var method = ArrayProto[name];
1311 | _.prototype[name] = function() {
1312 | return result.call(this, method.apply(this._wrapped, arguments));
1313 | };
1314 | });
1315 |
1316 | _.extend(_.prototype, {
1317 |
1318 | // Start chaining a wrapped Underscore object.
1319 | chain: function() {
1320 | this._chain = true;
1321 | return this;
1322 | },
1323 |
1324 | // Extracts the result from a wrapped and chained object.
1325 | value: function() {
1326 | return this._wrapped;
1327 | }
1328 |
1329 | });
1330 |
1331 | // AMD registration happens at the end for compatibility with AMD loaders
1332 | // that may not enforce next-turn semantics on modules. Even though general
1333 | // practice for AMD registration is to be anonymous, underscore registers
1334 | // as a named module because, like jQuery, it is a base library that is
1335 | // popular enough to be bundled in a third party lib, but not be part of
1336 | // an AMD load request. Those cases could generate an error when an
1337 | // anonymous define() is called outside of a loader request.
1338 | if (typeof define === 'function' && define.amd) {
1339 | define('underscore', [], function() {
1340 | return _;
1341 | });
1342 | }
1343 | }).call(this);
1344 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Foxandxss/rails-angular-jwt-example/69c0df72f598c6f9834cb7cd33de988e66b101c4/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/auth_token.rb:
--------------------------------------------------------------------------------
1 | require 'jwt'
2 |
3 | module AuthToken
4 | def AuthToken.issue_token(payload)
5 | # Set expiration to 24 hours.
6 | JWT.encode(payload, Rails.application.secrets.secret_key_base, claims: { exp: 86400 })
7 | end
8 |
9 | def AuthToken.valid?(token)
10 | begin
11 | JWT.decode(token, Rails.application.secrets.secret_key_base)
12 | rescue
13 | false
14 | end
15 | end
16 | end
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Foxandxss/rails-angular-jwt-example/69c0df72f598c6f9834cb7cd33de988e66b101c4/lib/tasks/.keep
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Foxandxss/rails-angular-jwt-example/69c0df72f598c6f9834cb7cd33de988e66b101c4/log/.keep
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Foxandxss/rails-angular-jwt-example/69c0df72f598c6f9834cb7cd33de988e66b101c4/public/favicon.ico
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Foxandxss/rails-angular-jwt-example/69c0df72f598c6f9834cb7cd33de988e66b101c4/vendor/assets/javascripts/.keep
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Foxandxss/rails-angular-jwt-example/69c0df72f598c6f9834cb7cd33de988e66b101c4/vendor/assets/stylesheets/.keep
--------------------------------------------------------------------------------