├── .gitignore ├── views ├── partials │ ├── .gitignore │ ├── partial1.jade │ └── partial2.jade ├── layout.jade └── index.jade ├── .bowerrc ├── public ├── bower_components │ ├── angular-socket-io │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── bower.json │ │ ├── mock │ │ │ └── socket-io.js │ │ ├── package.json │ │ ├── .bower.json │ │ ├── karma.conf.js │ │ ├── socket.js │ │ ├── socket.spec.js │ │ └── README.md │ ├── angular │ │ ├── angular.min.js.gzip │ │ ├── bower.json │ │ ├── angular-csp.css │ │ ├── .bower.json │ │ ├── README.md │ │ └── angular.min.js │ └── angular-route │ │ ├── bower.json │ │ ├── .bower.json │ │ ├── README.md │ │ ├── angular-route.min.js │ │ ├── angular-route.min.js.map │ │ └── angular-route.js ├── js │ ├── directives.js │ ├── filters.js │ ├── services.js │ ├── controllers.js │ └── app.js └── css │ └── app.css ├── routes ├── api.js ├── index.js └── socket.js ├── package.json ├── bower.json ├── app.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /views/partials/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "public/bower_components" 3 | } -------------------------------------------------------------------------------- /public/bower_components/angular-socket-io/.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | bower_components/ 3 | -------------------------------------------------------------------------------- /views/partials/partial1.jade: -------------------------------------------------------------------------------- 1 | p This is the partial for view 1. 2 | p The current time is {{time}} -------------------------------------------------------------------------------- /public/bower_components/angular/angular.min.js.gzip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/btford/angular-socket-io-seed/HEAD/public/bower_components/angular/angular.min.js.gzip -------------------------------------------------------------------------------- /public/bower_components/angular/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular", 3 | "version": "1.2.14", 4 | "main": "./angular.js", 5 | "dependencies": { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /routes/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Serve JSON to our AngularJS client 3 | */ 4 | 5 | exports.name = function (req, res) { 6 | res.json({ 7 | name: 'Bob' 8 | }); 9 | }; -------------------------------------------------------------------------------- /views/partials/partial2.jade: -------------------------------------------------------------------------------- 1 | p This is the partial for view 2. 2 | p 3 | | Showing of 'interpolate' filter: 4 | | {{ 'Current version is v%VERSION%.' | interpolate }} 5 | -------------------------------------------------------------------------------- /public/bower_components/angular-socket-io/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | before_script: 5 | - export DISPLAY=:99.0 6 | - sh -e /etc/init.d/xvfb start 7 | -------------------------------------------------------------------------------- /public/bower_components/angular-route/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-route", 3 | "version": "1.2.14", 4 | "main": "./angular-route.js", 5 | "dependencies": { 6 | "angular": "1.2.14" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /views/layout.jade: -------------------------------------------------------------------------------- 1 | !!! 2 | html(ng-app="myApp") 3 | head 4 | meta(charset='utf8') 5 | base(href='/') 6 | title Angular Socket.io Seed App 7 | link(rel='stylesheet', href='/css/app.css') 8 | body 9 | block body -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "application-name", 3 | "version": "0.0.0", 4 | "private": true, 5 | "dependencies": { 6 | "socket.io": "~0.9.16", 7 | "express": "~3.2.6", 8 | "jade": "~0.31.2" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * GET home page. 3 | */ 4 | 5 | exports.index = function(req, res){ 6 | res.render('index'); 7 | }; 8 | 9 | exports.partials = function (req, res) { 10 | var name = req.params.name; 11 | res.render('partials/' + name); 12 | }; -------------------------------------------------------------------------------- /public/js/directives.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Directives */ 4 | 5 | angular.module('myApp.directives', []). 6 | directive('appVersion', function (version) { 7 | return function(scope, elm, attrs) { 8 | elm.text(version); 9 | }; 10 | }); 11 | -------------------------------------------------------------------------------- /public/js/filters.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Filters */ 4 | 5 | angular.module('myApp.filters', []). 6 | filter('interpolate', function (version) { 7 | return function (text) { 8 | return String(text).replace(/\%VERSION\%/mg, version); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /public/bower_components/angular-socket-io/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-socket-io", 3 | "version": "0.3.0", 4 | "main": "socket.js", 5 | "dependencies": { 6 | "angular": "~1.2.6" 7 | }, 8 | "devDependencies": { 9 | "angular-mocks": "~1.2.6" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "application-name", 3 | "version": "0.0.0", 4 | "ignore": [ 5 | "**/.*", 6 | "node_modules", 7 | "components" 8 | ], 9 | "dependencies": { 10 | "angular": "~1.2.14", 11 | "angular-socket-io": "~0.3.0", 12 | "angular-route": "~1.2.14" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /routes/socket.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Serve content over a socket 3 | */ 4 | 5 | module.exports = function (socket) { 6 | socket.emit('send:name', { 7 | name: 'Bob' 8 | }); 9 | 10 | setInterval(function () { 11 | socket.emit('send:time', { 12 | time: (new Date()).toString() 13 | }); 14 | }, 1000); 15 | }; 16 | -------------------------------------------------------------------------------- /public/js/services.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Services */ 4 | 5 | 6 | // Demonstrate how to register services 7 | // In this case it is a simple value service. 8 | angular.module('myApp.services', []). 9 | factory('socket', function (socketFactory) { 10 | return socketFactory(); 11 | }). 12 | value('version', '0.1'); 13 | -------------------------------------------------------------------------------- /public/bower_components/angular/angular-csp.css: -------------------------------------------------------------------------------- 1 | /* Include this file in your html if you are using the CSP mode. */ 2 | 3 | @charset "UTF-8"; 4 | 5 | [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], 6 | .ng-cloak, .x-ng-cloak, 7 | .ng-hide { 8 | display: none !important; 9 | } 10 | 11 | ng\:form { 12 | display: block; 13 | } 14 | 15 | .ng-animate-block-transitions { 16 | transition:0s all!important; 17 | -webkit-transition:0s all!important; 18 | } 19 | -------------------------------------------------------------------------------- /public/css/app.css: -------------------------------------------------------------------------------- 1 | /* app css stylesheet */ 2 | 3 | .menu { 4 | list-style: none; 5 | border-bottom: 0.1em solid black; 6 | margin-bottom: 2em; 7 | padding: 0 0 0.5em; 8 | } 9 | 10 | .menu:before { 11 | content: "["; 12 | } 13 | 14 | .menu:after { 15 | content: "]"; 16 | } 17 | 18 | .menu > li { 19 | display: inline; 20 | } 21 | 22 | .menu > li:before { 23 | content: "|"; 24 | padding-right: 0.3em; 25 | } 26 | 27 | .menu > li:nth-child(1):before { 28 | content: ""; 29 | padding: 0; 30 | } 31 | -------------------------------------------------------------------------------- /public/js/controllers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Controllers */ 4 | 5 | angular.module('myApp.controllers', []). 6 | controller('AppCtrl', function ($scope, socket) { 7 | socket.on('send:name', function (data) { 8 | $scope.name = data.name; 9 | }); 10 | }). 11 | controller('MyCtrl1', function ($scope, socket) { 12 | socket.on('send:time', function (data) { 13 | $scope.time = data.time; 14 | }); 15 | }). 16 | controller('MyCtrl2', function ($scope) { 17 | // write Ctrl here 18 | }); 19 | -------------------------------------------------------------------------------- /public/bower_components/angular-socket-io/mock/socket-io.js: -------------------------------------------------------------------------------- 1 | var io = { 2 | connect: createMockSocketObject 3 | }; 4 | 5 | function createMockSocketObject () { 6 | 7 | var socket = { 8 | on: function (ev, fn) { 9 | this._listeners[ev] = fn; 10 | }, 11 | emit: function (ev, data) { 12 | return (this._listeners[ev] || angular.noop)(data); 13 | }, 14 | _listeners: {}, 15 | removeListener: function (ev) { 16 | delete this._listeners[ev]; 17 | } 18 | }; 19 | 20 | return socket; 21 | } 22 | -------------------------------------------------------------------------------- /public/bower_components/angular/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular", 3 | "version": "1.2.14", 4 | "main": "./angular.js", 5 | "dependencies": {}, 6 | "homepage": "https://github.com/angular/bower-angular", 7 | "_release": "1.2.14", 8 | "_resolution": { 9 | "type": "version", 10 | "tag": "v1.2.14", 11 | "commit": "6a20ae7b5ea044d51c01c9d75d45a9350fffb88c" 12 | }, 13 | "_source": "git://github.com/angular/bower-angular.git", 14 | "_target": "~1.2.14", 15 | "_originalSource": "angular", 16 | "_direct": true 17 | } -------------------------------------------------------------------------------- /public/bower_components/angular-socket-io/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-socket-io", 3 | "version": "0.3.0", 4 | "main": "socket.js", 5 | "directories": { 6 | "test": "test" 7 | }, 8 | "scripts": { 9 | "test": "./node_modules/.bin/karma start --browsers Firefox --single-run" 10 | }, 11 | "author": "Brian Ford", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "karma": "~0.10.2", 15 | "karma-jasmine": "~0.1.3", 16 | "karma-firefox-launcher": "~0.1.0" 17 | }, 18 | "dependencies": { 19 | "karma-coverage": "~0.1.4" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /public/bower_components/angular-route/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-route", 3 | "version": "1.2.14", 4 | "main": "./angular-route.js", 5 | "dependencies": { 6 | "angular": "1.2.14" 7 | }, 8 | "homepage": "https://github.com/angular/bower-angular-route", 9 | "_release": "1.2.14", 10 | "_resolution": { 11 | "type": "version", 12 | "tag": "v1.2.14", 13 | "commit": "2a998317521fb468b8b69a4a29e6be2d19bc6a3e" 14 | }, 15 | "_source": "git://github.com/angular/bower-angular-route.git", 16 | "_target": "~1.2.14", 17 | "_originalSource": "angular-route", 18 | "_direct": true 19 | } -------------------------------------------------------------------------------- /public/bower_components/angular-socket-io/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-socket-io", 3 | "version": "0.3.0", 4 | "main": "socket.js", 5 | "dependencies": { 6 | "angular": "~1.2.6" 7 | }, 8 | "devDependencies": { 9 | "angular-mocks": "~1.2.6" 10 | }, 11 | "homepage": "https://github.com/btford/angular-socket-io", 12 | "_release": "0.3.0", 13 | "_resolution": { 14 | "type": "version", 15 | "tag": "v0.3.0", 16 | "commit": "081289dbc426c87a57c141c70b2ede1e2315d894" 17 | }, 18 | "_source": "git://github.com/btford/angular-socket-io.git", 19 | "_target": "~0.3.0", 20 | "_originalSource": "angular-socket-io", 21 | "_direct": true 22 | } -------------------------------------------------------------------------------- /views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block body 4 | div(ng-controller='AppCtrl') 5 | h2 Hello {{name}} 6 | ul.menu 7 | li 8 | a(href='view1') view1 9 | li 10 | a(href='view2') view2 11 | 12 | div(ng-view) 13 | 14 | div 15 | | Angular Socket.io seed app: v 16 | span(app-version) 17 | 18 | script(src='/socket.io/socket.io.js') 19 | script(src='bower_components/angular/angular.js') 20 | script(src='bower_components/angular-route/angular-route.js') 21 | script(src='bower_components/angular-socket-io/socket.js') 22 | script(src='js/app.js') 23 | script(src='js/services.js') 24 | script(src='js/controllers.js') 25 | script(src='js/filters.js') 26 | script(src='js/directives.js') 27 | -------------------------------------------------------------------------------- /public/js/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Declare app level module which depends on filters, and services 4 | 5 | angular.module('myApp', [ 6 | 'ngRoute', 7 | 8 | 'myApp.controllers', 9 | 'myApp.filters', 10 | 'myApp.services', 11 | 'myApp.directives', 12 | 13 | // 3rd party dependencies 14 | 'btford.socket-io' 15 | ]). 16 | config(function ($routeProvider, $locationProvider) { 17 | $routeProvider. 18 | when('/view1', { 19 | templateUrl: 'partials/partial1', 20 | controller: 'MyCtrl1' 21 | }). 22 | when('/view2', { 23 | templateUrl: 'partials/partial2', 24 | controller: 'MyCtrl2' 25 | }). 26 | otherwise({ 27 | redirectTo: '/view1' 28 | }); 29 | 30 | $locationProvider.html5Mode(true); 31 | }); 32 | -------------------------------------------------------------------------------- /public/bower_components/angular-socket-io/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | 3 | module.exports = function (config) { 4 | config.set({ 5 | basePath: '', 6 | files: [ 7 | 'mock/socket-io.js', 8 | 'bower_components/angular/angular.js', 9 | 'bower_components/angular-mocks/angular-mocks.js', 10 | 'socket.js', 11 | '*.spec.js' 12 | ], 13 | 14 | preprocessors: { 15 | 'socket.js': ['coverage'] 16 | }, 17 | 18 | reporters: ['progress', 'coverage'], 19 | 20 | port: 9876, 21 | colors: true, 22 | 23 | logLevel: config.LOG_INFO, 24 | 25 | browsers: ['Chrome'], 26 | frameworks: ['jasmine'], 27 | 28 | captureTimeout: 60000, 29 | 30 | autoWatch: true, 31 | singleRun: false 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies 4 | */ 5 | 6 | var express = require('express'), 7 | routes = require('./routes'), 8 | api = require('./routes/api'), 9 | http = require('http'), 10 | path = require('path'); 11 | 12 | var app = module.exports = express(); 13 | var server = require('http').createServer(app); 14 | var io = require('socket.io').listen(server); 15 | 16 | /** 17 | * Configuration 18 | */ 19 | 20 | // all environments 21 | app.set('port', process.env.PORT || 3000); 22 | app.set('views', __dirname + '/views'); 23 | app.set('view engine', 'jade'); 24 | app.use(express.logger('dev')); 25 | app.use(express.bodyParser()); 26 | app.use(express.methodOverride()); 27 | app.use(express.static(path.join(__dirname, 'public'))); 28 | app.use(app.router); 29 | 30 | // development only 31 | if (app.get('env') === 'development') { 32 | app.use(express.errorHandler()); 33 | } 34 | 35 | // production only 36 | if (app.get('env') === 'production') { 37 | // TODO 38 | }; 39 | 40 | 41 | /** 42 | * Routes 43 | */ 44 | 45 | // serve index and view partials 46 | app.get('/', routes.index); 47 | app.get('/partials/:name', routes.partials); 48 | 49 | // JSON API 50 | app.get('/api/name', api.name); 51 | 52 | // redirect all others to the index (HTML5 history) 53 | app.get('*', routes.index); 54 | 55 | // Socket.io Communication 56 | io.sockets.on('connection', require('./routes/socket')); 57 | 58 | /** 59 | * Start Server 60 | */ 61 | 62 | server.listen(app.get('port'), function () { 63 | console.log('Express server listening on port ' + app.get('port')); 64 | }); 65 | -------------------------------------------------------------------------------- /public/bower_components/angular/README.md: -------------------------------------------------------------------------------- 1 | # bower-angular 2 | 3 | This repo is for distribution on `bower`. The source for this module is in the 4 | [main AngularJS repo](https://github.com/angular/angular.js). 5 | Please file issues and pull requests against that repo. 6 | 7 | ## Install 8 | 9 | Install with `bower`: 10 | 11 | ```shell 12 | bower install angular 13 | ``` 14 | 15 | Add a ` 19 | ``` 20 | 21 | ## Documentation 22 | 23 | Documentation is available on the 24 | [AngularJS docs site](http://docs.angularjs.org/). 25 | 26 | ## License 27 | 28 | The MIT License 29 | 30 | Copyright (c) 2010-2012 Google, Inc. http://angularjs.org 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining a copy 33 | of this software and associated documentation files (the "Software"), to deal 34 | in the Software without restriction, including without limitation the rights 35 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 36 | copies of the Software, and to permit persons to whom the Software is 37 | furnished to do so, subject to the following conditions: 38 | 39 | The above copyright notice and this permission notice shall be included in 40 | all copies or substantial portions of the Software. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 44 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 45 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 46 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 47 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 48 | THE SOFTWARE. 49 | -------------------------------------------------------------------------------- /public/bower_components/angular-route/README.md: -------------------------------------------------------------------------------- 1 | # bower-angular-route 2 | 3 | This repo is for distribution on `bower`. The source for this module is in the 4 | [main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngRoute). 5 | Please file issues and pull requests against that repo. 6 | 7 | ## Install 8 | 9 | Install with `bower`: 10 | 11 | ```shell 12 | bower install angular-route 13 | ``` 14 | 15 | Add a ` 19 | ``` 20 | 21 | And add `ngRoute` as a dependency for your app: 22 | 23 | ```javascript 24 | angular.module('myApp', ['ngRoute']); 25 | ``` 26 | 27 | ## Documentation 28 | 29 | Documentation is available on the 30 | [AngularJS docs site](http://docs.angularjs.org/api/ngRoute). 31 | 32 | ## License 33 | 34 | The MIT License 35 | 36 | Copyright (c) 2010-2012 Google, Inc. http://angularjs.org 37 | 38 | Permission is hereby granted, free of charge, to any person obtaining a copy 39 | of this software and associated documentation files (the "Software"), to deal 40 | in the Software without restriction, including without limitation the rights 41 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 42 | copies of the Software, and to permit persons to whom the Software is 43 | furnished to do so, subject to the following conditions: 44 | 45 | The above copyright notice and this permission notice shall be included in 46 | all copies or substantial portions of the Software. 47 | 48 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 49 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 50 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 51 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 52 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 53 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 54 | THE SOFTWARE. 55 | -------------------------------------------------------------------------------- /public/bower_components/angular-socket-io/socket.js: -------------------------------------------------------------------------------- 1 | /* 2 | * angular-socket-io v0.3.0 3 | * (c) 2014 Brian Ford http://briantford.com 4 | * License: MIT 5 | */ 6 | 7 | 'use strict'; 8 | 9 | angular.module('btford.socket-io', []). 10 | provider('socketFactory', function () { 11 | 12 | // when forwarding events, prefix the event name 13 | var defaultPrefix = 'socket:', 14 | ioSocket; 15 | 16 | // expose to provider 17 | this.$get = function ($rootScope, $timeout) { 18 | 19 | var asyncAngularify = function (socket, callback) { 20 | return callback ? function () { 21 | var args = arguments; 22 | $timeout(function () { 23 | callback.apply(socket, args); 24 | }, 0); 25 | } : angular.noop; 26 | }; 27 | 28 | return function socketFactory (options) { 29 | options = options || {}; 30 | var socket = options.ioSocket || io.connect(); 31 | var prefix = options.prefix || defaultPrefix; 32 | var defaultScope = options.scope || $rootScope; 33 | 34 | var addListener = function (eventName, callback) { 35 | socket.on(eventName, asyncAngularify(socket, callback)); 36 | }; 37 | 38 | var wrappedSocket = { 39 | on: addListener, 40 | addListener: addListener, 41 | 42 | emit: function (eventName, data, callback) { 43 | return socket.emit(eventName, data, asyncAngularify(socket, callback)); 44 | }, 45 | 46 | removeListener: function () { 47 | return socket.removeListener.apply(socket, arguments); 48 | }, 49 | 50 | // when socket.on('someEvent', fn (data) { ... }), 51 | // call scope.$broadcast('someEvent', data) 52 | forward: function (events, scope) { 53 | if (events instanceof Array === false) { 54 | events = [events]; 55 | } 56 | if (!scope) { 57 | scope = defaultScope; 58 | } 59 | events.forEach(function (eventName) { 60 | var prefixedEvent = prefix + eventName; 61 | var forwardBroadcast = asyncAngularify(socket, function (data) { 62 | scope.$broadcast(prefixedEvent, data); 63 | }); 64 | scope.$on('$destroy', function () { 65 | socket.removeListener(eventName, forwardBroadcast); 66 | }); 67 | socket.on(eventName, forwardBroadcast); 68 | }); 69 | } 70 | }; 71 | 72 | return wrappedSocket; 73 | }; 74 | }; 75 | }); 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular Socket.io Seed 2 | 3 | Start an awesome app with AngularJS on the front, Socket.io + Express + Node on the back. This 4 | project is an application skeleton for writing [AngularJS](http://angularjs.org/) apps that use 5 | web sockets to add real-time functionality. If you're not planning on using web sockets, you 6 | should consider the [Angular Express Seed](https://github.com/btford/angular-express-seed) instead. 7 | 8 | The seed contains angular libraries, test libraries and a bunch of scripts all preconfigured for 9 | instant web development gratification. Just clone the repo (or download the zip/tarball) and 10 | you're ready to develop your application. 11 | 12 | The seed app shows how to wire together Angular client-side components with Socket.io and Express 13 | on the server. It also illustrates writing angular partials/views with the Jade templating library. 14 | 15 | _Note: Although Jade supports interpolation, you should be doing that mostly on the client. Mixing 16 | server and browser templating will convolute your app. Instead, use Jade as a syntactic sugar for 17 | HTML, and let AngularJS take care of interpolation on the browser side._ 18 | 19 | ## How to use it 20 | 21 | Clone the angular-socket-io-seed repository and start hacking! 22 | 23 | ### Running the app 24 | 25 | Runs like a typical express app: 26 | 27 | ```shell 28 | node app.js 29 | ``` 30 | 31 | ### Running tests 32 | 33 | Coming soon! 34 | 35 | ### Receiving updates from upstream 36 | 37 | Just fetch the changes and merge them into your project with git. 38 | 39 | ### Updating `angular.js` 40 | 41 | Alternatively, you can update AngularJS with [Bower](http://bower.io): 42 | 43 | ```shell 44 | bower update angular 45 | ``` 46 | 47 | ## Example Application 48 | 49 | I created a [simple instant messaging application](https://github.com/btford/angular-socket-io-im) 50 | and wrote a [blog post](http://briantford.com/blog/angular-socket-io.html) walking through the app to 51 | illustrate using the seed. 52 | 53 | ## Directory Layout 54 | 55 | app.js --> app config 56 | bower.json --> for bower 57 | package.json --> for npm 58 | public/ --> all of the files to be used in on the client side 59 | css/ --> css files 60 | app.css --> default stylesheet 61 | img/ --> image files 62 | js/ --> javascript files 63 | app.js --> declare top-level app module 64 | controllers.js --> application controllers 65 | directives.js --> custom angular directives 66 | filters.js --> custom angular filters 67 | services.js --> custom angular services 68 | bower_components/ 69 | angular/ --> angular.js 70 | angular-socket-io/ --> socket.io adapter for angular 71 | routes/ 72 | index.js --> route for serving HTML pages and partials 73 | views/ 74 | index.jade --> main page for app 75 | layout.jade --> doctype, title, head boilerplate 76 | partials/ --> angular view partials (partial jade templates) 77 | partial1.jade 78 | partial2.jade 79 | 80 | 81 | 82 | ## Contact 83 | 84 | For more information on AngularJS please check out http://angularjs.org/ 85 | For more on Express and Jade, http://expressjs.com/ and http://jade-lang.com/ are 86 | your friends. 87 | -------------------------------------------------------------------------------- /public/bower_components/angular-socket-io/socket.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * angular-socket-io v0.3.0 3 | * (c) 2014 Brian Ford http://briantford.com 4 | * License: MIT 5 | */ 6 | 7 | 'use strict'; 8 | 9 | 10 | describe('socketFactory', function () { 11 | 12 | beforeEach(module('btford.socket-io')); 13 | 14 | var socket, 15 | scope, 16 | $timeout, 17 | $browser, 18 | mockIoSocket, 19 | spy; 20 | 21 | beforeEach(inject(function (socketFactory, _$browser_, $rootScope, _$timeout_) { 22 | $browser = _$browser_; 23 | $timeout = _$timeout_; 24 | scope = $rootScope.$new(); 25 | spy = jasmine.createSpy('emitSpy'); 26 | mockIoSocket = io.connect(); 27 | socket = socketFactory({ 28 | ioSocket: mockIoSocket, 29 | scope: scope 30 | }); 31 | })); 32 | 33 | 34 | describe('#on', function () { 35 | 36 | it('should apply asynchronously', function () { 37 | socket.on('event', spy); 38 | 39 | mockIoSocket.emit('event'); 40 | 41 | expect(spy).not.toHaveBeenCalled(); 42 | $timeout.flush(); 43 | 44 | expect(spy).toHaveBeenCalled(); 45 | }); 46 | 47 | }); 48 | 49 | 50 | describe('#emit', function () { 51 | 52 | it('should call the delegate socket\'s emit', function () { 53 | spyOn(mockIoSocket, 'emit'); 54 | 55 | socket.emit('event', {foo: 'bar'}); 56 | 57 | expect(mockIoSocket.emit).toHaveBeenCalled(); 58 | }); 59 | 60 | }); 61 | 62 | 63 | describe('#removeListener', function () { 64 | 65 | it('should not call after removing an event', function () { 66 | socket.on('event', spy); 67 | socket.removeListener('event', spy); 68 | 69 | mockIoSocket.emit('event'); 70 | 71 | expect($browser.deferredFns.length).toBe(0); 72 | }); 73 | 74 | }); 75 | 76 | 77 | describe('#forward', function () { 78 | 79 | it('should forward events', function () { 80 | socket.forward('event'); 81 | 82 | scope.$on('socket:event', spy); 83 | mockIoSocket.emit('event'); 84 | $timeout.flush(); 85 | 86 | expect(spy).toHaveBeenCalled(); 87 | }); 88 | 89 | it('should forward an array of events', function () { 90 | socket.forward(['e1', 'e2']); 91 | 92 | scope.$on('socket:e1', spy); 93 | scope.$on('socket:e2', spy); 94 | 95 | mockIoSocket.emit('e1'); 96 | mockIoSocket.emit('e2'); 97 | $timeout.flush(); 98 | expect(spy.callCount).toBe(2); 99 | }); 100 | 101 | it('should remove watchers when the scope is removed', function () { 102 | 103 | socket.forward('event'); 104 | scope.$on('socket:event', spy); 105 | mockIoSocket.emit('event'); 106 | $timeout.flush(); 107 | 108 | expect(spy).toHaveBeenCalled(); 109 | 110 | scope.$destroy(); 111 | spy.reset(); 112 | mockIoSocket.emit('event'); 113 | expect(spy).not.toHaveBeenCalled(); 114 | }); 115 | 116 | it('should use the specified prefix', inject(function (socketFactory) { 117 | var socket = socketFactory({ 118 | ioSocket: mockIoSocket, 119 | scope: scope, 120 | prefix: 'custom:' 121 | }); 122 | 123 | socket.forward('event'); 124 | 125 | scope.$on('custom:event', spy); 126 | mockIoSocket.emit('event'); 127 | $timeout.flush(); 128 | 129 | expect(spy).toHaveBeenCalled(); 130 | })); 131 | 132 | it('should forward to the specified scope when one is provided', function () { 133 | var child = scope.$new(); 134 | spyOn(child, '$broadcast'); 135 | socket.forward('event', child); 136 | 137 | scope.$on('socket:event', spy); 138 | mockIoSocket.emit('event'); 139 | $timeout.flush(); 140 | 141 | expect(child.$broadcast).toHaveBeenCalled(); 142 | }); 143 | }); 144 | 145 | }); 146 | -------------------------------------------------------------------------------- /public/bower_components/angular-route/angular-route.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.14 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(n,e,A){'use strict';function x(s,g,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,w){function y(){p&&(p.remove(),p=null);h&&(h.$destroy(),h=null);l&&(k.leave(l,function(){p=null}),p=l,l=null)}function v(){var b=s.current&&s.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),d=s.current;l=w(b,function(d){k.enter(d,null,l||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||g()});y()});h=d.scope=b;h.$emit("$viewContentLoaded");h.$eval(u)}else y()} 7 | var h,l,p,t=b.autoscroll,u=b.onload||"";a.$on("$routeChangeSuccess",v);v()}}}function z(e,g,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var w=e(c.contents());b.controller&&(f.$scope=a,f=g(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));w(a)}}}n=e.module("ngRoute",["ng"]).provider("$route",function(){function s(a,c){return e.extend(new (e.extend(function(){}, 8 | {prototype:a})),c)}function g(a,e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},k=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;k.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&g(a,c));if(a){var b= 9 | "/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";k[b]=e.extend({redirectTo:a},g(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,g,n,v,h){function l(){var d=p(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!u)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)u=!1,a.$broadcast("$routeChangeStart", 10 | d,m),(r.current=d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(t(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?g.get(d):g.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=h.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl= 11 | b,c=n.get(b,{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function p(){var a,b;e.forEach(k,function(f,k){var q;if(q=!b){var g=c.path();q=f.keys;var l={};if(f.regexp)if(g=f.regexp.exec(g)){for(var h=1,p=g.length;h 22 | */ 23 | /* global -ngRouteModule */ 24 | var ngRouteModule = angular.module('ngRoute', ['ng']). 25 | provider('$route', $RouteProvider); 26 | 27 | /** 28 | * @ngdoc provider 29 | * @name $routeProvider 30 | * @function 31 | * 32 | * @description 33 | * 34 | * Used for configuring routes. 35 | * 36 | * ## Example 37 | * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`. 38 | * 39 | * ## Dependencies 40 | * Requires the {@link ngRoute `ngRoute`} module to be installed. 41 | */ 42 | function $RouteProvider(){ 43 | function inherit(parent, extra) { 44 | return angular.extend(new (angular.extend(function() {}, {prototype:parent}))(), extra); 45 | } 46 | 47 | var routes = {}; 48 | 49 | /** 50 | * @ngdoc method 51 | * @name $routeProvider#when 52 | * 53 | * @param {string} path Route path (matched against `$location.path`). If `$location.path` 54 | * contains redundant trailing slash or is missing one, the route will still match and the 55 | * `$location.path` will be updated to add or drop the trailing slash to exactly match the 56 | * route definition. 57 | * 58 | * * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up 59 | * to the next slash are matched and stored in `$routeParams` under the given `name` 60 | * when the route matches. 61 | * * `path` can contain named groups starting with a colon and ending with a star: 62 | * e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name` 63 | * when the route matches. 64 | * * `path` can contain optional named groups with a question mark: e.g.`:name?`. 65 | * 66 | * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match 67 | * `/color/brown/largecode/code/with/slashes/edit` and extract: 68 | * 69 | * * `color: brown` 70 | * * `largecode: code/with/slashes`. 71 | * 72 | * 73 | * @param {Object} route Mapping information to be assigned to `$route.current` on route 74 | * match. 75 | * 76 | * Object properties: 77 | * 78 | * - `controller` – `{(string|function()=}` – Controller fn that should be associated with 79 | * newly created scope or the name of a {@link angular.Module#controller registered 80 | * controller} if passed as a string. 81 | * - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be 82 | * published to scope under the `controllerAs` name. 83 | * - `template` – `{string=|function()=}` – html template as a string or a function that 84 | * returns an html template as a string which should be used by {@link 85 | * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives. 86 | * This property takes precedence over `templateUrl`. 87 | * 88 | * If `template` is a function, it will be called with the following parameters: 89 | * 90 | * - `{Array.<Object>}` - route parameters extracted from the current 91 | * `$location.path()` by applying the current route 92 | * 93 | * - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html 94 | * template that should be used by {@link ngRoute.directive:ngView ngView}. 95 | * 96 | * If `templateUrl` is a function, it will be called with the following parameters: 97 | * 98 | * - `{Array.<Object>}` - route parameters extracted from the current 99 | * `$location.path()` by applying the current route 100 | * 101 | * - `resolve` - `{Object.=}` - An optional map of dependencies which should 102 | * be injected into the controller. If any of these dependencies are promises, the router 103 | * will wait for them all to be resolved or one to be rejected before the controller is 104 | * instantiated. 105 | * If all the promises are resolved successfully, the values of the resolved promises are 106 | * injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is 107 | * fired. If any of the promises are rejected the 108 | * {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. The map object 109 | * is: 110 | * 111 | * - `key` – `{string}`: a name of a dependency to be injected into the controller. 112 | * - `factory` - `{string|function}`: If `string` then it is an alias for a service. 113 | * Otherwise if function, then it is {@link auto.$injector#invoke injected} 114 | * and the return value is treated as the dependency. If the result is a promise, it is 115 | * resolved before its value is injected into the controller. Be aware that 116 | * `ngRoute.$routeParams` will still refer to the previous route within these resolve 117 | * functions. Use `$route.current.params` to access the new route parameters, instead. 118 | * 119 | * - `redirectTo` – {(string|function())=} – value to update 120 | * {@link ng.$location $location} path with and trigger route redirection. 121 | * 122 | * If `redirectTo` is a function, it will be called with the following parameters: 123 | * 124 | * - `{Object.}` - route parameters extracted from the current 125 | * `$location.path()` by applying the current route templateUrl. 126 | * - `{string}` - current `$location.path()` 127 | * - `{Object}` - current `$location.search()` 128 | * 129 | * The custom `redirectTo` function is expected to return a string which will be used 130 | * to update `$location.path()` and `$location.search()`. 131 | * 132 | * - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()` 133 | * or `$location.hash()` changes. 134 | * 135 | * If the option is set to `false` and url in the browser changes, then 136 | * `$routeUpdate` event is broadcasted on the root scope. 137 | * 138 | * - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive 139 | * 140 | * If the option is set to `true`, then the particular route can be matched without being 141 | * case sensitive 142 | * 143 | * @returns {Object} self 144 | * 145 | * @description 146 | * Adds a new route definition to the `$route` service. 147 | */ 148 | this.when = function(path, route) { 149 | routes[path] = angular.extend( 150 | {reloadOnSearch: true}, 151 | route, 152 | path && pathRegExp(path, route) 153 | ); 154 | 155 | // create redirection for trailing slashes 156 | if (path) { 157 | var redirectPath = (path[path.length-1] == '/') 158 | ? path.substr(0, path.length-1) 159 | : path +'/'; 160 | 161 | routes[redirectPath] = angular.extend( 162 | {redirectTo: path}, 163 | pathRegExp(redirectPath, route) 164 | ); 165 | } 166 | 167 | return this; 168 | }; 169 | 170 | /** 171 | * @param path {string} path 172 | * @param opts {Object} options 173 | * @return {?Object} 174 | * 175 | * @description 176 | * Normalizes the given path, returning a regular expression 177 | * and the original path. 178 | * 179 | * Inspired by pathRexp in visionmedia/express/lib/utils.js. 180 | */ 181 | function pathRegExp(path, opts) { 182 | var insensitive = opts.caseInsensitiveMatch, 183 | ret = { 184 | originalPath: path, 185 | regexp: path 186 | }, 187 | keys = ret.keys = []; 188 | 189 | path = path 190 | .replace(/([().])/g, '\\$1') 191 | .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option){ 192 | var optional = option === '?' ? option : null; 193 | var star = option === '*' ? option : null; 194 | keys.push({ name: key, optional: !!optional }); 195 | slash = slash || ''; 196 | return '' 197 | + (optional ? '' : slash) 198 | + '(?:' 199 | + (optional ? slash : '') 200 | + (star && '(.+?)' || '([^/]+)') 201 | + (optional || '') 202 | + ')' 203 | + (optional || ''); 204 | }) 205 | .replace(/([\/$\*])/g, '\\$1'); 206 | 207 | ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : ''); 208 | return ret; 209 | } 210 | 211 | /** 212 | * @ngdoc method 213 | * @name $routeProvider#otherwise 214 | * 215 | * @description 216 | * Sets route definition that will be used on route change when no other route definition 217 | * is matched. 218 | * 219 | * @param {Object} params Mapping information to be assigned to `$route.current`. 220 | * @returns {Object} self 221 | */ 222 | this.otherwise = function(params) { 223 | this.when(null, params); 224 | return this; 225 | }; 226 | 227 | 228 | this.$get = ['$rootScope', 229 | '$location', 230 | '$routeParams', 231 | '$q', 232 | '$injector', 233 | '$http', 234 | '$templateCache', 235 | '$sce', 236 | function($rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) { 237 | 238 | /** 239 | * @ngdoc service 240 | * @name $route 241 | * @requires $location 242 | * @requires $routeParams 243 | * 244 | * @property {Object} current Reference to the current route definition. 245 | * The route definition contains: 246 | * 247 | * - `controller`: The controller constructor as define in route definition. 248 | * - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for 249 | * controller instantiation. The `locals` contain 250 | * the resolved values of the `resolve` map. Additionally the `locals` also contain: 251 | * 252 | * - `$scope` - The current route scope. 253 | * - `$template` - The current route template HTML. 254 | * 255 | * @property {Array.<Object>} routes Array of all configured routes. 256 | * 257 | * @description 258 | * `$route` is used for deep-linking URLs to controllers and views (HTML partials). 259 | * It watches `$location.url()` and tries to map the path to an existing route definition. 260 | * 261 | * Requires the {@link ngRoute `ngRoute`} module to be installed. 262 | * 263 | * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API. 264 | * 265 | * The `$route` service is typically used in conjunction with the 266 | * {@link ngRoute.directive:ngView `ngView`} directive and the 267 | * {@link ngRoute.$routeParams `$routeParams`} service. 268 | * 269 | * @example 270 | This example shows how changing the URL hash causes the `$route` to match a route against the 271 | URL, and the `ngView` pulls in the partial. 272 | 273 | Note that this example is using {@link ng.directive:script inlined templates} 274 | to get it working on jsfiddle as well. 275 | 276 | 277 | 278 |
279 | Choose: 280 | Moby | 281 | Moby: Ch1 | 282 | Gatsby | 283 | Gatsby: Ch4 | 284 | Scarlet Letter
285 | 286 |
287 |
288 | 289 |
$location.path() = {{$location.path()}}
290 |
$route.current.templateUrl = {{$route.current.templateUrl}}
291 |
$route.current.params = {{$route.current.params}}
292 |
$route.current.scope.name = {{$route.current.scope.name}}
293 |
$routeParams = {{$routeParams}}
294 |
295 |
296 | 297 | 298 | controller: {{name}}
299 | Book Id: {{params.bookId}}
300 |
301 | 302 | 303 | controller: {{name}}
304 | Book Id: {{params.bookId}}
305 | Chapter Id: {{params.chapterId}} 306 |
307 | 308 | 309 | angular.module('ngRouteExample', ['ngRoute']) 310 | 311 | .config(function($routeProvider, $locationProvider) { 312 | $routeProvider.when('/Book/:bookId', { 313 | templateUrl: 'book.html', 314 | controller: BookCntl, 315 | resolve: { 316 | // I will cause a 1 second delay 317 | delay: function($q, $timeout) { 318 | var delay = $q.defer(); 319 | $timeout(delay.resolve, 1000); 320 | return delay.promise; 321 | } 322 | } 323 | }); 324 | $routeProvider.when('/Book/:bookId/ch/:chapterId', { 325 | templateUrl: 'chapter.html', 326 | controller: ChapterCntl 327 | }); 328 | 329 | // configure html5 to get links working on jsfiddle 330 | $locationProvider.html5Mode(true); 331 | }); 332 | 333 | function MainCntl($scope, $route, $routeParams, $location) { 334 | $scope.$route = $route; 335 | $scope.$location = $location; 336 | $scope.$routeParams = $routeParams; 337 | } 338 | 339 | function BookCntl($scope, $routeParams) { 340 | $scope.name = "BookCntl"; 341 | $scope.params = $routeParams; 342 | } 343 | 344 | function ChapterCntl($scope, $routeParams) { 345 | $scope.name = "ChapterCntl"; 346 | $scope.params = $routeParams; 347 | } 348 | 349 | 350 | 351 | it('should load and compile correct template', function() { 352 | element(by.linkText('Moby: Ch1')).click(); 353 | var content = element(by.css('[ng-view]')).getText(); 354 | expect(content).toMatch(/controller\: ChapterCntl/); 355 | expect(content).toMatch(/Book Id\: Moby/); 356 | expect(content).toMatch(/Chapter Id\: 1/); 357 | 358 | element(by.partialLinkText('Scarlet')).click(); 359 | 360 | content = element(by.css('[ng-view]')).getText(); 361 | expect(content).toMatch(/controller\: BookCntl/); 362 | expect(content).toMatch(/Book Id\: Scarlet/); 363 | }); 364 | 365 |
366 | */ 367 | 368 | /** 369 | * @ngdoc event 370 | * @name $route#$routeChangeStart 371 | * @eventType broadcast on root scope 372 | * @description 373 | * Broadcasted before a route change. At this point the route services starts 374 | * resolving all of the dependencies needed for the route change to occur. 375 | * Typically this involves fetching the view template as well as any dependencies 376 | * defined in `resolve` route property. Once all of the dependencies are resolved 377 | * `$routeChangeSuccess` is fired. 378 | * 379 | * @param {Object} angularEvent Synthetic event object. 380 | * @param {Route} next Future route information. 381 | * @param {Route} current Current route information. 382 | */ 383 | 384 | /** 385 | * @ngdoc event 386 | * @name $route#$routeChangeSuccess 387 | * @eventType broadcast on root scope 388 | * @description 389 | * Broadcasted after a route dependencies are resolved. 390 | * {@link ngRoute.directive:ngView ngView} listens for the directive 391 | * to instantiate the controller and render the view. 392 | * 393 | * @param {Object} angularEvent Synthetic event object. 394 | * @param {Route} current Current route information. 395 | * @param {Route|Undefined} previous Previous route information, or undefined if current is 396 | * first route entered. 397 | */ 398 | 399 | /** 400 | * @ngdoc event 401 | * @name $route#$routeChangeError 402 | * @eventType broadcast on root scope 403 | * @description 404 | * Broadcasted if any of the resolve promises are rejected. 405 | * 406 | * @param {Object} angularEvent Synthetic event object 407 | * @param {Route} current Current route information. 408 | * @param {Route} previous Previous route information. 409 | * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise. 410 | */ 411 | 412 | /** 413 | * @ngdoc event 414 | * @name $route#$routeUpdate 415 | * @eventType broadcast on root scope 416 | * @description 417 | * 418 | * The `reloadOnSearch` property has been set to false, and we are reusing the same 419 | * instance of the Controller. 420 | */ 421 | 422 | var forceReload = false, 423 | $route = { 424 | routes: routes, 425 | 426 | /** 427 | * @ngdoc method 428 | * @name $route#reload 429 | * 430 | * @description 431 | * Causes `$route` service to reload the current route even if 432 | * {@link ng.$location $location} hasn't changed. 433 | * 434 | * As a result of that, {@link ngRoute.directive:ngView ngView} 435 | * creates new scope, reinstantiates the controller. 436 | */ 437 | reload: function() { 438 | forceReload = true; 439 | $rootScope.$evalAsync(updateRoute); 440 | } 441 | }; 442 | 443 | $rootScope.$on('$locationChangeSuccess', updateRoute); 444 | 445 | return $route; 446 | 447 | ///////////////////////////////////////////////////// 448 | 449 | /** 450 | * @param on {string} current url 451 | * @param route {Object} route regexp to match the url against 452 | * @return {?Object} 453 | * 454 | * @description 455 | * Check if the route matches the current url. 456 | * 457 | * Inspired by match in 458 | * visionmedia/express/lib/router/router.js. 459 | */ 460 | function switchRouteMatcher(on, route) { 461 | var keys = route.keys, 462 | params = {}; 463 | 464 | if (!route.regexp) return null; 465 | 466 | var m = route.regexp.exec(on); 467 | if (!m) return null; 468 | 469 | for (var i = 1, len = m.length; i < len; ++i) { 470 | var key = keys[i - 1]; 471 | 472 | var val = 'string' == typeof m[i] 473 | ? decodeURIComponent(m[i]) 474 | : m[i]; 475 | 476 | if (key && val) { 477 | params[key.name] = val; 478 | } 479 | } 480 | return params; 481 | } 482 | 483 | function updateRoute() { 484 | var next = parseRoute(), 485 | last = $route.current; 486 | 487 | if (next && last && next.$$route === last.$$route 488 | && angular.equals(next.pathParams, last.pathParams) 489 | && !next.reloadOnSearch && !forceReload) { 490 | last.params = next.params; 491 | angular.copy(last.params, $routeParams); 492 | $rootScope.$broadcast('$routeUpdate', last); 493 | } else if (next || last) { 494 | forceReload = false; 495 | $rootScope.$broadcast('$routeChangeStart', next, last); 496 | $route.current = next; 497 | if (next) { 498 | if (next.redirectTo) { 499 | if (angular.isString(next.redirectTo)) { 500 | $location.path(interpolate(next.redirectTo, next.params)).search(next.params) 501 | .replace(); 502 | } else { 503 | $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search())) 504 | .replace(); 505 | } 506 | } 507 | } 508 | 509 | $q.when(next). 510 | then(function() { 511 | if (next) { 512 | var locals = angular.extend({}, next.resolve), 513 | template, templateUrl; 514 | 515 | angular.forEach(locals, function(value, key) { 516 | locals[key] = angular.isString(value) ? 517 | $injector.get(value) : $injector.invoke(value); 518 | }); 519 | 520 | if (angular.isDefined(template = next.template)) { 521 | if (angular.isFunction(template)) { 522 | template = template(next.params); 523 | } 524 | } else if (angular.isDefined(templateUrl = next.templateUrl)) { 525 | if (angular.isFunction(templateUrl)) { 526 | templateUrl = templateUrl(next.params); 527 | } 528 | templateUrl = $sce.getTrustedResourceUrl(templateUrl); 529 | if (angular.isDefined(templateUrl)) { 530 | next.loadedTemplateUrl = templateUrl; 531 | template = $http.get(templateUrl, {cache: $templateCache}). 532 | then(function(response) { return response.data; }); 533 | } 534 | } 535 | if (angular.isDefined(template)) { 536 | locals['$template'] = template; 537 | } 538 | return $q.all(locals); 539 | } 540 | }). 541 | // after route change 542 | then(function(locals) { 543 | if (next == $route.current) { 544 | if (next) { 545 | next.locals = locals; 546 | angular.copy(next.params, $routeParams); 547 | } 548 | $rootScope.$broadcast('$routeChangeSuccess', next, last); 549 | } 550 | }, function(error) { 551 | if (next == $route.current) { 552 | $rootScope.$broadcast('$routeChangeError', next, last, error); 553 | } 554 | }); 555 | } 556 | } 557 | 558 | 559 | /** 560 | * @returns {Object} the current active route, by matching it against the URL 561 | */ 562 | function parseRoute() { 563 | // Match a route 564 | var params, match; 565 | angular.forEach(routes, function(route, path) { 566 | if (!match && (params = switchRouteMatcher($location.path(), route))) { 567 | match = inherit(route, { 568 | params: angular.extend({}, $location.search(), params), 569 | pathParams: params}); 570 | match.$$route = route; 571 | } 572 | }); 573 | // No route matched; fallback to "otherwise" route 574 | return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}}); 575 | } 576 | 577 | /** 578 | * @returns {string} interpolation of the redirect path with the parameters 579 | */ 580 | function interpolate(string, params) { 581 | var result = []; 582 | angular.forEach((string||'').split(':'), function(segment, i) { 583 | if (i === 0) { 584 | result.push(segment); 585 | } else { 586 | var segmentMatch = segment.match(/(\w+)(.*)/); 587 | var key = segmentMatch[1]; 588 | result.push(params[key]); 589 | result.push(segmentMatch[2] || ''); 590 | delete params[key]; 591 | } 592 | }); 593 | return result.join(''); 594 | } 595 | }]; 596 | } 597 | 598 | ngRouteModule.provider('$routeParams', $RouteParamsProvider); 599 | 600 | 601 | /** 602 | * @ngdoc service 603 | * @name $routeParams 604 | * @requires $route 605 | * 606 | * @description 607 | * The `$routeParams` service allows you to retrieve the current set of route parameters. 608 | * 609 | * Requires the {@link ngRoute `ngRoute`} module to be installed. 610 | * 611 | * The route parameters are a combination of {@link ng.$location `$location`}'s 612 | * {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}. 613 | * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched. 614 | * 615 | * In case of parameter name collision, `path` params take precedence over `search` params. 616 | * 617 | * The service guarantees that the identity of the `$routeParams` object will remain unchanged 618 | * (but its properties will likely change) even when a route change occurs. 619 | * 620 | * Note that the `$routeParams` are only updated *after* a route change completes successfully. 621 | * This means that you cannot rely on `$routeParams` being correct in route resolve functions. 622 | * Instead you can use `$route.current.params` to access the new route's parameters. 623 | * 624 | * @example 625 | * ```js 626 | * // Given: 627 | * // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby 628 | * // Route: /Chapter/:chapterId/Section/:sectionId 629 | * // 630 | * // Then 631 | * $routeParams ==> {chapterId:1, sectionId:2, search:'moby'} 632 | * ``` 633 | */ 634 | function $RouteParamsProvider() { 635 | this.$get = function() { return {}; }; 636 | } 637 | 638 | ngRouteModule.directive('ngView', ngViewFactory); 639 | ngRouteModule.directive('ngView', ngViewFillContentFactory); 640 | 641 | 642 | /** 643 | * @ngdoc directive 644 | * @name ngView 645 | * @restrict ECA 646 | * 647 | * @description 648 | * # Overview 649 | * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by 650 | * including the rendered template of the current route into the main layout (`index.html`) file. 651 | * Every time the current route changes, the included view changes with it according to the 652 | * configuration of the `$route` service. 653 | * 654 | * Requires the {@link ngRoute `ngRoute`} module to be installed. 655 | * 656 | * @animations 657 | * enter - animation is used to bring new content into the browser. 658 | * leave - animation is used to animate existing content away. 659 | * 660 | * The enter and leave animation occur concurrently. 661 | * 662 | * @scope 663 | * @priority 400 664 | * @param {string=} onload Expression to evaluate whenever the view updates. 665 | * 666 | * @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll 667 | * $anchorScroll} to scroll the viewport after the view is updated. 668 | * 669 | * - If the attribute is not set, disable scrolling. 670 | * - If the attribute is set without value, enable scrolling. 671 | * - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated 672 | * as an expression yields a truthy value. 673 | * @example 674 | 677 | 678 |
679 | Choose: 680 | Moby | 681 | Moby: Ch1 | 682 | Gatsby | 683 | Gatsby: Ch4 | 684 | Scarlet Letter
685 | 686 |
687 |
688 |
689 |
690 | 691 |
$location.path() = {{main.$location.path()}}
692 |
$route.current.templateUrl = {{main.$route.current.templateUrl}}
693 |
$route.current.params = {{main.$route.current.params}}
694 |
$route.current.scope.name = {{main.$route.current.scope.name}}
695 |
$routeParams = {{main.$routeParams}}
696 |
697 |
698 | 699 | 700 |
701 | controller: {{book.name}}
702 | Book Id: {{book.params.bookId}}
703 |
704 |
705 | 706 | 707 |
708 | controller: {{chapter.name}}
709 | Book Id: {{chapter.params.bookId}}
710 | Chapter Id: {{chapter.params.chapterId}} 711 |
712 |
713 | 714 | 715 | .view-animate-container { 716 | position:relative; 717 | height:100px!important; 718 | position:relative; 719 | background:white; 720 | border:1px solid black; 721 | height:40px; 722 | overflow:hidden; 723 | } 724 | 725 | .view-animate { 726 | padding:10px; 727 | } 728 | 729 | .view-animate.ng-enter, .view-animate.ng-leave { 730 | -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s; 731 | transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s; 732 | 733 | display:block; 734 | width:100%; 735 | border-left:1px solid black; 736 | 737 | position:absolute; 738 | top:0; 739 | left:0; 740 | right:0; 741 | bottom:0; 742 | padding:10px; 743 | } 744 | 745 | .view-animate.ng-enter { 746 | left:100%; 747 | } 748 | .view-animate.ng-enter.ng-enter-active { 749 | left:0; 750 | } 751 | .view-animate.ng-leave.ng-leave-active { 752 | left:-100%; 753 | } 754 | 755 | 756 | 757 | angular.module('ngViewExample', ['ngRoute', 'ngAnimate'], 758 | function($routeProvider, $locationProvider) { 759 | $routeProvider.when('/Book/:bookId', { 760 | templateUrl: 'book.html', 761 | controller: BookCntl, 762 | controllerAs: 'book' 763 | }); 764 | $routeProvider.when('/Book/:bookId/ch/:chapterId', { 765 | templateUrl: 'chapter.html', 766 | controller: ChapterCntl, 767 | controllerAs: 'chapter' 768 | }); 769 | 770 | // configure html5 to get links working on jsfiddle 771 | $locationProvider.html5Mode(true); 772 | }); 773 | 774 | function MainCntl($route, $routeParams, $location) { 775 | this.$route = $route; 776 | this.$location = $location; 777 | this.$routeParams = $routeParams; 778 | } 779 | 780 | function BookCntl($routeParams) { 781 | this.name = "BookCntl"; 782 | this.params = $routeParams; 783 | } 784 | 785 | function ChapterCntl($routeParams) { 786 | this.name = "ChapterCntl"; 787 | this.params = $routeParams; 788 | } 789 | 790 | 791 | 792 | it('should load and compile correct template', function() { 793 | element(by.linkText('Moby: Ch1')).click(); 794 | var content = element(by.css('[ng-view]')).getText(); 795 | expect(content).toMatch(/controller\: ChapterCntl/); 796 | expect(content).toMatch(/Book Id\: Moby/); 797 | expect(content).toMatch(/Chapter Id\: 1/); 798 | 799 | element(by.partialLinkText('Scarlet')).click(); 800 | 801 | content = element(by.css('[ng-view]')).getText(); 802 | expect(content).toMatch(/controller\: BookCntl/); 803 | expect(content).toMatch(/Book Id\: Scarlet/); 804 | }); 805 | 806 |
807 | */ 808 | 809 | 810 | /** 811 | * @ngdoc event 812 | * @name ngView#$viewContentLoaded 813 | * @eventType emit on the current ngView scope 814 | * @description 815 | * Emitted every time the ngView content is reloaded. 816 | */ 817 | ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate']; 818 | function ngViewFactory( $route, $anchorScroll, $animate) { 819 | return { 820 | restrict: 'ECA', 821 | terminal: true, 822 | priority: 400, 823 | transclude: 'element', 824 | link: function(scope, $element, attr, ctrl, $transclude) { 825 | var currentScope, 826 | currentElement, 827 | previousElement, 828 | autoScrollExp = attr.autoscroll, 829 | onloadExp = attr.onload || ''; 830 | 831 | scope.$on('$routeChangeSuccess', update); 832 | update(); 833 | 834 | function cleanupLastView() { 835 | if(previousElement) { 836 | previousElement.remove(); 837 | previousElement = null; 838 | } 839 | if(currentScope) { 840 | currentScope.$destroy(); 841 | currentScope = null; 842 | } 843 | if(currentElement) { 844 | $animate.leave(currentElement, function() { 845 | previousElement = null; 846 | }); 847 | previousElement = currentElement; 848 | currentElement = null; 849 | } 850 | } 851 | 852 | function update() { 853 | var locals = $route.current && $route.current.locals, 854 | template = locals && locals.$template; 855 | 856 | if (angular.isDefined(template)) { 857 | var newScope = scope.$new(); 858 | var current = $route.current; 859 | 860 | // Note: This will also link all children of ng-view that were contained in the original 861 | // html. If that content contains controllers, ... they could pollute/change the scope. 862 | // However, using ng-view on an element with additional content does not make sense... 863 | // Note: We can't remove them in the cloneAttchFn of $transclude as that 864 | // function is called before linking the content, which would apply child 865 | // directives to non existing elements. 866 | var clone = $transclude(newScope, function(clone) { 867 | $animate.enter(clone, null, currentElement || $element, function onNgViewEnter () { 868 | if (angular.isDefined(autoScrollExp) 869 | && (!autoScrollExp || scope.$eval(autoScrollExp))) { 870 | $anchorScroll(); 871 | } 872 | }); 873 | cleanupLastView(); 874 | }); 875 | 876 | currentElement = clone; 877 | currentScope = current.scope = newScope; 878 | currentScope.$emit('$viewContentLoaded'); 879 | currentScope.$eval(onloadExp); 880 | } else { 881 | cleanupLastView(); 882 | } 883 | } 884 | } 885 | }; 886 | } 887 | 888 | // This directive is called during the $transclude call of the first `ngView` directive. 889 | // It will replace and compile the content of the element with the loaded template. 890 | // We need this directive so that the element content is already filled when 891 | // the link function of another directive on the same element as ngView 892 | // is called. 893 | ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route']; 894 | function ngViewFillContentFactory($compile, $controller, $route) { 895 | return { 896 | restrict: 'ECA', 897 | priority: -400, 898 | link: function(scope, $element) { 899 | var current = $route.current, 900 | locals = current.locals; 901 | 902 | $element.html(locals.$template); 903 | 904 | var link = $compile($element.contents()); 905 | 906 | if (current.controller) { 907 | locals.$scope = scope; 908 | var controller = $controller(current.controller, locals); 909 | if (current.controllerAs) { 910 | scope[current.controllerAs] = controller; 911 | } 912 | $element.data('$ngControllerController', controller); 913 | $element.children().data('$ngControllerController', controller); 914 | } 915 | 916 | link(scope); 917 | } 918 | }; 919 | } 920 | 921 | 922 | })(window, window.angular); 923 | -------------------------------------------------------------------------------- /public/bower_components/angular/angular.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.14 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(D,T,s){'use strict';function F(b){return function(){var a=arguments[0],c,a="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.2.14/"+(b?b+"/":"")+a;for(c=1;c").append(b).html();try{return 3===b[0].nodeType?O(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/, 15 | function(a,b){return"<"+O(b)})}catch(d){return O(c)}}function Wb(b){try{return decodeURIComponent(b)}catch(a){}}function Xb(b){var a={},c,d;r((b||"").split("&"),function(b){b&&(c=b.split("="),d=Wb(c[0]),v(d)&&(b=v(c[1])?Wb(c[1]):!0,a[d]?I(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function Yb(b){var a=[];r(b,function(b,d){I(b)?r(b,function(b){a.push(ua(d,!0)+(!0===b?"":"="+ua(b,!0)))}):a.push(ua(d,!0)+(!0===b?"":"="+ua(b,!0)))});return a.length?a.join("&"):""}function wb(b){return ua(b, 16 | !0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function ua(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function Uc(b,a){function c(a){a&&d.push(a)}var d=[b],e,f,g=["ng:app","ng-app","x-ng-app","data-ng-app"],h=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;r(g,function(a){g[a]=!0;c(T.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(r(b.querySelectorAll("."+a),c),r(b.querySelectorAll("."+ 17 | a+"\\:"),c),r(b.querySelectorAll("["+a+"]"),c))});r(d,function(a){if(!e){var b=h.exec(" "+a.className+" ");b?(e=a,f=(b[2]||"").replace(/\s+/g,",")):r(a.attributes,function(b){!e&&g[b.name]&&(e=a,f=b.value)})}});e&&a(e,f?[f]:[])}function Zb(b,a){var c=function(){b=z(b);if(b.injector()){var c=b[0]===T?"document":fa(b);throw Na("btstrpd",c);}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");c=$b(a);c.invoke(["$rootScope","$rootElement","$compile","$injector","$animate", 18 | function(a,b,c,d,e){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},d=/^NG_DEFER_BOOTSTRAP!/;if(D&&!d.test(D.name))return c();D.name=D.name.replace(d,"");Ba.resumeBootstrap=function(b){r(b,function(b){a.push(b)});c()}}function cb(b,a){a=a||"_";return b.replace(Vc,function(b,d){return(d?a:"")+b.toLowerCase()})}function xb(b,a,c){if(!b)throw Na("areq",a||"?",c||"required");return b}function Pa(b,a,c){c&&I(b)&&(b=b[b.length-1]);xb(N(b),a,"not a function, got "+(b&&"object"==typeof b? 19 | b.constructor.name||"Object":typeof b));return b}function va(b,a){if("hasOwnProperty"===b)throw Na("badname",a);}function ac(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,f=a.length,g=0;g "+b;a.removeChild(a.firstChild);Bb(this,a.childNodes);z(T.createDocumentFragment()).append(this)}else Bb(this, 23 | b)}function Cb(b){return b.cloneNode(!0)}function Da(b){bc(b);var a=0;for(b=b.childNodes||[];a=P?(c.preventDefault=null,c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function Ea(b){var a=typeof b,c;"object"==a&&null!==b?"function"==typeof(c=b.$$hashKey)?c=b.$$hashKey():c=== 28 | s&&(c=b.$$hashKey=Za()):c=b;return a+":"+c}function Sa(b){r(b,this.put,this)}function ic(b){var a,c;"function"==typeof b?(a=b.$inject)||(a=[],b.length&&(c=b.toString().replace(ad,""),c=c.match(bd),r(c[1].split(cd),function(b){b.replace(dd,function(b,c,d){a.push(d)})})),b.$inject=a):I(b)?(c=b.length-1,Pa(b[c],"fn"),a=b.slice(0,c)):Pa(b,"fn",!0);return a}function $b(b){function a(a){return function(b,c){if(X(b))r(b,Qb(a));else return a(b,c)}}function c(a,b){va(a,"service");if(N(b)||I(b))b=n.instantiate(b); 29 | if(!b.$get)throw Ta("pget",a);return l[a+h]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[],c,d,f,h;r(a,function(a){if(!k.get(a)){k.put(a,!0);try{if(E(a))for(c=Ua(a),b=b.concat(e(c.requires)).concat(c._runBlocks),d=c._invokeQueue,f=0,h=d.length;f 4096 bytes)!"));else{if(m.cookie!==aa)for(aa=m.cookie,d=aa.split("; "),M={},f=0;fk&&this.remove(q.key),b},get:function(a){if(k]*)?>/i,h=/^(on[a-z]+|formaction)$/;this.directive=function k(a,e){va(a,"directive");E(a)? 40 | (xb(e,"directiveFactory"),c.hasOwnProperty(a)||(c[a]=[],b.factory(a+d,["$injector","$exceptionHandler",function(b,d){var e=[];r(c[a],function(c,f){try{var h=b.invoke(c);N(h)?h={compile:$(h)}:!h.compile&&h.link&&(h.compile=$(h.link));h.priority=h.priority||0;h.index=f;h.name=h.name||a;h.require=h.require||h.controller&&h.name;h.restrict=h.restrict||"A";e.push(h)}catch(g){d(g)}});return e}])),c[a].push(e)):r(a,Qb(k));return this};this.aHrefSanitizationWhitelist=function(b){return v(b)?(a.aHrefSanitizationWhitelist(b), 41 | this):a.aHrefSanitizationWhitelist()};this.imgSrcSanitizationWhitelist=function(b){return v(b)?(a.imgSrcSanitizationWhitelist(b),this):a.imgSrcSanitizationWhitelist()};this.$get=["$injector","$interpolate","$exceptionHandler","$http","$templateCache","$parse","$controller","$rootScope","$document","$sce","$animate","$$sanitizeUri",function(a,b,n,q,p,y,C,A,u,H,W,w){function Y(a,b,c,d,e){a instanceof z||(a=z(a));r(a,function(b,c){3==b.nodeType&&b.nodeValue.match(/\S+/)&&(a[c]=z(b).wrap("").parent()[0])}); 42 | var f=M(a,b,a,c,d,e);S(a,"ng-scope");return function(b,c,d){xb(b,"scope");var e=c?Fa.clone.call(a):a;r(d,function(a,b){e.data("$"+b+"Controller",a)});d=0;for(var h=e.length;darguments.length&&(b=a,a=s);Ha&&(c=kb);return p(a,b,c)}var L,w,u,Y,J,U,kb={},v;L=c===f?d:Tb(d,new Fb(z(f),d.$attr));w=L.$$element;if(M){var t=/^\s*([@=&])(\??)\s*(\w*)\s*$/;h=z(f);U=e.$new(!0);aa&&aa===M.$$originalDirective?h.data("$isolateScope",U):h.data("$isolateScopeNoTemplate",U);S(h,"ng-isolate-scope");r(M.scope,function(a,c){var d= 48 | a.match(t)||[],f=d[3]||c,h="?"==d[2],d=d[1],g,k,p,n;U.$$isolateBindings[c]=d+f;switch(d){case "@":L.$observe(f,function(a){U[c]=a});L.$$observers[f].$$scope=e;L[f]&&(U[c]=b(L[f])(e));break;case "=":if(h&&!L[f])break;k=y(L[f]);n=k.literal?sa:function(a,b){return a===b};p=k.assign||function(){g=U[c]=k(e);throw ha("nonassign",L[f],M.name);};g=U[c]=k(e);U.$watch(function(){var a=k(e);n(a,U[c])||(n(a,g)?p(e,a=U[c]):U[c]=a);return g=a},null,k.literal);break;case "&":k=y(L[f]);U[c]=function(a){return k(e, 49 | a)};break;default:throw ha("iscp",M.name,c,a);}})}v=p&&q;W&&r(W,function(a){var b={$scope:a===M||a.$$isolateScope?U:e,$element:w,$attrs:L,$transclude:v},c;J=a.controller;"@"==J&&(J=L[a.name]);c=C(J,b);kb[a.name]=c;Ha||w.data("$"+a.name+"Controller",c);a.controllerAs&&(b.$scope[a.controllerAs]=c)});h=0;for(u=g.length;hG.priority)break;if(t=G.scope)u=u||G,G.templateUrl||(R("new/isolated scope",M,G,K),X(t)&&(M=G));ga= 51 | G.name;!G.templateUrl&&G.controller&&(t=G.controller,W=W||{},R("'"+ga+"' controller",W[ga],G,K),W[ga]=G);if(t=G.transclude)Va=!0,G.$$tlb||(R("transclusion",v,G,K),v=G),"element"==t?(Ha=!0,w=G.priority,t=J(c,Q,V),K=d.$$element=z(T.createComment(" "+ga+": "+d[ga]+" ")),c=K[0],lb(f,z(ta.call(t,0)),c),F=Y(t,e,w,h&&h.name,{nonTlbTranscludeDirective:v})):(t=z(Cb(c)).contents(),K.empty(),F=Y(t,e));if(G.template)if(R("template",aa,G,K),aa=G,t=N(G.template)?G.template(K,d):G.template,t=lc(t),G.replace){h= 52 | G;t=B(t);c=t[0];if(1!=t.length||1!==c.nodeType)throw ha("tplrt",ga,"");lb(f,K,c);P={$attr:{}};t=U(c,[],P);var Z=a.splice(D+1,a.length-(D+1));M&&jb(t);a=a.concat(t).concat(Z);x(d,P);P=a.length}else K.html(t);if(G.templateUrl)R("template",aa,G,K),aa=G,G.replace&&(h=G),A=O(a.splice(D,a.length-D),K,d,f,F,g,k,{controllerDirectives:W,newIsolateScopeDirective:M,templateDirective:aa,nonTlbTranscludeDirective:v}),P=a.length;else if(G.compile)try{oa=G.compile(K,d,F),N(oa)?q(null,oa,Q,V):oa&&q(oa.pre,oa.post, 53 | Q,V)}catch($){n($,fa(K))}G.terminal&&(A.terminal=!0,w=Math.max(w,G.priority))}A.scope=u&&!0===u.scope;A.transclude=Va&&F;p.hasElementTranscludeDirective=Ha;return A}function jb(a){for(var b=0,c=a.length;bq.priority)&&-1!=q.restrict.indexOf(f)&&(l&&(q=Sb(q,{$$start:l,$$end:p})),b.push(q),g=q)}catch(H){n(H)}}return g} 54 | function x(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;r(a,function(d,e){"$"!=e.charAt(0)&&(b[e]&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});r(b,function(b,f){"class"==f?(S(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):"style"==f?(e.attr("style",e.attr("style")+";"+b),a.style=(a.style?a.style+";":"")+b):"$"==f.charAt(0)||a.hasOwnProperty(f)||(a[f]=b,d[f]=c[f])})}function B(a){var b;a=ca(a);if(b=g.exec(a)){b=b[1].toLowerCase();a=z(""+a+"
");var c=a.children("tbody"),d= 55 | /(td|th)/.test(b)&&a.find("tr");c.length&&"tbody"!==b&&(a=c);d&&d.length&&(a=d);return a.contents()}return z("
"+a+"
").contents()}function O(a,b,c,d,e,f,h,g){var k=[],l,n,y=b[0],C=a.shift(),w=t({},C,{templateUrl:null,transclude:null,replace:null,$$originalDirective:C}),A=N(C.templateUrl)?C.templateUrl(b,c):C.templateUrl;b.empty();q.get(H.getTrustedResourceUrl(A),{cache:p}).success(function(p){var q,H;p=lc(p);if(C.replace){p=B(p);q=p[0];if(1!=p.length||1!==q.nodeType)throw ha("tplrt",C.name, 56 | A);p={$attr:{}};lb(d,b,q);var u=U(q,[],p);X(C.scope)&&jb(u);a=u.concat(a);x(c,p)}else q=y,b.html(p);a.unshift(w);l=Va(a,q,c,e,b,C,f,h,g);r(d,function(a,c){a==q&&(d[c]=b[0])});for(n=M(b[0].childNodes,e);k.length;){p=k.shift();H=k.shift();var W=k.shift(),Y=k.shift(),u=b[0];if(H!==y){var J=H.className;g.hasElementTranscludeDirective&&C.replace||(u=Cb(q));lb(W,z(H),u);S(z(u),J)}H=l.transclude?aa(p,l.transclude):Y;l(n,p,u,d,H)}k=null}).error(function(a,b,c,d){throw ha("tpload",d.url);});return function(a, 57 | b,c,d,e){k?(k.push(b),k.push(c),k.push(d),k.push(e)):l(n,b,c,d,e)}}function F(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.namea.status?b:n.reject(b)}var d={method:"get", 66 | transformRequest:e.transformRequest,transformResponse:e.transformResponse},f=function(a){function b(a){var c;r(a,function(b,d){N(b)&&(c=b(),null!=c?a[d]=c:delete a[d])})}var c=e.headers,d=t({},a.headers),f,h,c=t({},c.common,c[O(a.method)]);b(c);b(d);a:for(f in c){a=O(f);for(h in d)if(O(h)===a)continue a;d[f]=c[f]}return d}(a);t(d,a);d.headers=f;d.method=Ia(d.method);(a=Gb(d.url)?b.cookies()[d.xsrfCookieName||e.xsrfCookieName]:s)&&(f[d.xsrfHeaderName||e.xsrfHeaderName]=a);var h=[function(a){f=a.headers; 67 | var b=pc(a.data,oc(f),a.transformRequest);B(a.data)&&r(f,function(a,b){"content-type"===O(b)&&delete f[b]});B(a.withCredentials)&&!B(e.withCredentials)&&(a.withCredentials=e.withCredentials);return y(a,b,f).then(c,c)},s],g=n.when(d);for(r(u,function(a){(a.request||a.requestError)&&h.unshift(a.request,a.requestError);(a.response||a.responseError)&&h.push(a.response,a.responseError)});h.length;){a=h.shift();var k=h.shift(),g=g.then(a,k)}g.success=function(a){g.then(function(b){a(b.data,b.status,b.headers, 68 | d)});return g};g.error=function(a){g.then(null,function(b){a(b.data,b.status,b.headers,d)});return g};return g}function y(b,c,f){function g(a,b,c){u&&(200<=a&&300>a?u.put(s,[a,b,nc(c)]):u.remove(s));k(b,a,c);d.$$phase||d.$apply()}function k(a,c,d){c=Math.max(c,0);(200<=c&&300>c?q.resolve:q.reject)({data:a,status:c,headers:oc(d),config:b})}function m(){var a=ab(p.pendingRequests,b);-1!==a&&p.pendingRequests.splice(a,1)}var q=n.defer(),y=q.promise,u,r,s=C(b.url,b.params);p.pendingRequests.push(b);y.then(m, 69 | m);(b.cache||e.cache)&&(!1!==b.cache&&"GET"==b.method)&&(u=X(b.cache)?b.cache:X(e.cache)?e.cache:A);if(u)if(r=u.get(s),v(r)){if(r.then)return r.then(m,m),r;I(r)?k(r[1],r[0],ba(r[2])):k(r,200,{})}else u.put(s,y);B(r)&&a(b.method,s,c,g,f,b.timeout,b.withCredentials,b.responseType);return y}function C(a,b){if(!b)return a;var c=[];Qc(b,function(a,b){null===a||B(a)||(I(a)||(a=[a]),r(a,function(a){X(a)&&(a=na(a));c.push(ua(b)+"="+ua(a))}))});0=P&&(!b.match(/^(get|post|head|put|delete|options)$/i)||!D.XMLHttpRequest))return new D.ActiveXObject("Microsoft.XMLHTTP");if(D.XMLHttpRequest)return new D.XMLHttpRequest;throw F("$httpBackend")("noxhr");}function qd(){this.$get=["$browser","$window","$document",function(b,a,c){return rd(b,pd,b.defer,a.angular.callbacks,c[0])}]}function rd(b,a,c,d,e){function f(a,b){var c=e.createElement("script"),d=function(){c.onreadystatechange=c.onload=c.onerror=null; 72 | e.body.removeChild(c);b&&b()};c.type="text/javascript";c.src=a;P&&8>=P?c.onreadystatechange=function(){/loaded|complete/.test(c.readyState)&&d()}:c.onload=c.onerror=function(){d()};e.body.appendChild(c);return d}var g=-1;return function(e,m,k,l,n,q,p,y){function C(){u=g;W&&W();w&&w.abort()}function A(a,d,e,f){S&&c.cancel(S);W=w=null;d=0===d?e?200:404:d;a(1223==d?204:d,e,f);b.$$completeOutstandingRequest(x)}var u;b.$$incOutstandingRequestCount();m=m||b.url();if("jsonp"==O(e)){var H="_"+(d.counter++).toString(36); 73 | d[H]=function(a){d[H].data=a};var W=f(m.replace("JSON_CALLBACK","angular.callbacks."+H),function(){d[H].data?A(l,200,d[H].data):A(l,u||-2);d[H]=Ba.noop})}else{var w=a(e);w.open(e,m,!0);r(n,function(a,b){v(a)&&w.setRequestHeader(b,a)});w.onreadystatechange=function(){if(w&&4==w.readyState){var a=null,b=null;u!==g&&(a=w.getAllResponseHeaders(),b="response"in w?w.response:w.responseText);A(l,u||w.status,b,a)}};p&&(w.withCredentials=!0);if(y)try{w.responseType=y}catch(Y){if("json"!==y)throw Y;}w.send(k|| 74 | null)}if(0=h&&(n.resolve(p),l(q.$$intervalId),delete e[q.$$intervalId]);y||b.$apply()},g);e[q.$$intervalId]=n;return q}var e={};d.cancel=function(a){return a&&a.$$intervalId in e?(e[a.$$intervalId].reject("canceled"),clearInterval(a.$$intervalId),delete e[a.$$intervalId],!0):!1};return d}]}function ud(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".", 77 | GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "), 78 | SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return 1===b?"one":"other"}}}}function rc(b){b=b.split("/");for(var a=b.length;a--;)b[a]=wb(b[a]);return b.join("/")}function sc(b,a,c){b=wa(b,c);a.$$protocol=b.protocol;a.$$host=b.hostname;a.$$port=Q(b.port)||vd[b.protocol]||null} 79 | function tc(b,a,c){var d="/"!==b.charAt(0);d&&(b="/"+b);b=wa(b,c);a.$$path=decodeURIComponent(d&&"/"===b.pathname.charAt(0)?b.pathname.substring(1):b.pathname);a.$$search=Xb(b.search);a.$$hash=decodeURIComponent(b.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function la(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function Wa(b){var a=b.indexOf("#");return-1==a?b:b.substr(0,a)}function Hb(b){return b.substr(0,Wa(b).lastIndexOf("/")+1)}function uc(b,a){this.$$html5=!0;a=a|| 80 | "";var c=Hb(b);sc(b,this,b);this.$$parse=function(a){var e=la(c,a);if(!E(e))throw Ib("ipthprfx",a,c);tc(e,this,b);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=Yb(this.$$search),b=this.$$hash?"#"+wb(this.$$hash):"";this.$$url=rc(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$rewrite=function(d){var e;if((e=la(b,d))!==s)return d=e,(e=la(a,e))!==s?c+(la("/",e)||e):b+d;if((e=la(c,d))!==s)return c+e;if(c==d+"/")return c}}function Jb(b,a){var c= 81 | Hb(b);sc(b,this,b);this.$$parse=function(d){var e=la(b,d)||la(c,d),e="#"==e.charAt(0)?la(a,e):this.$$html5?e:"";if(!E(e))throw Ib("ihshprfx",d,a);tc(e,this,b);d=this.$$path;var f=/^\/?.*?:(\/.*)/;0===e.indexOf(b)&&(e=e.replace(b,""));f.exec(e)||(d=(e=f.exec(d))?e[1]:d);this.$$path=d;this.$$compose()};this.$$compose=function(){var c=Yb(this.$$search),e=this.$$hash?"#"+wb(this.$$hash):"";this.$$url=rc(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+(this.$$url?a+this.$$url:"")};this.$$rewrite=function(a){if(Wa(b)== 82 | Wa(a))return a}}function vc(b,a){this.$$html5=!0;Jb.apply(this,arguments);var c=Hb(b);this.$$rewrite=function(d){var e;if(b==Wa(d))return d;if(e=la(c,d))return b+a+e;if(c===d+"/")return c}}function mb(b){return function(){return this[b]}}function wc(b,a){return function(c){if(B(c))return this[b];this[b]=a(c);this.$$compose();return this}}function wd(){var b="",a=!1;this.hashPrefix=function(a){return v(a)?(b=a,this):b};this.html5Mode=function(b){return v(b)?(a=b,this):a};this.$get=["$rootScope","$browser", 83 | "$sniffer","$rootElement",function(c,d,e,f){function g(a){c.$broadcast("$locationChangeSuccess",h.absUrl(),a)}var h,m=d.baseHref(),k=d.url();a?(m=k.substring(0,k.indexOf("/",k.indexOf("//")+2))+(m||"/"),e=e.history?uc:vc):(m=Wa(k),e=Jb);h=new e(m,"#"+b);h.$$parse(h.$$rewrite(k));f.on("click",function(a){if(!a.ctrlKey&&!a.metaKey&&2!=a.which){for(var b=z(a.target);"a"!==O(b[0].nodeName);)if(b[0]===f[0]||!(b=b.parent())[0])return;var e=b.prop("href");X(e)&&"[object SVGAnimatedString]"===e.toString()&& 84 | (e=wa(e.animVal).href);var g=h.$$rewrite(e);e&&(!b.attr("target")&&g&&!a.isDefaultPrevented())&&(a.preventDefault(),g!=d.url()&&(h.$$parse(g),c.$apply(),D.angular["ff-684208-preventDefault"]=!0))}});h.absUrl()!=k&&d.url(h.absUrl(),!0);d.onUrlChange(function(a){h.absUrl()!=a&&(c.$evalAsync(function(){var b=h.absUrl();h.$$parse(a);c.$broadcast("$locationChangeStart",a,b).defaultPrevented?(h.$$parse(b),d.url(b)):g(b)}),c.$$phase||c.$digest())});var l=0;c.$watch(function(){var a=d.url(),b=h.$$replace; 85 | l&&a==h.absUrl()||(l++,c.$evalAsync(function(){c.$broadcast("$locationChangeStart",h.absUrl(),a).defaultPrevented?h.$$parse(a):(d.url(h.absUrl(),b),g(a))}));h.$$replace=!1;return l});return h}]}function xd(){var b=!0,a=this;this.debugEnabled=function(a){return v(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a} 86 | function e(a){var b=c.console||{},e=b[a]||b.log||x;a=!1;try{a=!!e.apply}catch(m){}return a?function(){var a=[];r(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function da(b,a){if("constructor"===b)throw xa("isecfld",a);return b}function Xa(b,a){if(b){if(b.constructor===b)throw xa("isecfn",a);if(b.document&& 87 | b.location&&b.alert&&b.setInterval)throw xa("isecwindow",a);if(b.children&&(b.nodeName||b.prop&&b.attr&&b.find))throw xa("isecdom",a);}return b}function nb(b,a,c,d,e){e=e||{};a=a.split(".");for(var f,g=0;1e?xc(d[0],d[1],d[2],d[3],d[4],c,a):function(b,f){var h=0,g;do g=xc(d[h++],d[h++],d[h++],d[h++],d[h++],c,a)(b,f),f=s,b=g;while(ha)for(b in h++,d)d.hasOwnProperty(b)&&!e.hasOwnProperty(b)&&(m--,delete d[b])}else d!==e&&(d=e,h++);return h},function(){b(e,d,c)})},$digest:function(){var d,f,h,g,k=this.$$asyncQueue, 102 | l=this.$$postDigestQueue,r,w,s=b,S,M=[],v,t,J;m("$digest");c=null;do{w=!1;for(S=this;k.length;){try{J=k.shift(),J.scope.$eval(J.expression)}catch(z){q.$$phase=null,e(z)}c=null}a:do{if(g=S.$$watchers)for(r=g.length;r--;)try{if(d=g[r])if((f=d.get(S))!==(h=d.last)&&!(d.eq?sa(f,h):"number"==typeof f&&"number"==typeof h&&isNaN(f)&&isNaN(h)))w=!0,c=d,d.last=d.eq?ba(f):f,d.fn(f,h===n?f:h,S),5>s&&(v=4-s,M[v]||(M[v]=[]),t=N(d.exp)?"fn: "+(d.exp.name||d.exp.toString()):d.exp,t+="; newVal: "+na(f)+"; oldVal: "+ 103 | na(h),M[v].push(t));else if(d===c){w=!1;break a}}catch(E){q.$$phase=null,e(E)}if(!(g=S.$$childHead||S!==this&&S.$$nextSibling))for(;S!==this&&!(g=S.$$nextSibling);)S=S.$parent}while(S=g);if((w||k.length)&&!s--)throw q.$$phase=null,a("infdig",b,na(M));}while(w||k.length);for(q.$$phase=null;l.length;)try{l.shift()()}catch(x){e(x)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this!==q&&(r(this.$$listenerCount,bb(null,l,this)),a.$$childHead== 104 | this&&(a.$$childHead=this.$$nextSibling),a.$$childTail==this&&(a.$$childTail=this.$$prevSibling),this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling),this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling),this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null)}},$eval:function(a,b){return f(a)(this,b)},$evalAsync:function(a){q.$$phase||q.$$asyncQueue.length||g.defer(function(){q.$$asyncQueue.length&&q.$digest()});this.$$asyncQueue.push({scope:this, 105 | expression:a})},$$postDigest:function(a){this.$$postDigestQueue.push(a)},$apply:function(a){try{return m("$apply"),this.$eval(a)}catch(b){e(b)}finally{q.$$phase=null;try{q.$digest()}catch(c){throw e(c),c;}}},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);var d=this;do d.$$listenerCount[a]||(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){c[ab(c,b)]=null;l(e,1,a)}},$emit:function(a,b){var c=[],d,f=this,h=!1,g={name:a, 106 | targetScope:f,stopPropagation:function(){h=!0},preventDefault:function(){g.defaultPrevented=!0},defaultPrevented:!1},k=[g].concat(ta.call(arguments,1)),l,m;do{d=f.$$listeners[a]||c;g.currentScope=f;l=0;for(m=d.length;lc.msieDocumentMode)throw qa("iequirks");var e=ba(ea);e.isEnabled=function(){return b};e.trustAs=d.trustAs;e.getTrusted=d.getTrusted;e.valueOf=d.valueOf;b||(e.trustAs=e.getTrusted=function(a,b){return b},e.valueOf=za);e.parseAs=function(b,c){var d=a(c);return d.literal&&d.constant?d:function(a,c){return e.getTrusted(b,d(a,c))}};var f=e.parseAs,g=e.getTrusted,h=e.trustAs;r(ea,function(a,b){var c=O(b);e[Qa("parse_as_"+c)]= 113 | function(b){return f(a,b)};e[Qa("get_trusted_"+c)]=function(b){return g(a,b)};e[Qa("trust_as_"+c)]=function(b){return h(a,b)}});return e}]}function Jd(){this.$get=["$window","$document",function(b,a){var c={},d=Q((/android (\d+)/.exec(O((b.navigator||{}).userAgent))||[])[1]),e=/Boxee/i.test((b.navigator||{}).userAgent),f=a[0]||{},g=f.documentMode,h,m=/^(Moz|webkit|O|ms)(?=[A-Z])/,k=f.body&&f.body.style,l=!1,n=!1;if(k){for(var q in k)if(l=m.exec(q)){h=l[0];h=h.substr(0,1).toUpperCase()+h.substr(1); 114 | break}h||(h="WebkitOpacity"in k&&"webkit");l=!!("transition"in k||h+"Transition"in k);n=!!("animation"in k||h+"Animation"in k);!d||l&&n||(l=E(f.body.style.webkitTransition),n=E(f.body.style.webkitAnimation))}return{history:!(!b.history||!b.history.pushState||4>d||e),hashchange:"onhashchange"in b&&(!g||7b;b=Math.abs(b);var g=b+"",h="",m=[],k=!1;if(-1!==g.indexOf("e")){var l=g.match(/([\d\.]+)e(-?)(\d+)/);l&&"-"==l[2]&&l[3]>e+1?g="0":(h=g,k=!0)}if(k)0b)&&(h=b.toFixed(e));else{g=(g.split(Ic)[1]||"").length;B(e)&&(e=Math.min(Math.max(a.minFrac,g),a.maxFrac));g=Math.pow(10, 121 | e);b=Math.round(b*g)/g;b=(""+b).split(Ic);g=b[0];b=b[1]||"";var l=0,n=a.lgSize,q=a.gSize;if(g.length>=n+q)for(l=g.length-n,k=0;kb&&(d="-",b=-b);for(b=""+b;b.length-c)e+=c;0===e&&-12==c&&(e=12);return Mb(e,a,d)}}function ob(b,a){return function(c,d){var e=c["get"+b](),f=Ia(a?"SHORT"+b:b);return d[f][e]}}function Ec(b){function a(a){var b;if(b=a.match(c)){a=new Date(0);var f=0,g=0,h=b[8]?a.setUTCFullYear:a.setFullYear,m=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=Q(b[9]+b[10]),g=Q(b[9]+b[11]));h.call(a,Q(b[1]),Q(b[2])-1,Q(b[3]));f=Q(b[4]||0)-f;g=Q(b[5]||0)-g;h=Q(b[6]||0);b=Math.round(1E3*parseFloat("0."+ 123 | (b[7]||0)));m.call(a,f,g,h,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e){var f="",g=[],h,m;e=e||"mediumDate";e=b.DATETIME_FORMATS[e]||e;E(c)&&(c=Sd.test(c)?Q(c):a(c));vb(c)&&(c=new Date(c));if(!La(c))return c;for(;e;)(m=Td.exec(e))?(g=g.concat(ta.call(m,1)),e=g.pop()):(g.push(e),e=null);r(g,function(a){h=Ud[a];f+=h?h(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return f}}function Nd(){return function(b){return na(b, 124 | !0)}}function Od(){return function(b,a){if(!I(b)&&!E(b))return b;a=Q(a);if(E(b))return a?0<=a?b.slice(0,a):b.slice(a,b.length):"";var c=[],d,e;a>b.length?a=b.length:a<-b.length&&(a=-b.length);0a||37<=a&&40>=a)||l()});if(e.hasEvent("paste"))a.on("paste cut",l)}a.on("change",m);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)?"":d.$viewValue)};var n=c.ngPattern;n&&((e=n.match(/^\/(.*)\/([gim]*)$/))?(n=RegExp(e[1],e[2]),e=function(a){return ma(d,"pattern",d.$isEmpty(a)||n.test(a),a)}):e= 130 | function(c){var e=b.$eval(n);if(!e||!e.test)throw F("ngPattern")("noregexp",n,e,fa(a));return ma(d,"pattern",d.$isEmpty(c)||e.test(c),c)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var q=Q(c.ngMinlength);e=function(a){return ma(d,"minlength",d.$isEmpty(a)||a.length>=q,a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){var p=Q(c.ngMaxlength);e=function(a){return ma(d,"maxlength",d.$isEmpty(a)||a.length<=p,a)};d.$parsers.push(e);d.$formatters.push(e)}}function Nb(b,a){b= 131 | "ngClass"+b;return function(){return{restrict:"AC",link:function(c,d,e){function f(b){if(!0===a||c.$index%2===a){var d=g(b||"");h?sa(b,h)||e.$updateClass(d,g(h)):e.$addClass(d)}h=ba(b)}function g(a){if(I(a))return a.join(" ");if(X(a)){var b=[];r(a,function(a,c){a&&b.push(c)});return b.join(" ")}return a}var h;c.$watch(e[b],f,!0);e.$observe("class",function(a){f(c.$eval(e[b]))});"ngClass"!==b&&c.$watch("$index",function(d,f){var h=d&1;if(h!==f&1){var n=g(c.$eval(e[b]));h===a?e.$addClass(n):e.$removeClass(n)}})}}}} 132 | var O=function(b){return E(b)?b.toLowerCase():b},Rd=Object.prototype.hasOwnProperty,Ia=function(b){return E(b)?b.toUpperCase():b},P,z,Ca,ta=[].slice,Wd=[].push,Aa=Object.prototype.toString,Na=F("ng"),Ba=D.angular||(D.angular={}),Ua,Ga,ia=["0","0","0"];P=Q((/msie (\d+)/.exec(O(navigator.userAgent))||[])[1]);isNaN(P)&&(P=Q((/trident\/.*; rv:(\d+)/.exec(O(navigator.userAgent))||[])[1]));x.$inject=[];za.$inject=[];var ca=function(){return String.prototype.trim?function(b){return E(b)?b.trim():b}:function(b){return E(b)? 133 | b.replace(/^\s\s*/,"").replace(/\s\s*$/,""):b}}();Ga=9>P?function(b){b=b.nodeName?b:b[0];return b.scopeName&&"HTML"!=b.scopeName?Ia(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?b.nodeName:b[0].nodeName};var Vc=/[A-Z]/g,Xd={full:"1.2.14",major:1,minor:2,dot:14,codeName:"feisty-cryokinesis"},Ra=R.cache={},db=R.expando="ng-"+(new Date).getTime(),Zc=1,Kc=D.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},Db=D.document.removeEventListener? 134 | function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)};R._data=function(b){return this.cache[b[this.expando]]||{}};var Xc=/([\:\-\_]+(.))/g,Yc=/^moz([A-Z])/,Ab=F("jqLite"),Fa=R.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===T.readyState?setTimeout(a):(this.on("DOMContentLoaded",a),R(D).on("load",a))},toString:function(){var b=[];r(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return 0<=b?z(this[b]):z(this[this.length+ 135 | b])},length:0,push:Wd,sort:[].sort,splice:[].splice},hb={};r("multiple selected checked disabled readOnly required open".split(" "),function(b){hb[O(b)]=b});var hc={};r("input select option textarea button form details".split(" "),function(b){hc[Ia(b)]=!0});r({data:dc,inheritedData:gb,scope:function(b){return z(b).data("$scope")||gb(b.parentNode||b,["$isolateScope","$scope"])},isolateScope:function(b){return z(b).data("$isolateScope")||z(b).data("$isolateScopeNoTemplate")},controller:ec,injector:function(b){return gb(b, 136 | "$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Eb,css:function(b,a,c){a=Qa(a);if(v(c))b.style[a]=c;else{var d;8>=P&&(d=b.currentStyle&&b.currentStyle[a],""===d&&(d="auto"));d=d||b.style[a];8>=P&&(d=""===d?s:d);return d}},attr:function(b,a,c){var d=O(a);if(hb[d])if(v(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||x).specified?d:s;else if(v(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a, 137 | 2),null===b?s:b},prop:function(b,a,c){if(v(c))b[a]=c;else return b[a]},text:function(){function b(b,d){var e=a[b.nodeType];if(B(d))return e?b[e]:"";b[e]=d}var a=[];9>P?(a[1]="innerText",a[3]="nodeValue"):a[1]=a[3]="textContent";b.$dv="";return b}(),val:function(b,a){if(B(a)){if("SELECT"===Ga(b)&&b.multiple){var c=[];r(b.options,function(a){a.selected&&c.push(a.value||a.text)});return 0===c.length?null:c}return b.value}b.value=a},html:function(b,a){if(B(a))return b.innerHTML;for(var c=0,d=b.childNodes;c< 138 | d.length;c++)Da(d[c]);b.innerHTML=a},empty:fc},function(b,a){R.prototype[a]=function(a,d){var e,f;if(b!==fc&&(2==b.length&&b!==Eb&&b!==ec?a:d)===s){if(X(a)){for(e=0;e":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a, 149 | c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},ae={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'},Lb=function(a){this.options=a};Lb.prototype={constructor:Lb,lex:function(a){this.text=a;this.index=0;this.ch=s;this.lastCh=":";this.tokens=[];var c; 150 | for(a=[];this.index=a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)}, 153 | throwError:function(a,c,d){d=d||this.index;c=v(c)?"s "+c+"-"+this.index+" ["+this.text.substring(c,d)+"]":" "+d;throw xa("lexerr",a,c,this.text);},readNumber:function(){for(var a="",c=this.index;this.index","<=",">="))a=this.binaryFn(a,c.fn,this.relational());return a},additive:function(){for(var a=this.multiplicative(),c;c=this.expect("+","-");)a=this.binaryFn(a,c.fn,this.multiplicative());return a},multiplicative:function(){for(var a= 164 | this.unary(),c;c=this.expect("*","/","%");)a=this.binaryFn(a,c.fn,this.unary());return a},unary:function(){var a;return this.expect("+")?this.primary():(a=this.expect("-"))?this.binaryFn(Ya.ZERO,a.fn,this.unary()):(a=this.expect("!"))?this.unaryFn(a.fn,this.unary()):this.primary()},fieldAccess:function(a){var c=this,d=this.expect().text,e=yc(d,this.options,this.text);return t(function(c,d,h){return e(h||a(c,d))},{assign:function(e,g,h){return nb(a(e,h),d,g,c.text,c.options)}})},objectIndex:function(a){var c= 165 | this,d=this.expression();this.consume("]");return t(function(e,f){var g=a(e,f),h=d(e,f),m;if(!g)return s;(g=Xa(g[h],c.text))&&(g.then&&c.options.unwrapPromises)&&(m=g,"$$v"in g||(m.$$v=s,m.then(function(a){m.$$v=a})),g=g.$$v);return g},{assign:function(e,f,g){var h=d(e,g);return Xa(a(e,g),c.text)[h]=f}})},functionCall:function(a,c){var d=[];if(")"!==this.peekToken().text){do d.push(this.expression());while(this.expect(","))}this.consume(")");var e=this;return function(f,g){for(var h=[],m=c?c(f,g): 166 | f,k=0;ka.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=-1*a.getTimezoneOffset();return a=(0<=a?"+":"")+(Mb(Math[0< 169 | a?"floor":"ceil"](a/60),2)+Mb(Math.abs(a%60),2))}},Td=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,Sd=/^\-?\d+$/;Ec.$inject=["$locale"];var Pd=$(O),Qd=$(Ia);Gc.$inject=["$parse"];var be=$({restrict:"E",compile:function(a,c){8>=P&&(c.href||c.name||c.$set("href",""),a.append(T.createComment("IE fix")));if(!c.href&&!c.xlinkHref&&!c.name)return function(a,c){var f="[object SVGAnimatedString]"===Aa.call(c.prop("href"))?"xlink:href":"href";c.on("click",function(a){c.attr(f)|| 170 | a.preventDefault()})}}}),Ob={};r(hb,function(a,c){if("multiple"!=a){var d=ka("ng-"+c);Ob[d]=function(){return{priority:100,link:function(a,f,g){a.$watch(g[d],function(a){g.$set(c,!!a)})}}}}});r(["src","srcset","href"],function(a){var c=ka("ng-"+a);Ob[c]=function(){return{priority:99,link:function(d,e,f){var g=a,h=a;"href"===a&&"[object SVGAnimatedString]"===Aa.call(e.prop("href"))&&(h="xlinkHref",f.$attr[h]="xlink:href",g=null);f.$observe(c,function(a){a&&(f.$set(h,a),P&&g&&e.prop(g,f[h]))})}}}}); 171 | var rb={$addControl:x,$removeControl:x,$setValidity:x,$setDirty:x,$setPristine:x};Jc.$inject=["$element","$attrs","$scope","$animate"];var Lc=function(a){return["$timeout",function(c){return{name:"form",restrict:a?"EAC":"E",controller:Jc,compile:function(){return{pre:function(a,e,f,g){if(!f.action){var h=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1};Kc(e[0],"submit",h);e.on("$destroy",function(){c(function(){Db(e[0],"submit",h)},0,!1)})}var m=e.parent().controller("form"),k=f.name|| 172 | f.ngForm;k&&nb(a,k,g,k);if(m)e.on("$destroy",function(){m.$removeControl(g);k&&nb(a,k,s,k);t(g,rb)})}}}}}]},ce=Lc(),de=Lc(!0),ee=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,fe=/^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i,ge=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,Mc={text:tb,number:function(a,c,d,e,f,g){tb(a,c,d,e,f,g);e.$parsers.push(function(a){var c=e.$isEmpty(a);if(c||ge.test(a))return e.$setValidity("number",!0),""===a?null:c?a:parseFloat(a); 173 | e.$setValidity("number",!1);return s});Vd(e,"number",c);e.$formatters.push(function(a){return e.$isEmpty(a)?"":""+a});d.min&&(a=function(a){var c=parseFloat(d.min);return ma(e,"min",e.$isEmpty(a)||a>=c,a)},e.$parsers.push(a),e.$formatters.push(a));d.max&&(a=function(a){var c=parseFloat(d.max);return ma(e,"max",e.$isEmpty(a)||a<=c,a)},e.$parsers.push(a),e.$formatters.push(a));e.$formatters.push(function(a){return ma(e,"number",e.$isEmpty(a)||vb(a),a)})},url:function(a,c,d,e,f,g){tb(a,c,d,e,f,g);a= 174 | function(a){return ma(e,"url",e.$isEmpty(a)||ee.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,f,g){tb(a,c,d,e,f,g);a=function(a){return ma(e,"email",e.$isEmpty(a)||fe.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){B(d.name)&&c.attr("name",Za());c.on("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a, 175 | c,d,e){var f=d.ngTrueValue,g=d.ngFalseValue;E(f)||(f=!0);E(g)||(g=!1);c.on("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});e.$render=function(){c[0].checked=e.$viewValue};e.$isEmpty=function(a){return a!==f};e.$formatters.push(function(a){return a===f});e.$parsers.push(function(a){return a?f:g})},hidden:x,button:x,submit:x,reset:x,file:x},Nc=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",link:function(d,e,f,g){g&&(Mc[O(f.type)]||Mc.text)(d,e,f, 176 | g,c,a)}}}],qb="ng-valid",pb="ng-invalid",Ja="ng-pristine",sb="ng-dirty",he=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate",function(a,c,d,e,f,g){function h(a,c){c=c?"-"+cb(c,"-"):"";g.removeClass(e,(a?pb:qb)+c);g.addClass(e,(a?qb:pb)+c)}this.$modelValue=this.$viewValue=Number.NaN;this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var m=f(d.ngModel),k=m.assign;if(!k)throw F("ngModel")("nonassign", 177 | d.ngModel,fa(e));this.$render=x;this.$isEmpty=function(a){return B(a)||""===a||null===a||a!==a};var l=e.inheritedData("$formController")||rb,n=0,q=this.$error={};e.addClass(Ja);h(!0);this.$setValidity=function(a,c){q[a]!==!c&&(c?(q[a]&&n--,n||(h(!0),this.$valid=!0,this.$invalid=!1)):(h(!1),this.$invalid=!0,this.$valid=!1,n++),q[a]=!c,h(c,a),l.$setValidity(a,c,this))};this.$setPristine=function(){this.$dirty=!1;this.$pristine=!0;g.removeClass(e,sb);g.addClass(e,Ja)};this.$setViewValue=function(d){this.$viewValue= 178 | d;this.$pristine&&(this.$dirty=!0,this.$pristine=!1,g.removeClass(e,Ja),g.addClass(e,sb),l.$setDirty());r(this.$parsers,function(a){d=a(d)});this.$modelValue!==d&&(this.$modelValue=d,k(a,d),r(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}}))};var p=this;a.$watch(function(){var c=m(a);if(p.$modelValue!==c){var d=p.$formatters,e=d.length;for(p.$modelValue=c;e--;)c=d[e](c);p.$viewValue!==c&&(p.$viewValue=c,p.$render())}return c})}],ie=function(){return{require:["ngModel","^?form"],controller:he, 179 | link:function(a,c,d,e){var f=e[0],g=e[1]||rb;g.$addControl(f);a.$on("$destroy",function(){g.$removeControl(f)})}}},je=$({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),Oc=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var f=function(a){if(d.required&&e.$isEmpty(a))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(f);e.$parsers.unshift(f);d.$observe("required",function(){f(e.$viewValue)})}}}}, 180 | ke=function(){return{require:"ngModel",link:function(a,c,d,e){var f=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){if(!B(a)){var c=[];a&&r(a.split(f),function(a){a&&c.push(ca(a))});return c}});e.$formatters.push(function(a){return I(a)?a.join(", "):s});e.$isEmpty=function(a){return!a||!a.length}}}},le=/^(true|false|\d+)$/,me=function(){return{priority:100,compile:function(a,c){return le.test(c.ngValue)?function(a,c,f){f.$set("value",a.$eval(f.ngValue))}:function(a, 181 | c,f){a.$watch(f.ngValue,function(a){f.$set("value",a)})}}}},ne=ra(function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==s?"":a)})}),oe=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],pe=["$sce","$parse",function(a,c){return function(d,e,f){e.addClass("ng-binding").data("$binding",f.ngBindHtml);var g=c(f.ngBindHtml); 182 | d.$watch(function(){return(g(d)||"").toString()},function(c){e.html(a.getTrustedHtml(g(d))||"")})}}],qe=Nb("",!0),re=Nb("Odd",0),se=Nb("Even",1),te=ra({compile:function(a,c){c.$set("ngCloak",s);a.removeClass("ng-cloak")}}),ue=[function(){return{scope:!0,controller:"@",priority:500}}],Pc={};r("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var c=ka("ng-"+a);Pc[c]=["$parse",function(d){return{compile:function(e, 183 | f){var g=d(f[c]);return function(c,d,e){d.on(O(a),function(a){c.$apply(function(){g(c,{$event:a})})})}}}}]});var ve=["$animate",function(a){return{transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(c,d,e,f,g){var h,m,k;c.$watch(e.ngIf,function(f){Oa(f)?m||(m=c.$new(),g(m,function(c){c[c.length++]=T.createComment(" end ngIf: "+e.ngIf+" ");h={clone:c};a.enter(c,d.parent(),d)})):(k&&(k.remove(),k=null),m&&(m.$destroy(),m=null),h&&(k=yb(h.clone),a.leave(k,function(){k=null}), 184 | h=null))})}}}],we=["$http","$templateCache","$anchorScroll","$animate","$sce",function(a,c,d,e,f){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:Ba.noop,compile:function(g,h){var m=h.ngInclude||h.src,k=h.onload||"",l=h.autoscroll;return function(g,h,p,r,C){var s=0,u,t,z,w=function(){t&&(t.remove(),t=null);u&&(u.$destroy(),u=null);z&&(e.leave(z,function(){t=null}),t=z,z=null)};g.$watch(f.parseAsResourceUrl(m),function(f){var m=function(){!v(l)||l&&!g.$eval(l)||d()}, 185 | p=++s;f?(a.get(f,{cache:c}).success(function(a){if(p===s){var c=g.$new();r.template=a;a=C(c,function(a){w();e.enter(a,null,h,m)});u=c;z=a;u.$emit("$includeContentLoaded");g.$eval(k)}}).error(function(){p===s&&w()}),g.$emit("$includeContentRequested")):(w(),r.template=null)})}}}}],xe=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(c,d,e,f){d.html(f.template);a(d.contents())(c)}}}],ye=ra({priority:450,compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}), 186 | ze=ra({terminal:!0,priority:1E3}),Ae=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,f,g){var h=g.count,m=g.$attr.when&&f.attr(g.$attr.when),k=g.offset||0,l=e.$eval(m)||{},n={},q=c.startSymbol(),p=c.endSymbol(),s=/^when(Minus)?(.+)$/;r(g,function(a,c){s.test(c)&&(l[O(c.replace("when","").replace("Minus","-"))]=f.attr(g.$attr[c]))});r(l,function(a,e){n[e]=c(a.replace(d,q+h+"-"+k+p))});e.$watch(function(){var c=parseFloat(e.$eval(h));if(isNaN(c))return"";c in 187 | l||(c=a.pluralCat(c-k));return n[c](e,f,!0)},function(a){f.text(a)})}}}],Be=["$parse","$animate",function(a,c){var d=F("ngRepeat");return{transclude:"element",priority:1E3,terminal:!0,$$tlb:!0,link:function(e,f,g,h,m){var k=g.ngRepeat,l=k.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),n,q,p,s,t,v,u={$id:Ea};if(!l)throw d("iexp",k);g=l[1];h=l[2];(l=l[3])?(n=a(l),q=function(a,c,d){v&&(u[v]=a);u[t]=c;u.$index=d;return n(e,u)}):(p=function(a,c){return Ea(c)},s=function(a){return a}); 188 | l=g.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!l)throw d("iidexp",g);t=l[3]||l[1];v=l[2];var H={};e.$watchCollection(h,function(a){var g,h,l=f[0],n,u={},E,J,x,B,F,K,I=[];if(ub(a))F=a,n=q||p;else{n=q||s;F=[];for(x in a)a.hasOwnProperty(x)&&"$"!=x.charAt(0)&&F.push(x);F.sort()}E=F.length;h=I.length=F.length;for(g=0;gD;)y.pop().element.remove()}for(;x.length> 199 | A;)x.pop()[0].element.remove()}var k;if(!(k=t.match(d)))throw Ke("iexp",t,fa(f));var l=c(k[2]||k[1]),m=k[4]||k[6],n=k[5],q=c(k[3]||""),r=c(k[2]?k[1]:m),z=c(k[7]),w=k[8]?c(k[8]):null,x=[[{element:f,label:""}]];C&&(a(C)(e),C.removeClass("ng-scope"),C.remove());f.empty();f.on("change",function(){e.$apply(function(){var a,c=z(e)||[],d={},h,k,l,q,t,v,u;if(p)for(k=[],q=0,v=x.length;q@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}'); 206 | //# sourceMappingURL=angular.min.js.map 207 | --------------------------------------------------------------------------------