diff --git a/.bower.json.un~ b/.bower.json.un~
new file mode 100644
index 0000000..78eb9b8
Binary files /dev/null and b/.bower.json.un~ differ
diff --git a/.iframe.html.un~ b/.iframe.html.un~
new file mode 100644
index 0000000..75a25e1
Binary files /dev/null and b/.iframe.html.un~ differ
diff --git a/.start.php.un~ b/.start.php.un~
new file mode 100644
index 0000000..3ec7ca8
Binary files /dev/null and b/.start.php.un~ differ
diff --git a/assets/.PositionModels.coffee.un~ b/assets/.PositionModels.coffee.un~
new file mode 100644
index 0000000..19c1b76
Binary files /dev/null and b/assets/.PositionModels.coffee.un~ differ
diff --git a/assets/.PositionsApplication.coffee.un~ b/assets/.PositionsApplication.coffee.un~
new file mode 100644
index 0000000..09f1995
Binary files /dev/null and b/assets/.PositionsApplication.coffee.un~ differ
diff --git a/assets/.PositionsController.coffee.un~ b/assets/.PositionsController.coffee.un~
new file mode 100644
index 0000000..f6082cb
Binary files /dev/null and b/assets/.PositionsController.coffee.un~ differ
diff --git a/assets/.PositionsViews.coffee.un~ b/assets/.PositionsViews.coffee.un~
new file mode 100644
index 0000000..9902298
Binary files /dev/null and b/assets/.PositionsViews.coffee.un~ differ
diff --git a/assets/.setup.coffee.un~ b/assets/.setup.coffee.un~
new file mode 100644
index 0000000..2e53849
Binary files /dev/null and b/assets/.setup.coffee.un~ differ
diff --git a/assets/PositionsApplication.coffee b/assets/PositionsApplication.coffee
new file mode 100644
index 0000000..9c5da13
--- /dev/null
+++ b/assets/PositionsApplication.coffee
@@ -0,0 +1,2 @@
+positionsApp = new Backbone.Marionette.Application
+
diff --git a/assets/PositionsController.coffee b/assets/PositionsController.coffee
new file mode 100644
index 0000000..d2eef00
--- /dev/null
+++ b/assets/PositionsController.coffee
@@ -0,0 +1,18 @@
+positionsApp.module 'Controller', (PositionsController, App, Backbone, Marionette, $, _) ->
+
+ class PositionsController.Controller extends Marionette.Controller
+ constructor: ->
+
+ start: ->
+ createView = new positionsApp.View.CreatePosition()
+ createView.show()
+ App.vent.on 'position:add', (position) ->
+ that.positions.add position
+
+
+
+ PositionsController.addInitializer ->
+ controller = new PositionsController.Controller
+
+ controller.start()
+
diff --git a/assets/PositionsViews.coffee b/assets/PositionsViews.coffee
new file mode 100644
index 0000000..b93c5d8
--- /dev/null
+++ b/assets/PositionsViews.coffee
@@ -0,0 +1,84 @@
+positionsApp.module 'Views', (Views, App, Backbone) ->
+ Helpers =
+ calculatePensum: ((weeklyHours) ->
+ (workload) ->
+ Math.round(workload / weeklyHours * 1000) / 10
+ )(Bejoo.organisation.weeklyHours)
+
+
+ class Views.CreatePosition extends Marionette.View
+ template: Handlebars.compile $('#create-view-template').html()
+ el: 'article#content'
+ events:
+ 'click .submit-position': 'submitPosition'
+ 'click .x': 'hide'
+ 'change #workload-position': 'workloadChanged'
+
+ ui:
+ title: '.title-position'
+ indefinite: '#indefinite'
+ description: '.description-position'
+ workload: '#workload-position'
+ from: '.from-position'
+ to: '.to-position'
+ pensum: '.pensum-number'
+ duration: '#duration'
+ mon: '#mon'
+ tue: '#tue'
+ wed: '#wed'
+ thu: '#thu'
+ fri: '#fri'
+ sat: '#sat'
+ sun: '#sun'
+
+ show: ->
+ if not $('article#content #create-panel').length
+ $('article#content').prepend @render()
+ @bindUIElements()
+ @workloadChanged()
+ else
+ $('#create-panel').show()
+
+ hide: ->
+ $('#create-panel').hide()
+
+ render: ->
+ @template { }
+
+ submitPosition: (e) ->
+ e.preventDefault()
+ formData = @formData()
+ formData.created_at = new Date
+ formData.closed_at = new Date
+ formData.user_id = 83
+
+ position = new positionsApp.Models.Position formData
+
+ positionsApp.vent.trigger 'position:add', position
+
+ position.save()
+
+ checkboxToValue: (box) ->
+ if box.is ':checked' then 1 else 0
+
+ formData: ->
+ title: @ui.title.val()
+ description: @ui.description.val()
+ workload: parseFloat @ui.workload.val(), 10
+ from: new Date @ui.from.val()
+ to: new Date @ui.to.val()
+ duration: @ui.duration.val()
+ indefinite: @ui.indefinite.val()
+ weekdays:
+ Mon: @checkboxToValue @ui.mon
+ Tue: @checkboxToValue @ui.tue
+ Wed: @checkboxToValue @ui.wed
+ Thu: @checkboxToValue @ui.thu
+ Fri: @checkboxToValue @ui.fri
+ Sat: @checkboxToValue @ui.sat
+ Sun: @checkboxToValue @ui.sun
+
+ workloadChanged: ->
+ workload = parseFloat @ui.workload.val(), 10
+ @ui.pensum.html Helpers.calculatePensum workload
+
diff --git a/assets/app/app.coffee b/assets/app/app.coffee
new file mode 100644
index 0000000..db55783
--- /dev/null
+++ b/assets/app/app.coffee
@@ -0,0 +1,298 @@
+Bejoo.sapiURL = window.Bejoo.sapiurl + "organisation/"
+
+Handlebars.registerHelper 'printDate', (date) ->
+ moment(date).format 'DD.MM.YYYY'
+
+Backbone.Marionette.TemplateCache::compileTemplate = (rawTemplate) ->
+ Handlebars.compile rawTemplate
+
+getAuthKey = ->
+ if sessionStorage.authKey
+ deferred = new $.Deferred
+
+ deferred.resolve
+ key: sessionStorage.authKey
+
+ deferred
+ else
+ request = $.ajax
+ url: "#{Bejoo.baseUrl}common/auth/key"
+ dataType: 'json'
+
+ request.done (data) ->
+ sessionStorage.authKey = data.key
+
+ request
+
+
+setAuthKey = (key) ->
+ originalSync = Backbone.sync
+
+ Backbone.sync = (method, model, options) ->
+ options.headers = options.headers || {};
+ _.extend options.headers, {'Authorization': "Token #{key}"}
+ originalSync.call(model, method, model, options);
+
+positionsApp = new Backbone.Marionette.Application
+
+positionsApp.addRegions
+ compoundView: '#compound-view'
+
+positionsApp.module 'Helpers', (Helpers, App, Backbone, Marionette, $, _) ->
+
+
+positionsApp.module 'Models', (Models, App, Backbone, Marionette, $, _) ->
+
+ class Models.Position extends Backbone.Model
+
+ class Models.Positions extends Backbone.Collection
+ model: Models.Position
+ url: "#{Bejoo.sapiURL}position"
+
+ class Models.Round extends Backbone.Model
+
+ close: ->
+ Bejoo.requestHelper "#{Bejoo.sapiURL}round/#{@get('id')}/close"
+
+ class Models.Rounds extends Backbone.Collection
+ model: Models.Round
+
+ initialize: ->
+ @listenTo @, 'add', (round, rounds) =>
+ name = round.get 'name'
+ processedName = if name is '' then "Runde #{@rounds.length - rounds.indexOf(round)}" else name
+ round.set 'name', processedName
+
+ comparator: (a, b) ->
+ if a.get('created_at') < b.get('created_at') then 1 else -1
+
+ class Models.Application extends Backbone.Model
+ promote: ->
+ Bejoo.requestHelper "#{Bejoo.sapiURL}application/#{@get('id')}/promote"
+
+ close: ->
+ Bejoo.requestHelper "#{Bejoo.sapiURL}application/#{@get('id')}/close"
+
+ class Models.Applications extends Backbone.Collection
+ model: Models.Application
+
+
+
+positionsApp.module 'Views', (Views, App, Backbone) ->
+
+ class Views.CreatePosition extends Marionette.View
+ template: Handlebars.compile $('#create-view-template').html()
+ el: 'article#content'
+ events:
+ 'click .submit-position': 'submitPosition'
+ 'click .x': 'hide'
+ 'change #workload-position': 'workloadChanged'
+
+ ui:
+ title: '.title-position'
+ description: '.description-position'
+ workload: '#workload-position'
+ from: '.from-position'
+ to: '.to-position'
+ pensum: '.pensum-number'
+
+ initialize: ->
+
+ show: ->
+ if not $('article#content #create-panel').length
+ $('article#content').prepend @render()
+ @bindUIElements()
+ else
+ $('#create-panel').show()
+
+ hide: ->
+ $('#create-panel').hide()
+
+ render: ->
+ @template { }
+
+ onDomRefresh: ->
+ @workloadChanged()
+
+
+ submitPosition: (e) ->
+ e.preventDefault()
+ console.log 'submit'
+ formData = @formData()
+ formData.created_at = new Date
+ formData.closed_at = new Date
+ formData.user_id = 83
+ console.log formData
+
+ position = new positionsApp.Models.Position formData
+
+ positionsApp.vent.trigger 'position:add', position
+
+ position.save()
+
+ formData: ->
+ title: @ui.title.val()
+ description: @ui.description.val()
+ workload: parseFloat @ui.workload.val(), 10
+ from: new Date @ui.from.val()
+ to: new Date @ui.to.val()
+
+ calculatePensum: (weekMax, workload) ->
+ Math.round(workload / weekMax * 1000) / 10
+
+ workloadChanged: ->
+ workload = parseFloat @ui.workload.val(), 10
+ @ui.pensum.html @calculatePensum 40, workload
+
+
+ class Views.PositionListView extends Backbone.Marionette.ItemView
+ template: '#position-list-item-template'
+ tagName: 'li'
+ className: 'list-group-item position-list-element'
+ events:
+ 'click': 'selectPosition'
+
+ selectPosition: ->
+ App.vent.trigger 'positionsList:selected', @model.get 'id'
+
+ class Views.PositionsListView extends Backbone.Marionette.CompositeView
+ tagName: 'ul'
+ className: 'list-group'
+ itemView: Views.PositionListView
+ template: '#position-list-view-template'
+ itemViewContainer: '.position-list-view-container'
+
+ events:
+ 'click #create-position': 'createPosition'
+
+ createPosition: ->
+ if not @createView
+ @createView = new Views.CreatePosition
+ @createView.show()
+
+
+ class Views.RoundView extends Backbone.Marionette.ItemView
+ template: '#positions-round-template'
+ className: 'position-round-element'
+ events:
+ 'click .close-round': 'closeRound'
+
+ onRender: ->
+ applicationsCollection = new App.Models.Applications @model.get 'applications'
+
+ applicationsView = new App.Views.ApplicationsView
+ collection: applicationsCollection
+
+ @$el.append applicationsView.el
+ applicationsView.render()
+
+ closeRound: ->
+ @model.close()
+
+ class Views.RoundsView extends Backbone.Marionette.CollectionView
+ itemView: Views.RoundView
+
+ class Views.ApplicationView extends Backbone.Marionette.ItemView
+ template: '#positions-appliation-template'
+ className: 'position-application-element col-md-2'
+ events:
+ 'click .application-accept': 'acceptApplication'
+ 'click .application-decline': 'closeApplication'
+
+ acceptApplication: ->
+ @model.collection.trigger 'application:accepted'
+ @model.promote()
+
+ closeApplication: ->
+ @model.collection.trigger 'application:closed'
+ @model.close()
+
+ onRender: ->
+ console.log @model
+
+ class Views.ApplicationsView extends Backbone.Marionette.CollectionView
+ itemView: Views.ApplicationView
+ className: 'row'
+
+ class Views.PositionView extends Backbone.Marionette.CompositeView
+ template: '#position-item-template'
+ className: 'panel panel-default'
+ itemView: Views.RoundView
+ itemViewContainer: '.rounds'
+
+ onRender: ->
+ roundCollection = @model.get 'rounds'
+
+ roundsView = new App.Views.RoundsView
+ collection: roundCollection
+
+ @$el.append roundsView.el
+ roundsView.render()
+
+ # @$el.affix
+ # offset:
+ # top: 80
+
+positionsApp.module 'Controller', (PositionsController, App, Backbone, Marionette, $, _) ->
+
+ class PositionsController.Controller extends Marionette.Controller
+ constructor: ->
+ @positions = new App.Models.Positions
+
+ start: ->
+ that = @
+ authKeyRequest = getAuthKey()
+ authKeyRequest.done (keyData) =>
+ Bejoo.requestHelper = (url, data) ->
+ $.ajax
+ dataType: 'json'
+ url: url
+ data: data
+ type: 'POST'
+ headers: {'Authorization': "Token #{keyData.key}"}
+
+ setAuthKey keyData.key
+
+ @init()
+
+ App.vent.on 'position:add', (position) ->
+ that.positions.add position
+
+ init: ->
+ compoundView = new Marionette.CompoundView
+ listView: App.Views.PositionsListView,
+ itemView: App.Views.PositionView,
+ collection: @positions,
+ template: '#compound-view-template',
+ breakWidth: 750
+
+ request = @prepareData()
+ request.then ->
+ App.compoundView.show compoundView
+
+ prepareData: ->
+ request = @positions.fetch()
+
+ request.then =>
+ @positions.forEach (position) ->
+ rounds = new App.Models.Rounds position.get('rounds')
+
+ counter = rounds.length
+
+ rounds.forEach (round) ->
+ counter = counter - 1
+ name = round.get 'name'
+ round.set 'name', if name is '' then "Runde #{counter}" else name
+
+ position.set 'rounds', rounds
+ #console.log position
+
+
+ PositionsController.addInitializer ->
+ controller = new PositionsController.Controller
+
+ controller.start()
+
+
+positionsApp.start()
+
diff --git a/assets/app/app.js b/assets/app/app.js
new file mode 100644
index 0000000..3c3b4c0
--- /dev/null
+++ b/assets/app/app.js
@@ -0,0 +1,205 @@
+// Generated by CoffeeScript 1.6.3
+(function() {
+ var positionsApp,
+ __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ Bejoo.sapiURL = window.Bejoo.sapiurl + "organisation/";
+
+ Handlebars.registerHelper('printDate', function(date) {
+ return moment(date).format('DD.MM.YYYY');
+ });
+
+ Backbone.Marionette.TemplateCache.prototype.compileTemplate = function(rawTemplate) {
+ return Handlebars.compile(rawTemplate);
+ };
+
+ positionsApp.module('Models', function(Models, App, Backbone, Marionette, $, _) {
+ var _ref, _ref1;
+ Models.Position = (function(_super) {
+ __extends(Position, _super);
+
+ function Position() {
+ _ref = Position.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ Position.prototype.parse = function(pos) {
+ pos.from = new Date(pos.from);
+ pos.to = new Date(pos.to);
+ return pos;
+ };
+
+ return Position;
+
+ })(Backbone.Model);
+ return Models.Positions = (function(_super) {
+ __extends(Positions, _super);
+
+ function Positions() {
+ _ref1 = Positions.__super__.constructor.apply(this, arguments);
+ return _ref1;
+ }
+
+ Positions.prototype.model = Models.Position;
+
+ Positions.prototype.url = "" + Bejoo.sapiURL + "position";
+
+ Positions.prototype.comparator = function(a, b) {
+ if (a.get('from') > b.get('from')) {
+ return 1;
+ } else {
+ return -1;
+ }
+ };
+
+ return Positions;
+
+ })(Backbone.Collection);
+ });
+
+ positionsApp = new Backbone.Marionette.Application;
+
+ positionsApp.module('Controller', function(PositionsController, App, Backbone, Marionette, $, _) {
+ PositionsController.Controller = (function(_super) {
+ __extends(Controller, _super);
+
+ function Controller() {}
+
+ Controller.prototype.start = function() {
+ var createView;
+ createView = new positionsApp.View.CreatePosition();
+ createView.show();
+ return App.vent.on('position:add', function(position) {
+ return that.positions.add(position);
+ });
+ };
+
+ return Controller;
+
+ })(Marionette.Controller);
+ return PositionsController.addInitializer(function() {
+ var controller;
+ controller = new PositionsController.Controller;
+ return controller.start();
+ });
+ });
+
+ positionsApp.module('Views', function(Views, App, Backbone) {
+ var Helpers, _ref;
+ Helpers = {
+ calculatePensum: (function(weeklyHours) {
+ return function(workload) {
+ return Math.round(workload / weeklyHours * 1000) / 10;
+ };
+ })(Bejoo.organisation.weeklyHours)
+ };
+ return Views.CreatePosition = (function(_super) {
+ __extends(CreatePosition, _super);
+
+ function CreatePosition() {
+ _ref = CreatePosition.__super__.constructor.apply(this, arguments);
+ return _ref;
+ }
+
+ CreatePosition.prototype.template = Handlebars.compile($('#create-view-template').html());
+
+ CreatePosition.prototype.el = 'article#content';
+
+ CreatePosition.prototype.events = {
+ 'click .submit-position': 'submitPosition',
+ 'click .x': 'hide',
+ 'change #workload-position': 'workloadChanged'
+ };
+
+ CreatePosition.prototype.ui = {
+ title: '.title-position',
+ indefinite: '#indefinite',
+ description: '.description-position',
+ workload: '#workload-position',
+ from: '.from-position',
+ to: '.to-position',
+ pensum: '.pensum-number',
+ duration: '#duration',
+ mon: '#mon',
+ tue: '#tue',
+ wed: '#wed',
+ thu: '#thu',
+ fri: '#fri',
+ sat: '#sat',
+ sun: '#sun'
+ };
+
+ CreatePosition.prototype.show = function() {
+ if (!$('article#content #create-panel').length) {
+ $('article#content').prepend(this.render());
+ this.bindUIElements();
+ return this.workloadChanged();
+ } else {
+ return $('#create-panel').show();
+ }
+ };
+
+ CreatePosition.prototype.hide = function() {
+ return $('#create-panel').hide();
+ };
+
+ CreatePosition.prototype.render = function() {
+ return this.template({});
+ };
+
+ CreatePosition.prototype.submitPosition = function(e) {
+ var formData, position;
+ e.preventDefault();
+ formData = this.formData();
+ formData.created_at = new Date;
+ formData.closed_at = new Date;
+ formData.user_id = 83;
+ position = new positionsApp.Models.Position(formData);
+ positionsApp.vent.trigger('position:add', position);
+ return position.save();
+ };
+
+ CreatePosition.prototype.checkboxToValue = function(box) {
+ if (box.is(':checked')) {
+ return 1;
+ } else {
+ return 0;
+ }
+ };
+
+ CreatePosition.prototype.formData = function() {
+ return {
+ title: this.ui.title.val(),
+ description: this.ui.description.val(),
+ workload: parseFloat(this.ui.workload.val(), 10),
+ from: new Date(this.ui.from.val()),
+ to: new Date(this.ui.to.val()),
+ duration: this.ui.duration.val(),
+ indefinite: this.ui.indefinite.val(),
+ weekdays: {
+ Mon: this.checkboxToValue(this.ui.mon),
+ Tue: this.checkboxToValue(this.ui.tue),
+ Wed: this.checkboxToValue(this.ui.wed),
+ Thu: this.checkboxToValue(this.ui.thu),
+ Fri: this.checkboxToValue(this.ui.fri),
+ Sat: this.checkboxToValue(this.ui.sat),
+ Sun: this.checkboxToValue(this.ui.sun)
+ }
+ };
+ };
+
+ CreatePosition.prototype.workloadChanged = function() {
+ var workload;
+ workload = parseFloat(this.ui.workload.val(), 10);
+ return this.ui.pensum.html(Helpers.calculatePensum(workload));
+ };
+
+ return CreatePosition;
+
+ })(Marionette.View);
+ });
+
+ positionsApp.start();
+
+}).call(this);
diff --git a/assets/app/app.map b/assets/app/app.map
new file mode 100644
index 0000000..3259e38
--- /dev/null
+++ b/assets/app/app.map
@@ -0,0 +1,10 @@
+{
+ "version": 3,
+ "file": "app.js",
+ "sourceRoot": "../../../../..",
+ "sources": [
+ "assets/scripts/organisation/stellenausschreibung/app/app.coffee"
+ ],
+ "names": [],
+ "mappings": "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"
+}
\ No newline at end of file
diff --git a/assets/bsetup.coffee b/assets/bsetup.coffee
new file mode 100644
index 0000000..8099e60
--- /dev/null
+++ b/assets/bsetup.coffee
@@ -0,0 +1,8 @@
+Bejoo.sapiURL = window.Bejoo.sapiurl + "organisation/"
+
+Handlebars.registerHelper 'printDate', (date) ->
+ moment(date).format 'DD.MM.YYYY'
+
+Backbone.Marionette.TemplateCache::compileTemplate = (rawTemplate) ->
+ Handlebars.compile rawTemplate
+
diff --git a/assets/css/stellenausschreibung.css b/assets/css/stellenausschreibung.css
new file mode 100644
index 0000000..51b0bf1
--- /dev/null
+++ b/assets/css/stellenausschreibung.css
@@ -0,0 +1,12 @@
+#list .position-public{color:#2b93d1}
+.position-round-element h3{background-color:#0f3a50;padding:12px;color:#fff}
+li.position-list-element{background-color:#333;color:#fff}
+.position-list-view-container{padding:0}
+#nav-tabs{padding-left:15px}
+.caption p{margin-bottom:0}
+#list .position-list-element h3{font-size:18px;margin-top:0}
+.panel.affix{top:80px;width:calc(16.200000000000003%)}
+.position-application-element .closed h4 a{color:#808080}
+.position-application-element .closed img{-webkit-filter:grayscale(100%);filter:grayscale(100%)}
+.single-element-container{float:right}
+#list>div{height:400px;overflow:auto}
diff --git a/assets/dPositionsModels.coffee b/assets/dPositionsModels.coffee
new file mode 100644
index 0000000..eda62fe
--- /dev/null
+++ b/assets/dPositionsModels.coffee
@@ -0,0 +1,17 @@
+positionsApp.module 'Models', (Models, App, Backbone, Marionette, $, _) ->
+
+ class Models.Position extends Backbone.Model
+ parse: (pos) ->
+ pos.from = new Date pos.from
+ pos.to = new Date pos.to
+ pos
+
+ class Models.Positions extends Backbone.Collection
+ model: Models.Position
+ url: "#{Bejoo.sapiURL}position"
+
+ comparator: (a, b) ->
+ if a.get('from') > b.get('from')
+ 1
+ else
+ -1
diff --git a/assets/zinit.coffee b/assets/zinit.coffee
new file mode 100644
index 0000000..973f620
--- /dev/null
+++ b/assets/zinit.coffee
@@ -0,0 +1,2 @@
+positionsApp.start()
+
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..82f259a
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,31 @@
+{
+ "name": "bejoo",
+ "version": "0.0.1",
+ "private": true,
+ "dependencies": {
+ "jquery": "~2.0.3",
+ "underscore": "1.5.x",
+ "backbone": "1.1.x",
+ "backbone.marionette": "1.6.x",
+ "momentjs": "~2.4.0",
+ "bootstrap": "~3.0.0",
+ "messenger": "1.4.x",
+ "spinjs": "~1.3.2",
+ "selectize": "~0.8.5",
+ "bacon": "~0.7.0",
+ "bacon.jquery": "~0.4.0",
+ "raven-js": "~1.1.7",
+ "handlebars": "~1.3.0"
+ },
+ "ignore": [
+ "**/.*",
+ "node_modules/",
+ "components/",
+ "bower_components/",
+ "test/",
+ "tests/",
+ "docs/",
+ "tests/",
+ "examples/"
+ ]
+}
diff --git a/bower_components/backbone.babysitter/.bower.json b/bower_components/backbone.babysitter/.bower.json
new file mode 100644
index 0000000..5b5106c
--- /dev/null
+++ b/bower_components/backbone.babysitter/.bower.json
@@ -0,0 +1,14 @@
+{
+ "name": "backbone.babysitter",
+ "homepage": "https://github.com/marionettejs/backbone.babysitter",
+ "version": "0.0.6",
+ "_release": "0.0.6",
+ "_resolution": {
+ "type": "version",
+ "tag": "v0.0.6",
+ "commit": "49b2d401d3ee02021485512f2b089b8b97d1918d"
+ },
+ "_source": "git://github.com/marionettejs/backbone.babysitter.git",
+ "_target": "~0.0.6",
+ "_originalSource": "backbone.babysitter"
+}
\ No newline at end of file
diff --git a/bower_components/backbone.babysitter/.gitignore b/bower_components/backbone.babysitter/.gitignore
new file mode 100644
index 0000000..ec6903a
--- /dev/null
+++ b/bower_components/backbone.babysitter/.gitignore
@@ -0,0 +1,8 @@
+.DS_Store
+*.swp
+*.swo
+.grunt/
+node_modules
+_SpecRunner.html
+.idea
+npm-debug.log
diff --git a/bower_components/backbone.babysitter/.jshintrc b/bower_components/backbone.babysitter/.jshintrc
new file mode 100644
index 0000000..cacb6a7
--- /dev/null
+++ b/bower_components/backbone.babysitter/.jshintrc
@@ -0,0 +1,24 @@
+{
+ "curly": true,
+ "eqeqeq": true,
+ "immed": false,
+ "latedef": true,
+ "newcap": true,
+ "noarg": true,
+ "sub": true,
+ "undef": true,
+ "boss": true,
+ "eqnull": true,
+ "browser": true,
+ "globals": {
+ "jQuery": true,
+ "Backbone": true,
+ "_": true,
+ "Marionette": true,
+ "$": true,
+ "slice": true,
+ "require": true,
+ "define": true,
+ "module": true
+ }
+}
diff --git a/bower_components/backbone.babysitter/CHANGELOG.md b/bower_components/backbone.babysitter/CHANGELOG.md
new file mode 100644
index 0000000..4ad341d
--- /dev/null
+++ b/bower_components/backbone.babysitter/CHANGELOG.md
@@ -0,0 +1,29 @@
+# Change log
+
+### v0.0.6
+
+* Removed `.findByCollection` method
+* Added `.findByModelCid` method
+
+### v0.0.5
+
+* Updated build process to use GruntJS v0.4
+
+### v0.0.4
+
+* Added a fix for IE < 9, when applying a function to the views
+* Added `.pluck` as a method, from Underscore.js
+* Can specify an array of views to the container constructor
+
+### v0.0.3
+
+* Added iterators and other collection processing functions from Underscore.js
+
+### v0.0.2
+
+* Added `.length` attribute
+* Added `.findByIndex` method
+
+### v0.0.1
+
+* Initial release
diff --git a/bower_components/backbone.babysitter/Gruntfile.js b/bower_components/backbone.babysitter/Gruntfile.js
new file mode 100644
index 0000000..20cc8b5
--- /dev/null
+++ b/bower_components/backbone.babysitter/Gruntfile.js
@@ -0,0 +1,150 @@
+/*global module:false*/
+module.exports = function(grunt) {
+
+ // Project configuration.
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+ meta: {
+ version: '<%= pkg.version %>',
+ banner:
+ '// Backbone.BabySitter\n' +
+ '// -------------------\n' +
+ '// v<%= pkg.version %>\n' +
+ '//\n' +
+ '// Copyright (c)<%= grunt.template.today("yyyy") %> Derick Bailey, Muted Solutions, LLC.\n' +
+ '// Distributed under MIT license\n' +
+ '//\n' +
+ '// http://github.com/babysitterjs/backbone.babysitter\n' +
+ '\n'
+ },
+
+ lint: {
+ files: ['src/*.js']
+ },
+
+ preprocess: {
+ core_build: {
+ files: {
+ 'lib/backbone.babysitter.js' : 'src/childviewcontainer.js'
+ }
+ },
+ core_amd: {
+ files: {
+ 'lib/amd/backbone.babysitter.js' : 'src/amd.js'
+ }
+ },
+ },
+
+ concat: {
+ options: {
+ banner: "<%= meta.banner %>"
+ },
+ core: {
+ src: 'lib/backbone.babysitter.js',
+ dest: 'lib/backbone.babysitter.js'
+ },
+ amd: {
+ src: 'lib/amd/backbone.babysitter.js',
+ dest: 'lib/amd/backbone.babysitter.js'
+ }
+ },
+
+ uglify : {
+ options: {
+ banner: "<%= meta.banner %>"
+ },
+ amd : {
+ src : 'lib/amd/backbone.babysitter.js',
+ dest : 'lib/amd/backbone.babysitter.min.js',
+ },
+ core : {
+ src : 'lib/backbone.babysitter.js',
+ dest : 'lib/backbone.babysitter.min.js',
+ options : {
+ sourceMap : 'lib/backbone.babysitter.map',
+ sourceMappingURL : 'backbone.babysitter.map',
+ sourceMapPrefix : 2,
+ }
+ }
+ },
+
+ jasmine : {
+ options : {
+ helpers : 'spec/javascripts/helpers/*.js',
+ specs : 'spec/javascripts/**/*.spec.js',
+ vendor : [
+ 'public/javascripts/jquery.js',
+ 'public/javascripts/json2.js',
+ 'public/javascripts/underscore.js',
+ 'public/javascripts/backbone.js'
+ ],
+ },
+ coverage : {
+ src : '<%= jasmine.babysitter.src %>',
+ options : {
+ template : require('grunt-template-jasmine-istanbul'),
+ templateOptions: {
+ coverage: 'reports/coverage.json',
+ report: 'reports/coverage'
+ }
+ }
+ },
+ babysitter : {
+ src : ['src/*.js'],
+ }
+ },
+
+ jshint: {
+ options: {
+ jshintrc : '.jshintrc'
+ },
+ babysitter : [ 'src/*.js' ]
+ },
+ plato: {
+ babysitter : {
+ src : 'src/*.js',
+ dest : 'reports',
+ options : {
+ jshint : grunt.file.readJSON('.jshintrc')
+ }
+ }
+ },
+ watch: {
+ babysitter : {
+ files : ['src/*.js', 'spec/**/*.js'],
+ tasks : ['jshint', 'jasmine:babysitter']
+ },
+ server : {
+ files : ['src/*.js', 'spec/**/*.js'],
+ tasks : ['jasmine:babysitter:build']
+ }
+ },
+
+ connect: {
+ server: {
+ options: {
+ port: 8888
+ }
+ }
+ }
+ });
+
+ grunt.loadNpmTasks('grunt-preprocess');
+ grunt.loadNpmTasks('grunt-contrib-jasmine');
+ grunt.loadNpmTasks('grunt-contrib-concat');
+ grunt.loadNpmTasks('grunt-contrib-jshint');
+ grunt.loadNpmTasks('grunt-contrib-uglify');
+ grunt.loadNpmTasks('grunt-contrib-watch');
+ grunt.loadNpmTasks('grunt-contrib-connect');
+ grunt.loadNpmTasks('grunt-plato');
+
+ grunt.registerTask('test', ['jshint', 'jasmine:babysitter']);
+
+ grunt.registerTask('dev', ['test', 'watch:babysitter']);
+
+ grunt.registerTask('server', ['jasmine:babysitter:build', 'connect:server', 'watch:server']);
+
+ // Default task.
+ grunt.registerTask('default', ['jshint', 'jasmine:coverage', 'preprocess', 'concat', 'uglify']);
+
+};
diff --git a/bower_components/backbone.babysitter/LICENSE.md b/bower_components/backbone.babysitter/LICENSE.md
new file mode 100644
index 0000000..1ec483c
--- /dev/null
+++ b/bower_components/backbone.babysitter/LICENSE.md
@@ -0,0 +1,5 @@
+# Backbone.BabySitter
+
+Copyright (C)2013 Derick Bailey, Muted Solutions, LLC
+
+Distributed Under [MIT License](http://mutedsolutions.mit-license.org/)
diff --git a/bower_components/backbone.babysitter/lib/amd/backbone.babysitter.js b/bower_components/backbone.babysitter/lib/amd/backbone.babysitter.js
new file mode 100644
index 0000000..a182eda
--- /dev/null
+++ b/bower_components/backbone.babysitter/lib/amd/backbone.babysitter.js
@@ -0,0 +1,178 @@
+// Backbone.BabySitter
+// -------------------
+// v0.0.6
+//
+// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+//
+// http://github.com/babysitterjs/backbone.babysitter
+
+(function (root, factory) {
+ if (typeof exports === 'object') {
+
+ var underscore = require('underscore');
+ var backbone = require('backbone');
+
+ module.exports = factory(underscore, backbone);
+
+ } else if (typeof define === 'function' && define.amd) {
+
+ define(['underscore', 'backbone'], factory);
+
+ }
+}(this, function (_, Backbone) {
+ "option strict";
+
+ // Backbone.ChildViewContainer
+// ---------------------------
+//
+// Provide a container to store, retrieve and
+// shut down child views.
+
+Backbone.ChildViewContainer = (function(Backbone, _){
+
+ // Container Constructor
+ // ---------------------
+
+ var Container = function(views){
+ this._views = {};
+ this._indexByModel = {};
+ this._indexByCustom = {};
+ this._updateLength();
+
+ _.each(views, this.add, this);
+ };
+
+ // Container Methods
+ // -----------------
+
+ _.extend(Container.prototype, {
+
+ // Add a view to this container. Stores the view
+ // by `cid` and makes it searchable by the model
+ // cid (and model itself). Optionally specify
+ // a custom key to store an retrieve the view.
+ add: function(view, customIndex){
+ var viewCid = view.cid;
+
+ // store the view
+ this._views[viewCid] = view;
+
+ // index it by model
+ if (view.model){
+ this._indexByModel[view.model.cid] = viewCid;
+ }
+
+ // index by custom
+ if (customIndex){
+ this._indexByCustom[customIndex] = viewCid;
+ }
+
+ this._updateLength();
+ },
+
+ // Find a view by the model that was attached to
+ // it. Uses the model's `cid` to find it.
+ findByModel: function(model){
+ return this.findByModelCid(model.cid);
+ },
+
+ // Find a view by the `cid` of the model that was attached to
+ // it. Uses the model's `cid` to find the view `cid` and
+ // retrieve the view using it.
+ findByModelCid: function(modelCid){
+ var viewCid = this._indexByModel[modelCid];
+ return this.findByCid(viewCid);
+ },
+
+ // Find a view by a custom indexer.
+ findByCustom: function(index){
+ var viewCid = this._indexByCustom[index];
+ return this.findByCid(viewCid);
+ },
+
+ // Find by index. This is not guaranteed to be a
+ // stable index.
+ findByIndex: function(index){
+ return _.values(this._views)[index];
+ },
+
+ // retrieve a view by it's `cid` directly
+ findByCid: function(cid){
+ return this._views[cid];
+ },
+
+ // Remove a view
+ remove: function(view){
+ var viewCid = view.cid;
+
+ // delete model index
+ if (view.model){
+ delete this._indexByModel[view.model.cid];
+ }
+
+ // delete custom index
+ _.any(this._indexByCustom, function(cid, key) {
+ if (cid === viewCid) {
+ delete this._indexByCustom[key];
+ return true;
+ }
+ }, this);
+
+ // remove the view from the container
+ delete this._views[viewCid];
+
+ // update the length
+ this._updateLength();
+ },
+
+ // Call a method on every view in the container,
+ // passing parameters to the call method one at a
+ // time, like `function.call`.
+ call: function(method){
+ this.apply(method, _.tail(arguments));
+ },
+
+ // Apply a method on every view in the container,
+ // passing parameters to the call method one at a
+ // time, like `function.apply`.
+ apply: function(method, args){
+ _.each(this._views, function(view){
+ if (_.isFunction(view[method])){
+ view[method].apply(view, args || []);
+ }
+ });
+ },
+
+ // Update the `.length` attribute on this container
+ _updateLength: function(){
+ this.length = _.size(this._views);
+ }
+ });
+
+ // Borrowing this code from Backbone.Collection:
+ // http://backbonejs.org/docs/backbone.html#section-106
+ //
+ // Mix in methods from Underscore, for iteration, and other
+ // collection related features.
+ var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',
+ 'select', 'reject', 'every', 'all', 'some', 'any', 'include',
+ 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',
+ 'last', 'without', 'isEmpty', 'pluck'];
+
+ _.each(methods, function(method) {
+ Container.prototype[method] = function() {
+ var views = _.values(this._views);
+ var args = [views].concat(_.toArray(arguments));
+ return _[method].apply(_, args);
+ };
+ });
+
+ // return the public API
+ return Container;
+})(Backbone, _);
+
+ return Backbone.ChildViewContainer;
+
+}));
+
diff --git a/bower_components/backbone.babysitter/lib/amd/backbone.babysitter.min.js b/bower_components/backbone.babysitter/lib/amd/backbone.babysitter.min.js
new file mode 100644
index 0000000..78355c8
--- /dev/null
+++ b/bower_components/backbone.babysitter/lib/amd/backbone.babysitter.min.js
@@ -0,0 +1,10 @@
+// Backbone.BabySitter
+// -------------------
+// v0.0.6
+//
+// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+//
+// http://github.com/babysitterjs/backbone.babysitter
+
+(function(i,e){if("object"==typeof exports){var t=require("underscore"),n=require("backbone");module.exports=e(t,n)}else"function"==typeof define&&define.amd&&define(["underscore","backbone"],e)})(this,function(i,e){"option strict";return e.ChildViewContainer=function(i,e){var t=function(i){this._views={},this._indexByModel={},this._indexByCustom={},this._updateLength(),e.each(i,this.add,this)};e.extend(t.prototype,{add:function(i,e){var t=i.cid;this._views[t]=i,i.model&&(this._indexByModel[i.model.cid]=t),e&&(this._indexByCustom[e]=t),this._updateLength()},findByModel:function(i){return this.findByModelCid(i.cid)},findByModelCid:function(i){var e=this._indexByModel[i];return this.findByCid(e)},findByCustom:function(i){var e=this._indexByCustom[i];return this.findByCid(e)},findByIndex:function(i){return e.values(this._views)[i]},findByCid:function(i){return this._views[i]},remove:function(i){var t=i.cid;i.model&&delete this._indexByModel[i.model.cid],e.any(this._indexByCustom,function(i,e){return i===t?(delete this._indexByCustom[e],!0):void 0},this),delete this._views[t],this._updateLength()},call:function(i){this.apply(i,e.tail(arguments))},apply:function(i,t){e.each(this._views,function(n){e.isFunction(n[i])&&n[i].apply(n,t||[])})},_updateLength:function(){this.length=e.size(this._views)}});var n=["forEach","each","map","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","toArray","first","initial","rest","last","without","isEmpty","pluck"];return e.each(n,function(i){t.prototype[i]=function(){var t=e.values(this._views),n=[t].concat(e.toArray(arguments));return e[i].apply(e,n)}}),t}(e,i),e.ChildViewContainer});
\ No newline at end of file
diff --git a/bower_components/backbone.babysitter/lib/backbone.babysitter.js b/bower_components/backbone.babysitter/lib/backbone.babysitter.js
new file mode 100644
index 0000000..8190ad3
--- /dev/null
+++ b/bower_components/backbone.babysitter/lib/backbone.babysitter.js
@@ -0,0 +1,157 @@
+// Backbone.BabySitter
+// -------------------
+// v0.0.6
+//
+// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+//
+// http://github.com/babysitterjs/backbone.babysitter
+
+// Backbone.ChildViewContainer
+// ---------------------------
+//
+// Provide a container to store, retrieve and
+// shut down child views.
+
+Backbone.ChildViewContainer = (function(Backbone, _){
+
+ // Container Constructor
+ // ---------------------
+
+ var Container = function(views){
+ this._views = {};
+ this._indexByModel = {};
+ this._indexByCustom = {};
+ this._updateLength();
+
+ _.each(views, this.add, this);
+ };
+
+ // Container Methods
+ // -----------------
+
+ _.extend(Container.prototype, {
+
+ // Add a view to this container. Stores the view
+ // by `cid` and makes it searchable by the model
+ // cid (and model itself). Optionally specify
+ // a custom key to store an retrieve the view.
+ add: function(view, customIndex){
+ var viewCid = view.cid;
+
+ // store the view
+ this._views[viewCid] = view;
+
+ // index it by model
+ if (view.model){
+ this._indexByModel[view.model.cid] = viewCid;
+ }
+
+ // index by custom
+ if (customIndex){
+ this._indexByCustom[customIndex] = viewCid;
+ }
+
+ this._updateLength();
+ },
+
+ // Find a view by the model that was attached to
+ // it. Uses the model's `cid` to find it.
+ findByModel: function(model){
+ return this.findByModelCid(model.cid);
+ },
+
+ // Find a view by the `cid` of the model that was attached to
+ // it. Uses the model's `cid` to find the view `cid` and
+ // retrieve the view using it.
+ findByModelCid: function(modelCid){
+ var viewCid = this._indexByModel[modelCid];
+ return this.findByCid(viewCid);
+ },
+
+ // Find a view by a custom indexer.
+ findByCustom: function(index){
+ var viewCid = this._indexByCustom[index];
+ return this.findByCid(viewCid);
+ },
+
+ // Find by index. This is not guaranteed to be a
+ // stable index.
+ findByIndex: function(index){
+ return _.values(this._views)[index];
+ },
+
+ // retrieve a view by it's `cid` directly
+ findByCid: function(cid){
+ return this._views[cid];
+ },
+
+ // Remove a view
+ remove: function(view){
+ var viewCid = view.cid;
+
+ // delete model index
+ if (view.model){
+ delete this._indexByModel[view.model.cid];
+ }
+
+ // delete custom index
+ _.any(this._indexByCustom, function(cid, key) {
+ if (cid === viewCid) {
+ delete this._indexByCustom[key];
+ return true;
+ }
+ }, this);
+
+ // remove the view from the container
+ delete this._views[viewCid];
+
+ // update the length
+ this._updateLength();
+ },
+
+ // Call a method on every view in the container,
+ // passing parameters to the call method one at a
+ // time, like `function.call`.
+ call: function(method){
+ this.apply(method, _.tail(arguments));
+ },
+
+ // Apply a method on every view in the container,
+ // passing parameters to the call method one at a
+ // time, like `function.apply`.
+ apply: function(method, args){
+ _.each(this._views, function(view){
+ if (_.isFunction(view[method])){
+ view[method].apply(view, args || []);
+ }
+ });
+ },
+
+ // Update the `.length` attribute on this container
+ _updateLength: function(){
+ this.length = _.size(this._views);
+ }
+ });
+
+ // Borrowing this code from Backbone.Collection:
+ // http://backbonejs.org/docs/backbone.html#section-106
+ //
+ // Mix in methods from Underscore, for iteration, and other
+ // collection related features.
+ var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',
+ 'select', 'reject', 'every', 'all', 'some', 'any', 'include',
+ 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',
+ 'last', 'without', 'isEmpty', 'pluck'];
+
+ _.each(methods, function(method) {
+ Container.prototype[method] = function() {
+ var views = _.values(this._views);
+ var args = [views].concat(_.toArray(arguments));
+ return _[method].apply(_, args);
+ };
+ });
+
+ // return the public API
+ return Container;
+})(Backbone, _);
diff --git a/bower_components/backbone.babysitter/lib/backbone.babysitter.map b/bower_components/backbone.babysitter/lib/backbone.babysitter.map
new file mode 100644
index 0000000..7f03801
--- /dev/null
+++ b/bower_components/backbone.babysitter/lib/backbone.babysitter.map
@@ -0,0 +1 @@
+{"version":3,"file":"lib/backbone.babysitter.min.js","sources":["?"],"names":["Backbone","ChildViewContainer","_","Container","views","this","_views","_indexByModel","_indexByCustom","_updateLength","each","add","extend","prototype","view","customIndex","viewCid","cid","model","findByModel","findByModelCid","modelCid","findByCid","findByCustom","index","findByIndex","values","remove","any","key","call","method","apply","tail","arguments","args","isFunction","length","size","methods","concat","toArray"],"mappings":"AAeAA,SAASC,mBAAqB,SAAUD,EAAUE,GAKhD,GAAIC,GAAY,SAASC,GACvBC,KAAKC,UACLD,KAAKE,iBACLF,KAAKG,kBACLH,KAAKI,gBAELP,EAAEQ,KAAKN,EAAOC,KAAKM,IAAKN,MAM1BH,GAAEU,OAAOT,EAAUU,WAMjBF,IAAK,SAASG,EAAMC,GAClB,GAAIC,GAAUF,EAAKG,GAGnBZ,MAAKC,OAAOU,GAAWF,EAGnBA,EAAKI,QACPb,KAAKE,cAAcO,EAAKI,MAAMD,KAAOD,GAInCD,IACFV,KAAKG,eAAeO,GAAeC,GAGrCX,KAAKI,iBAKPU,YAAa,SAASD,GACpB,MAAOb,MAAKe,eAAeF,EAAMD,MAMnCG,eAAgB,SAASC,GACvB,GAAIL,GAAUX,KAAKE,cAAcc,EACjC,OAAOhB,MAAKiB,UAAUN,IAIxBO,aAAc,SAASC,GACrB,GAAIR,GAAUX,KAAKG,eAAegB,EAClC,OAAOnB,MAAKiB,UAAUN,IAKxBS,YAAa,SAASD,GACpB,MAAOtB,GAAEwB,OAAOrB,KAAKC,QAAQkB,IAI/BF,UAAW,SAASL,GAClB,MAAOZ,MAAKC,OAAOW,IAIrBU,OAAQ,SAASb,GACf,GAAIE,GAAUF,EAAKG,GAGfH,GAAKI,aACAb,MAAKE,cAAcO,EAAKI,MAAMD,KAIvCf,EAAE0B,IAAIvB,KAAKG,eAAgB,SAASS,EAAKY,GACvC,MAAIZ,KAAQD,SACHX,MAAKG,eAAeqB,IACpB,GAFT,QAICxB,YAGIA,MAAKC,OAAOU,GAGnBX,KAAKI,iBAMPqB,KAAM,SAASC,GACb1B,KAAK2B,MAAMD,EAAQ7B,EAAE+B,KAAKC,aAM5BF,MAAO,SAASD,EAAQI,GACtBjC,EAAEQ,KAAKL,KAAKC,OAAQ,SAASQ,GACvBZ,EAAEkC,WAAWtB,EAAKiB,KACpBjB,EAAKiB,GAAQC,MAAMlB,EAAMqB,UAM/B1B,cAAe,WACbJ,KAAKgC,OAASnC,EAAEoC,KAAKjC,KAAKC,UAS9B,IAAIiC,IAAW,UAAW,OAAQ,MAAO,OAAQ,SAAU,SACzD,SAAU,SAAU,QAAS,MAAO,OAAQ,MAAO,UACnD,WAAY,SAAU,UAAW,QAAS,UAAW,OACrD,OAAQ,UAAW,UAAW,QAWhC,OATArC,GAAEQ,KAAK6B,EAAS,SAASR,GACvB5B,EAAUU,UAAUkB,GAAU,WAC5B,GAAI3B,GAAQF,EAAEwB,OAAOrB,KAAKC,QACtB6B,GAAQ/B,GAAOoC,OAAOtC,EAAEuC,QAAQP,WACpC,OAAOhC,GAAE6B,GAAQC,MAAM9B,EAAGiC,MAKvBhC,GACNH,SAAUE"}
\ No newline at end of file
diff --git a/bower_components/backbone.babysitter/lib/backbone.babysitter.min.js b/bower_components/backbone.babysitter/lib/backbone.babysitter.min.js
new file mode 100644
index 0000000..e930c0f
--- /dev/null
+++ b/bower_components/backbone.babysitter/lib/backbone.babysitter.min.js
@@ -0,0 +1,11 @@
+// Backbone.BabySitter
+// -------------------
+// v0.0.6
+//
+// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+//
+// http://github.com/babysitterjs/backbone.babysitter
+
+Backbone.ChildViewContainer=function(i,t){var e=function(i){this._views={},this._indexByModel={},this._indexByCustom={},this._updateLength(),t.each(i,this.add,this)};t.extend(e.prototype,{add:function(i,t){var e=i.cid;this._views[e]=i,i.model&&(this._indexByModel[i.model.cid]=e),t&&(this._indexByCustom[t]=e),this._updateLength()},findByModel:function(i){return this.findByModelCid(i.cid)},findByModelCid:function(i){var t=this._indexByModel[i];return this.findByCid(t)},findByCustom:function(i){var t=this._indexByCustom[i];return this.findByCid(t)},findByIndex:function(i){return t.values(this._views)[i]},findByCid:function(i){return this._views[i]},remove:function(i){var e=i.cid;i.model&&delete this._indexByModel[i.model.cid],t.any(this._indexByCustom,function(i,t){return i===e?(delete this._indexByCustom[t],!0):void 0},this),delete this._views[e],this._updateLength()},call:function(i){this.apply(i,t.tail(arguments))},apply:function(i,e){t.each(this._views,function(n){t.isFunction(n[i])&&n[i].apply(n,e||[])})},_updateLength:function(){this.length=t.size(this._views)}});var n=["forEach","each","map","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","toArray","first","initial","rest","last","without","isEmpty","pluck"];return t.each(n,function(i){e.prototype[i]=function(){var e=t.values(this._views),n=[e].concat(t.toArray(arguments));return t[i].apply(t,n)}}),e}(Backbone,_);
+//@ sourceMappingURL=backbone.babysitter.map
\ No newline at end of file
diff --git a/bower_components/backbone.babysitter/package.json b/bower_components/backbone.babysitter/package.json
new file mode 100644
index 0000000..aaab9be
--- /dev/null
+++ b/bower_components/backbone.babysitter/package.json
@@ -0,0 +1,89 @@
+{
+ "name": "backbone.babysitter",
+ "description": "Manage child views in a Backbone.View",
+ "version": "0.0.6",
+ "homepage": "https://github.com/marionettejs/backbone.babysitter",
+ "main": "lib/amd/backbone.babysitter.js",
+ "keywords": [
+ "backbone",
+ "plugin",
+ "computed",
+ "field",
+ "model",
+ "client",
+ "browser"
+ ],
+
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/marionettejs/backbone.babysitter/blob/master/LICENSE.md"
+ }
+ ],
+
+ "scripts": {
+ "test" : "grunt jasmine",
+ "start" : "grunt jasmine-server"
+ },
+
+ "author": {
+ "name": "Derick Bailey",
+ "email": "marionettejs@gmail.com",
+ "web": "http://derickbailey.lostechies.com"
+ },
+
+ "bugs": {
+ "web": "https://github.com/marionettejs/backbone.babysitter/issues"
+ },
+
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/marionettejs/backbone.babysitter.git"
+ },
+
+ "github": "https://github.com/marionettejs/backbone.babysitter",
+
+ "dependencies": {
+ "jquery": "~1.8.3",
+ "backbone": "~1.0.0"
+ },
+ "devDependencies": {
+ "grunt": "~0.4.0",
+ "grunt-contrib-jasmine": "~0.3.1",
+ "grunt-contrib-jshint": "~0.1.1",
+ "grunt-plato": "~0.1.4",
+ "grunt-preprocess": "git://github.com/onehealth/grunt-preprocess.git#grunt-0.4.0",
+ "grunt-contrib-uglify": "~0.1.1",
+ "grunt-contrib-concat": "~0.1.2",
+ "grunt-template-jasmine-istanbul": "~0.1.1",
+ "grunt-contrib-watch": "~0.2.0",
+ "grunt-contrib-connect": "~0.1.2"
+ },
+ "jam":{
+ "dependencies": {
+ "backbone": ">=0.9.9",
+ "underscore": ">=1.4.0"
+ },
+ "main": "lib/amd/backbone.babysitter.js",
+ "include": [
+ "lib/amd/backbone.babysitter.js",
+ "readme.md"
+ ]
+ },
+ "maintainers": [
+ {
+ "name": "Stefan Zerkalica",
+ "email": "zerkalica@gmail.com",
+ "web": "https://github.com/zerkalica"
+ },
+ {
+ "name": "Richard Mitchell",
+ "email": "richard.j.mitchell@gmail.com"
+ },
+ {
+ "name": "Joe Gornick",
+ "web": "http://joegornick.com",
+ "twitter": "https://twitter.com/jgornick"
+ }
+ ]
+}
diff --git a/bower_components/backbone.babysitter/public/javascripts/backbone.js b/bower_components/backbone.babysitter/public/javascripts/backbone.js
new file mode 100644
index 0000000..3512d42
--- /dev/null
+++ b/bower_components/backbone.babysitter/public/javascripts/backbone.js
@@ -0,0 +1,1571 @@
+// Backbone.js 1.0.0
+
+// (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc.
+// Backbone may be freely distributed under the MIT license.
+// For all details and documentation:
+// http://backbonejs.org
+
+(function(){
+
+ // Initial Setup
+ // -------------
+
+ // Save a reference to the global object (`window` in the browser, `exports`
+ // on the server).
+ var root = this;
+
+ // Save the previous value of the `Backbone` variable, so that it can be
+ // restored later on, if `noConflict` is used.
+ var previousBackbone = root.Backbone;
+
+ // Create local references to array methods we'll want to use later.
+ var array = [];
+ var push = array.push;
+ var slice = array.slice;
+ var splice = array.splice;
+
+ // The top-level namespace. All public Backbone classes and modules will
+ // be attached to this. Exported for both the browser and the server.
+ var Backbone;
+ if (typeof exports !== 'undefined') {
+ Backbone = exports;
+ } else {
+ Backbone = root.Backbone = {};
+ }
+
+ // Current version of the library. Keep in sync with `package.json`.
+ Backbone.VERSION = '1.0.0';
+
+ // Require Underscore, if we're on the server, and it's not already present.
+ var _ = root._;
+ if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
+
+ // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
+ // the `$` variable.
+ Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;
+
+ // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
+ // to its previous owner. Returns a reference to this Backbone object.
+ Backbone.noConflict = function() {
+ root.Backbone = previousBackbone;
+ return this;
+ };
+
+ // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
+ // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and
+ // set a `X-Http-Method-Override` header.
+ Backbone.emulateHTTP = false;
+
+ // Turn on `emulateJSON` to support legacy servers that can't deal with direct
+ // `application/json` requests ... will encode the body as
+ // `application/x-www-form-urlencoded` instead and will send the model in a
+ // form param named `model`.
+ Backbone.emulateJSON = false;
+
+ // Backbone.Events
+ // ---------------
+
+ // A module that can be mixed in to *any object* in order to provide it with
+ // custom events. You may bind with `on` or remove with `off` callback
+ // functions to an event; `trigger`-ing an event fires all callbacks in
+ // succession.
+ //
+ // var object = {};
+ // _.extend(object, Backbone.Events);
+ // object.on('expand', function(){ alert('expanded'); });
+ // object.trigger('expand');
+ //
+ var Events = Backbone.Events = {
+
+ // Bind an event to a `callback` function. Passing `"all"` will bind
+ // the callback to all events fired.
+ on: function(name, callback, context) {
+ if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
+ this._events || (this._events = {});
+ var events = this._events[name] || (this._events[name] = []);
+ events.push({callback: callback, context: context, ctx: context || this});
+ return this;
+ },
+
+ // Bind an event to only be triggered a single time. After the first time
+ // the callback is invoked, it will be removed.
+ once: function(name, callback, context) {
+ if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
+ var self = this;
+ var once = _.once(function() {
+ self.off(name, once);
+ callback.apply(this, arguments);
+ });
+ once._callback = callback;
+ return this.on(name, once, context);
+ },
+
+ // Remove one or many callbacks. If `context` is null, removes all
+ // callbacks with that function. If `callback` is null, removes all
+ // callbacks for the event. If `name` is null, removes all bound
+ // callbacks for all events.
+ off: function(name, callback, context) {
+ var retain, ev, events, names, i, l, j, k;
+ if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
+ if (!name && !callback && !context) {
+ this._events = {};
+ return this;
+ }
+
+ names = name ? [name] : _.keys(this._events);
+ for (i = 0, l = names.length; i < l; i++) {
+ name = names[i];
+ if (events = this._events[name]) {
+ this._events[name] = retain = [];
+ if (callback || context) {
+ for (j = 0, k = events.length; j < k; j++) {
+ ev = events[j];
+ if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
+ (context && context !== ev.context)) {
+ retain.push(ev);
+ }
+ }
+ }
+ if (!retain.length) delete this._events[name];
+ }
+ }
+
+ return this;
+ },
+
+ // Trigger one or many events, firing all bound callbacks. Callbacks are
+ // passed the same arguments as `trigger` is, apart from the event name
+ // (unless you're listening on `"all"`, which will cause your callback to
+ // receive the true name of the event as the first argument).
+ trigger: function(name) {
+ if (!this._events) return this;
+ var args = slice.call(arguments, 1);
+ if (!eventsApi(this, 'trigger', name, args)) return this;
+ var events = this._events[name];
+ var allEvents = this._events.all;
+ if (events) triggerEvents(events, args);
+ if (allEvents) triggerEvents(allEvents, arguments);
+ return this;
+ },
+
+ // Tell this object to stop listening to either specific events ... or
+ // to every object it's currently listening to.
+ stopListening: function(obj, name, callback) {
+ var listeners = this._listeners;
+ if (!listeners) return this;
+ var deleteListener = !name && !callback;
+ if (typeof name === 'object') callback = this;
+ if (obj) (listeners = {})[obj._listenerId] = obj;
+ for (var id in listeners) {
+ listeners[id].off(name, callback, this);
+ if (deleteListener) delete this._listeners[id];
+ }
+ return this;
+ }
+
+ };
+
+ // Regular expression used to split event strings.
+ var eventSplitter = /\s+/;
+
+ // Implement fancy features of the Events API such as multiple event
+ // names `"change blur"` and jQuery-style event maps `{change: action}`
+ // in terms of the existing API.
+ var eventsApi = function(obj, action, name, rest) {
+ if (!name) return true;
+
+ // Handle event maps.
+ if (typeof name === 'object') {
+ for (var key in name) {
+ obj[action].apply(obj, [key, name[key]].concat(rest));
+ }
+ return false;
+ }
+
+ // Handle space separated event names.
+ if (eventSplitter.test(name)) {
+ var names = name.split(eventSplitter);
+ for (var i = 0, l = names.length; i < l; i++) {
+ obj[action].apply(obj, [names[i]].concat(rest));
+ }
+ return false;
+ }
+
+ return true;
+ };
+
+ // A difficult-to-believe, but optimized internal dispatch function for
+ // triggering events. Tries to keep the usual cases speedy (most internal
+ // Backbone events have 3 arguments).
+ var triggerEvents = function(events, args) {
+ var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
+ switch (args.length) {
+ case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
+ case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
+ case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
+ case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
+ default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
+ }
+ };
+
+ var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
+
+ // Inversion-of-control versions of `on` and `once`. Tell *this* object to
+ // listen to an event in another object ... keeping track of what it's
+ // listening to.
+ _.each(listenMethods, function(implementation, method) {
+ Events[method] = function(obj, name, callback) {
+ var listeners = this._listeners || (this._listeners = {});
+ var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
+ listeners[id] = obj;
+ if (typeof name === 'object') callback = this;
+ obj[implementation](name, callback, this);
+ return this;
+ };
+ });
+
+ // Aliases for backwards compatibility.
+ Events.bind = Events.on;
+ Events.unbind = Events.off;
+
+ // Allow the `Backbone` object to serve as a global event bus, for folks who
+ // want global "pubsub" in a convenient place.
+ _.extend(Backbone, Events);
+
+ // Backbone.Model
+ // --------------
+
+ // Backbone **Models** are the basic data object in the framework --
+ // frequently representing a row in a table in a database on your server.
+ // A discrete chunk of data and a bunch of useful, related methods for
+ // performing computations and transformations on that data.
+
+ // Create a new model with the specified attributes. A client id (`cid`)
+ // is automatically generated and assigned for you.
+ var Model = Backbone.Model = function(attributes, options) {
+ var defaults;
+ var attrs = attributes || {};
+ options || (options = {});
+ this.cid = _.uniqueId('c');
+ this.attributes = {};
+ _.extend(this, _.pick(options, modelOptions));
+ if (options.parse) attrs = this.parse(attrs, options) || {};
+ if (defaults = _.result(this, 'defaults')) {
+ attrs = _.defaults({}, attrs, defaults);
+ }
+ this.set(attrs, options);
+ this.changed = {};
+ this.initialize.apply(this, arguments);
+ };
+
+ // A list of options to be attached directly to the model, if provided.
+ var modelOptions = ['url', 'urlRoot', 'collection'];
+
+ // Attach all inheritable methods to the Model prototype.
+ _.extend(Model.prototype, Events, {
+
+ // A hash of attributes whose current and previous value differ.
+ changed: null,
+
+ // The value returned during the last failed validation.
+ validationError: null,
+
+ // The default name for the JSON `id` attribute is `"id"`. MongoDB and
+ // CouchDB users may want to set this to `"_id"`.
+ idAttribute: 'id',
+
+ // Initialize is an empty function by default. Override it with your own
+ // initialization logic.
+ initialize: function(){},
+
+ // Return a copy of the model's `attributes` object.
+ toJSON: function(options) {
+ return _.clone(this.attributes);
+ },
+
+ // Proxy `Backbone.sync` by default -- but override this if you need
+ // custom syncing semantics for *this* particular model.
+ sync: function() {
+ return Backbone.sync.apply(this, arguments);
+ },
+
+ // Get the value of an attribute.
+ get: function(attr) {
+ return this.attributes[attr];
+ },
+
+ // Get the HTML-escaped value of an attribute.
+ escape: function(attr) {
+ return _.escape(this.get(attr));
+ },
+
+ // Returns `true` if the attribute contains a value that is not null
+ // or undefined.
+ has: function(attr) {
+ return this.get(attr) != null;
+ },
+
+ // Set a hash of model attributes on the object, firing `"change"`. This is
+ // the core primitive operation of a model, updating the data and notifying
+ // anyone who needs to know about the change in state. The heart of the beast.
+ set: function(key, val, options) {
+ var attr, attrs, unset, changes, silent, changing, prev, current;
+ if (key == null) return this;
+
+ // Handle both `"key", value` and `{key: value}` -style arguments.
+ if (typeof key === 'object') {
+ attrs = key;
+ options = val;
+ } else {
+ (attrs = {})[key] = val;
+ }
+
+ options || (options = {});
+
+ // Run validation.
+ if (!this._validate(attrs, options)) return false;
+
+ // Extract attributes and options.
+ unset = options.unset;
+ silent = options.silent;
+ changes = [];
+ changing = this._changing;
+ this._changing = true;
+
+ if (!changing) {
+ this._previousAttributes = _.clone(this.attributes);
+ this.changed = {};
+ }
+ current = this.attributes, prev = this._previousAttributes;
+
+ // Check for changes of `id`.
+ if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
+
+ // For each `set` attribute, update or delete the current value.
+ for (attr in attrs) {
+ val = attrs[attr];
+ if (!_.isEqual(current[attr], val)) changes.push(attr);
+ if (!_.isEqual(prev[attr], val)) {
+ this.changed[attr] = val;
+ } else {
+ delete this.changed[attr];
+ }
+ unset ? delete current[attr] : current[attr] = val;
+ }
+
+ // Trigger all relevant attribute changes.
+ if (!silent) {
+ if (changes.length) this._pending = true;
+ for (var i = 0, l = changes.length; i < l; i++) {
+ this.trigger('change:' + changes[i], this, current[changes[i]], options);
+ }
+ }
+
+ // You might be wondering why there's a `while` loop here. Changes can
+ // be recursively nested within `"change"` events.
+ if (changing) return this;
+ if (!silent) {
+ while (this._pending) {
+ this._pending = false;
+ this.trigger('change', this, options);
+ }
+ }
+ this._pending = false;
+ this._changing = false;
+ return this;
+ },
+
+ // Remove an attribute from the model, firing `"change"`. `unset` is a noop
+ // if the attribute doesn't exist.
+ unset: function(attr, options) {
+ return this.set(attr, void 0, _.extend({}, options, {unset: true}));
+ },
+
+ // Clear all attributes on the model, firing `"change"`.
+ clear: function(options) {
+ var attrs = {};
+ for (var key in this.attributes) attrs[key] = void 0;
+ return this.set(attrs, _.extend({}, options, {unset: true}));
+ },
+
+ // Determine if the model has changed since the last `"change"` event.
+ // If you specify an attribute name, determine if that attribute has changed.
+ hasChanged: function(attr) {
+ if (attr == null) return !_.isEmpty(this.changed);
+ return _.has(this.changed, attr);
+ },
+
+ // Return an object containing all the attributes that have changed, or
+ // false if there are no changed attributes. Useful for determining what
+ // parts of a view need to be updated and/or what attributes need to be
+ // persisted to the server. Unset attributes will be set to undefined.
+ // You can also pass an attributes object to diff against the model,
+ // determining if there *would be* a change.
+ changedAttributes: function(diff) {
+ if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
+ var val, changed = false;
+ var old = this._changing ? this._previousAttributes : this.attributes;
+ for (var attr in diff) {
+ if (_.isEqual(old[attr], (val = diff[attr]))) continue;
+ (changed || (changed = {}))[attr] = val;
+ }
+ return changed;
+ },
+
+ // Get the previous value of an attribute, recorded at the time the last
+ // `"change"` event was fired.
+ previous: function(attr) {
+ if (attr == null || !this._previousAttributes) return null;
+ return this._previousAttributes[attr];
+ },
+
+ // Get all of the attributes of the model at the time of the previous
+ // `"change"` event.
+ previousAttributes: function() {
+ return _.clone(this._previousAttributes);
+ },
+
+ // Fetch the model from the server. If the server's representation of the
+ // model differs from its current attributes, they will be overridden,
+ // triggering a `"change"` event.
+ fetch: function(options) {
+ options = options ? _.clone(options) : {};
+ if (options.parse === void 0) options.parse = true;
+ var model = this;
+ var success = options.success;
+ options.success = function(resp) {
+ if (!model.set(model.parse(resp, options), options)) return false;
+ if (success) success(model, resp, options);
+ model.trigger('sync', model, resp, options);
+ };
+ wrapError(this, options);
+ return this.sync('read', this, options);
+ },
+
+ // Set a hash of model attributes, and sync the model to the server.
+ // If the server returns an attributes hash that differs, the model's
+ // state will be `set` again.
+ save: function(key, val, options) {
+ var attrs, method, xhr, attributes = this.attributes;
+
+ // Handle both `"key", value` and `{key: value}` -style arguments.
+ if (key == null || typeof key === 'object') {
+ attrs = key;
+ options = val;
+ } else {
+ (attrs = {})[key] = val;
+ }
+
+ // If we're not waiting and attributes exist, save acts as `set(attr).save(null, opts)`.
+ if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false;
+
+ options = _.extend({validate: true}, options);
+
+ // Do not persist invalid models.
+ if (!this._validate(attrs, options)) return false;
+
+ // Set temporary attributes if `{wait: true}`.
+ if (attrs && options.wait) {
+ this.attributes = _.extend({}, attributes, attrs);
+ }
+
+ // After a successful server-side save, the client is (optionally)
+ // updated with the server-side state.
+ if (options.parse === void 0) options.parse = true;
+ var model = this;
+ var success = options.success;
+ options.success = function(resp) {
+ // Ensure attributes are restored during synchronous saves.
+ model.attributes = attributes;
+ var serverAttrs = model.parse(resp, options);
+ if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
+ if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
+ return false;
+ }
+ if (success) success(model, resp, options);
+ model.trigger('sync', model, resp, options);
+ };
+ wrapError(this, options);
+
+ method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
+ if (method === 'patch') options.attrs = attrs;
+ xhr = this.sync(method, this, options);
+
+ // Restore attributes.
+ if (attrs && options.wait) this.attributes = attributes;
+
+ return xhr;
+ },
+
+ // Destroy this model on the server if it was already persisted.
+ // Optimistically removes the model from its collection, if it has one.
+ // If `wait: true` is passed, waits for the server to respond before removal.
+ destroy: function(options) {
+ options = options ? _.clone(options) : {};
+ var model = this;
+ var success = options.success;
+
+ var destroy = function() {
+ model.trigger('destroy', model, model.collection, options);
+ };
+
+ options.success = function(resp) {
+ if (options.wait || model.isNew()) destroy();
+ if (success) success(model, resp, options);
+ if (!model.isNew()) model.trigger('sync', model, resp, options);
+ };
+
+ if (this.isNew()) {
+ options.success();
+ return false;
+ }
+ wrapError(this, options);
+
+ var xhr = this.sync('delete', this, options);
+ if (!options.wait) destroy();
+ return xhr;
+ },
+
+ // Default URL for the model's representation on the server -- if you're
+ // using Backbone's restful methods, override this to change the endpoint
+ // that will be called.
+ url: function() {
+ var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
+ if (this.isNew()) return base;
+ return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
+ },
+
+ // **parse** converts a response into the hash of attributes to be `set` on
+ // the model. The default implementation is just to pass the response along.
+ parse: function(resp, options) {
+ return resp;
+ },
+
+ // Create a new model with identical attributes to this one.
+ clone: function() {
+ return new this.constructor(this.attributes);
+ },
+
+ // A model is new if it has never been saved to the server, and lacks an id.
+ isNew: function() {
+ return this.id == null;
+ },
+
+ // Check if the model is currently in a valid state.
+ isValid: function(options) {
+ return this._validate({}, _.extend(options || {}, { validate: true }));
+ },
+
+ // Run validation against the next complete set of model attributes,
+ // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
+ _validate: function(attrs, options) {
+ if (!options.validate || !this.validate) return true;
+ attrs = _.extend({}, this.attributes, attrs);
+ var error = this.validationError = this.validate(attrs, options) || null;
+ if (!error) return true;
+ this.trigger('invalid', this, error, _.extend(options || {}, {validationError: error}));
+ return false;
+ }
+
+ });
+
+ // Underscore methods that we want to implement on the Model.
+ var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
+
+ // Mix in each Underscore method as a proxy to `Model#attributes`.
+ _.each(modelMethods, function(method) {
+ Model.prototype[method] = function() {
+ var args = slice.call(arguments);
+ args.unshift(this.attributes);
+ return _[method].apply(_, args);
+ };
+ });
+
+ // Backbone.Collection
+ // -------------------
+
+ // If models tend to represent a single row of data, a Backbone Collection is
+ // more analagous to a table full of data ... or a small slice or page of that
+ // table, or a collection of rows that belong together for a particular reason
+ // -- all of the messages in this particular folder, all of the documents
+ // belonging to this particular author, and so on. Collections maintain
+ // indexes of their models, both in order, and for lookup by `id`.
+
+ // Create a new **Collection**, perhaps to contain a specific type of `model`.
+ // If a `comparator` is specified, the Collection will maintain
+ // its models in sort order, as they're added and removed.
+ var Collection = Backbone.Collection = function(models, options) {
+ options || (options = {});
+ if (options.url) this.url = options.url;
+ if (options.model) this.model = options.model;
+ if (options.comparator !== void 0) this.comparator = options.comparator;
+ this._reset();
+ this.initialize.apply(this, arguments);
+ if (models) this.reset(models, _.extend({silent: true}, options));
+ };
+
+ // Default options for `Collection#set`.
+ var setOptions = {add: true, remove: true, merge: true};
+ var addOptions = {add: true, merge: false, remove: false};
+
+ // Define the Collection's inheritable methods.
+ _.extend(Collection.prototype, Events, {
+
+ // The default model for a collection is just a **Backbone.Model**.
+ // This should be overridden in most cases.
+ model: Model,
+
+ // Initialize is an empty function by default. Override it with your own
+ // initialization logic.
+ initialize: function(){},
+
+ // The JSON representation of a Collection is an array of the
+ // models' attributes.
+ toJSON: function(options) {
+ return this.map(function(model){ return model.toJSON(options); });
+ },
+
+ // Proxy `Backbone.sync` by default.
+ sync: function() {
+ return Backbone.sync.apply(this, arguments);
+ },
+
+ // Add a model, or list of models to the set.
+ add: function(models, options) {
+ return this.set(models, _.defaults(options || {}, addOptions));
+ },
+
+ // Remove a model, or a list of models from the set.
+ remove: function(models, options) {
+ models = _.isArray(models) ? models.slice() : [models];
+ options || (options = {});
+ var i, l, index, model;
+ for (i = 0, l = models.length; i < l; i++) {
+ model = this.get(models[i]);
+ if (!model) continue;
+ delete this._byId[model.id];
+ delete this._byId[model.cid];
+ index = this.indexOf(model);
+ this.models.splice(index, 1);
+ this.length--;
+ if (!options.silent) {
+ options.index = index;
+ model.trigger('remove', model, this, options);
+ }
+ this._removeReference(model);
+ }
+ return this;
+ },
+
+ // Update a collection by `set`-ing a new list of models, adding new ones,
+ // removing models that are no longer present, and merging models that
+ // already exist in the collection, as necessary. Similar to **Model#set**,
+ // the core operation for updating the data contained by the collection.
+ set: function(models, options) {
+ options = _.defaults(options || {}, setOptions);
+ if (options.parse) models = this.parse(models, options);
+ if (!_.isArray(models)) models = models ? [models] : [];
+ var i, l, model, attrs, existing, sort;
+ var at = options.at;
+ var sortable = this.comparator && (at == null) && options.sort !== false;
+ var sortAttr = _.isString(this.comparator) ? this.comparator : null;
+ var toAdd = [], toRemove = [], modelMap = {};
+
+ // Turn bare objects into model references, and prevent invalid models
+ // from being added.
+ for (i = 0, l = models.length; i < l; i++) {
+ if (!(model = this._prepareModel(models[i], options))) continue;
+
+ // If a duplicate is found, prevent it from being added and
+ // optionally merge it into the existing model.
+ if (existing = this.get(model)) {
+ if (options.remove) modelMap[existing.cid] = true;
+ if (options.merge) {
+ existing.set(model.attributes, options);
+ if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
+ }
+
+ // This is a new model, push it to the `toAdd` list.
+ } else if (options.add) {
+ toAdd.push(model);
+
+ // Listen to added models' events, and index models for lookup by
+ // `id` and by `cid`.
+ model.on('all', this._onModelEvent, this);
+ this._byId[model.cid] = model;
+ if (model.id != null) this._byId[model.id] = model;
+ }
+ }
+
+ // Remove nonexistent models if appropriate.
+ if (options.remove) {
+ for (i = 0, l = this.length; i < l; ++i) {
+ if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
+ }
+ if (toRemove.length) this.remove(toRemove, options);
+ }
+
+ // See if sorting is needed, update `length` and splice in new models.
+ if (toAdd.length) {
+ if (sortable) sort = true;
+ this.length += toAdd.length;
+ if (at != null) {
+ splice.apply(this.models, [at, 0].concat(toAdd));
+ } else {
+ push.apply(this.models, toAdd);
+ }
+ }
+
+ // Silently sort the collection if appropriate.
+ if (sort) this.sort({silent: true});
+
+ if (options.silent) return this;
+
+ // Trigger `add` events.
+ for (i = 0, l = toAdd.length; i < l; i++) {
+ (model = toAdd[i]).trigger('add', model, this, options);
+ }
+
+ // Trigger `sort` if the collection was sorted.
+ if (sort) this.trigger('sort', this, options);
+ return this;
+ },
+
+ // When you have more items than you want to add or remove individually,
+ // you can reset the entire set with a new list of models, without firing
+ // any granular `add` or `remove` events. Fires `reset` when finished.
+ // Useful for bulk operations and optimizations.
+ reset: function(models, options) {
+ options || (options = {});
+ for (var i = 0, l = this.models.length; i < l; i++) {
+ this._removeReference(this.models[i]);
+ }
+ options.previousModels = this.models;
+ this._reset();
+ this.add(models, _.extend({silent: true}, options));
+ if (!options.silent) this.trigger('reset', this, options);
+ return this;
+ },
+
+ // Add a model to the end of the collection.
+ push: function(model, options) {
+ model = this._prepareModel(model, options);
+ this.add(model, _.extend({at: this.length}, options));
+ return model;
+ },
+
+ // Remove a model from the end of the collection.
+ pop: function(options) {
+ var model = this.at(this.length - 1);
+ this.remove(model, options);
+ return model;
+ },
+
+ // Add a model to the beginning of the collection.
+ unshift: function(model, options) {
+ model = this._prepareModel(model, options);
+ this.add(model, _.extend({at: 0}, options));
+ return model;
+ },
+
+ // Remove a model from the beginning of the collection.
+ shift: function(options) {
+ var model = this.at(0);
+ this.remove(model, options);
+ return model;
+ },
+
+ // Slice out a sub-array of models from the collection.
+ slice: function(begin, end) {
+ return this.models.slice(begin, end);
+ },
+
+ // Get a model from the set by id.
+ get: function(obj) {
+ if (obj == null) return void 0;
+ return this._byId[obj.id != null ? obj.id : obj.cid || obj];
+ },
+
+ // Get the model at the given index.
+ at: function(index) {
+ return this.models[index];
+ },
+
+ // Return models with matching attributes. Useful for simple cases of
+ // `filter`.
+ where: function(attrs, first) {
+ if (_.isEmpty(attrs)) return first ? void 0 : [];
+ return this[first ? 'find' : 'filter'](function(model) {
+ for (var key in attrs) {
+ if (attrs[key] !== model.get(key)) return false;
+ }
+ return true;
+ });
+ },
+
+ // Return the first model with matching attributes. Useful for simple cases
+ // of `find`.
+ findWhere: function(attrs) {
+ return this.where(attrs, true);
+ },
+
+ // Force the collection to re-sort itself. You don't need to call this under
+ // normal circumstances, as the set will maintain sort order as each item
+ // is added.
+ sort: function(options) {
+ if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
+ options || (options = {});
+
+ // Run sort based on type of `comparator`.
+ if (_.isString(this.comparator) || this.comparator.length === 1) {
+ this.models = this.sortBy(this.comparator, this);
+ } else {
+ this.models.sort(_.bind(this.comparator, this));
+ }
+
+ if (!options.silent) this.trigger('sort', this, options);
+ return this;
+ },
+
+ // Figure out the smallest index at which a model should be inserted so as
+ // to maintain order.
+ sortedIndex: function(model, value, context) {
+ value || (value = this.comparator);
+ var iterator = _.isFunction(value) ? value : function(model) {
+ return model.get(value);
+ };
+ return _.sortedIndex(this.models, model, iterator, context);
+ },
+
+ // Pluck an attribute from each model in the collection.
+ pluck: function(attr) {
+ return _.invoke(this.models, 'get', attr);
+ },
+
+ // Fetch the default set of models for this collection, resetting the
+ // collection when they arrive. If `reset: true` is passed, the response
+ // data will be passed through the `reset` method instead of `set`.
+ fetch: function(options) {
+ options = options ? _.clone(options) : {};
+ if (options.parse === void 0) options.parse = true;
+ var success = options.success;
+ var collection = this;
+ options.success = function(resp) {
+ var method = options.reset ? 'reset' : 'set';
+ collection[method](resp, options);
+ if (success) success(collection, resp, options);
+ collection.trigger('sync', collection, resp, options);
+ };
+ wrapError(this, options);
+ return this.sync('read', this, options);
+ },
+
+ // Create a new instance of a model in this collection. Add the model to the
+ // collection immediately, unless `wait: true` is passed, in which case we
+ // wait for the server to agree.
+ create: function(model, options) {
+ options = options ? _.clone(options) : {};
+ if (!(model = this._prepareModel(model, options))) return false;
+ if (!options.wait) this.add(model, options);
+ var collection = this;
+ var success = options.success;
+ options.success = function(resp) {
+ if (options.wait) collection.add(model, options);
+ if (success) success(model, resp, options);
+ };
+ model.save(null, options);
+ return model;
+ },
+
+ // **parse** converts a response into a list of models to be added to the
+ // collection. The default implementation is just to pass it through.
+ parse: function(resp, options) {
+ return resp;
+ },
+
+ // Create a new collection with an identical list of models as this one.
+ clone: function() {
+ return new this.constructor(this.models);
+ },
+
+ // Private method to reset all internal state. Called when the collection
+ // is first initialized or reset.
+ _reset: function() {
+ this.length = 0;
+ this.models = [];
+ this._byId = {};
+ },
+
+ // Prepare a hash of attributes (or other model) to be added to this
+ // collection.
+ _prepareModel: function(attrs, options) {
+ if (attrs instanceof Model) {
+ if (!attrs.collection) attrs.collection = this;
+ return attrs;
+ }
+ options || (options = {});
+ options.collection = this;
+ var model = new this.model(attrs, options);
+ if (!model._validate(attrs, options)) {
+ this.trigger('invalid', this, attrs, options);
+ return false;
+ }
+ return model;
+ },
+
+ // Internal method to sever a model's ties to a collection.
+ _removeReference: function(model) {
+ if (this === model.collection) delete model.collection;
+ model.off('all', this._onModelEvent, this);
+ },
+
+ // Internal method called every time a model in the set fires an event.
+ // Sets need to update their indexes when models change ids. All other
+ // events simply proxy through. "add" and "remove" events that originate
+ // in other collections are ignored.
+ _onModelEvent: function(event, model, collection, options) {
+ if ((event === 'add' || event === 'remove') && collection !== this) return;
+ if (event === 'destroy') this.remove(model, options);
+ if (model && event === 'change:' + model.idAttribute) {
+ delete this._byId[model.previous(model.idAttribute)];
+ if (model.id != null) this._byId[model.id] = model;
+ }
+ this.trigger.apply(this, arguments);
+ }
+
+ });
+
+ // Underscore methods that we want to implement on the Collection.
+ // 90% of the core usefulness of Backbone Collections is actually implemented
+ // right here:
+ var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
+ 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
+ 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
+ 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
+ 'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
+ 'isEmpty', 'chain'];
+
+ // Mix in each Underscore method as a proxy to `Collection#models`.
+ _.each(methods, function(method) {
+ Collection.prototype[method] = function() {
+ var args = slice.call(arguments);
+ args.unshift(this.models);
+ return _[method].apply(_, args);
+ };
+ });
+
+ // Underscore methods that take a property name as an argument.
+ var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
+
+ // Use attributes instead of properties.
+ _.each(attributeMethods, function(method) {
+ Collection.prototype[method] = function(value, context) {
+ var iterator = _.isFunction(value) ? value : function(model) {
+ return model.get(value);
+ };
+ return _[method](this.models, iterator, context);
+ };
+ });
+
+ // Backbone.View
+ // -------------
+
+ // Backbone Views are almost more convention than they are actual code. A View
+ // is simply a JavaScript object that represents a logical chunk of UI in the
+ // DOM. This might be a single item, an entire list, a sidebar or panel, or
+ // even the surrounding frame which wraps your whole app. Defining a chunk of
+ // UI as a **View** allows you to define your DOM events declaratively, without
+ // having to worry about render order ... and makes it easy for the view to
+ // react to specific changes in the state of your models.
+
+ // Creating a Backbone.View creates its initial element outside of the DOM,
+ // if an existing element is not provided...
+ var View = Backbone.View = function(options) {
+ this.cid = _.uniqueId('view');
+ this._configure(options || {});
+ this._ensureElement();
+ this.initialize.apply(this, arguments);
+ this.delegateEvents();
+ };
+
+ // Cached regex to split keys for `delegate`.
+ var delegateEventSplitter = /^(\S+)\s*(.*)$/;
+
+ // List of view options to be merged as properties.
+ var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
+
+ // Set up all inheritable **Backbone.View** properties and methods.
+ _.extend(View.prototype, Events, {
+
+ // The default `tagName` of a View's element is `"div"`.
+ tagName: 'div',
+
+ // jQuery delegate for element lookup, scoped to DOM elements within the
+ // current view. This should be prefered to global lookups where possible.
+ $: function(selector) {
+ return this.$el.find(selector);
+ },
+
+ // Initialize is an empty function by default. Override it with your own
+ // initialization logic.
+ initialize: function(){},
+
+ // **render** is the core function that your view should override, in order
+ // to populate its element (`this.el`), with the appropriate HTML. The
+ // convention is for **render** to always return `this`.
+ render: function() {
+ return this;
+ },
+
+ // Remove this view by taking the element out of the DOM, and removing any
+ // applicable Backbone.Events listeners.
+ remove: function() {
+ this.$el.remove();
+ this.stopListening();
+ return this;
+ },
+
+ // Change the view's element (`this.el` property), including event
+ // re-delegation.
+ setElement: function(element, delegate) {
+ if (this.$el) this.undelegateEvents();
+ this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
+ this.el = this.$el[0];
+ if (delegate !== false) this.delegateEvents();
+ return this;
+ },
+
+ // Set callbacks, where `this.events` is a hash of
+ //
+ // *{"event selector": "callback"}*
+ //
+ // {
+ // 'mousedown .title': 'edit',
+ // 'click .button': 'save'
+ // 'click .open': function(e) { ... }
+ // }
+ //
+ // pairs. Callbacks will be bound to the view, with `this` set properly.
+ // Uses event delegation for efficiency.
+ // Omitting the selector binds the event to `this.el`.
+ // This only works for delegate-able events: not `focus`, `blur`, and
+ // not `change`, `submit`, and `reset` in Internet Explorer.
+ delegateEvents: function(events) {
+ if (!(events || (events = _.result(this, 'events')))) return this;
+ this.undelegateEvents();
+ for (var key in events) {
+ var method = events[key];
+ if (!_.isFunction(method)) method = this[events[key]];
+ if (!method) continue;
+
+ var match = key.match(delegateEventSplitter);
+ var eventName = match[1], selector = match[2];
+ method = _.bind(method, this);
+ eventName += '.delegateEvents' + this.cid;
+ if (selector === '') {
+ this.$el.on(eventName, method);
+ } else {
+ this.$el.on(eventName, selector, method);
+ }
+ }
+ return this;
+ },
+
+ // Clears all callbacks previously bound to the view with `delegateEvents`.
+ // You usually don't need to use this, but may wish to if you have multiple
+ // Backbone views attached to the same DOM element.
+ undelegateEvents: function() {
+ this.$el.off('.delegateEvents' + this.cid);
+ return this;
+ },
+
+ // Performs the initial configuration of a View with a set of options.
+ // Keys with special meaning *(e.g. model, collection, id, className)* are
+ // attached directly to the view. See `viewOptions` for an exhaustive
+ // list.
+ _configure: function(options) {
+ if (this.options) options = _.extend({}, _.result(this, 'options'), options);
+ _.extend(this, _.pick(options, viewOptions));
+ this.options = options;
+ },
+
+ // Ensure that the View has a DOM element to render into.
+ // If `this.el` is a string, pass it through `$()`, take the first
+ // matching element, and re-assign it to `el`. Otherwise, create
+ // an element from the `id`, `className` and `tagName` properties.
+ _ensureElement: function() {
+ if (!this.el) {
+ var attrs = _.extend({}, _.result(this, 'attributes'));
+ if (this.id) attrs.id = _.result(this, 'id');
+ if (this.className) attrs['class'] = _.result(this, 'className');
+ var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
+ this.setElement($el, false);
+ } else {
+ this.setElement(_.result(this, 'el'), false);
+ }
+ }
+
+ });
+
+ // Backbone.sync
+ // -------------
+
+ // Override this function to change the manner in which Backbone persists
+ // models to the server. You will be passed the type of request, and the
+ // model in question. By default, makes a RESTful Ajax request
+ // to the model's `url()`. Some possible customizations could be:
+ //
+ // * Use `setTimeout` to batch rapid-fire updates into a single request.
+ // * Send up the models as XML instead of JSON.
+ // * Persist models via WebSockets instead of Ajax.
+ //
+ // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
+ // as `POST`, with a `_method` parameter containing the true HTTP method,
+ // as well as all requests with the body as `application/x-www-form-urlencoded`
+ // instead of `application/json` with the model in a param named `model`.
+ // Useful when interfacing with server-side languages like **PHP** that make
+ // it difficult to read the body of `PUT` requests.
+ Backbone.sync = function(method, model, options) {
+ var type = methodMap[method];
+
+ // Default options, unless specified.
+ _.defaults(options || (options = {}), {
+ emulateHTTP: Backbone.emulateHTTP,
+ emulateJSON: Backbone.emulateJSON
+ });
+
+ // Default JSON-request options.
+ var params = {type: type, dataType: 'json'};
+
+ // Ensure that we have a URL.
+ if (!options.url) {
+ params.url = _.result(model, 'url') || urlError();
+ }
+
+ // Ensure that we have the appropriate request data.
+ if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
+ params.contentType = 'application/json';
+ params.data = JSON.stringify(options.attrs || model.toJSON(options));
+ }
+
+ // For older servers, emulate JSON by encoding the request into an HTML-form.
+ if (options.emulateJSON) {
+ params.contentType = 'application/x-www-form-urlencoded';
+ params.data = params.data ? {model: params.data} : {};
+ }
+
+ // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
+ // And an `X-HTTP-Method-Override` header.
+ if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
+ params.type = 'POST';
+ if (options.emulateJSON) params.data._method = type;
+ var beforeSend = options.beforeSend;
+ options.beforeSend = function(xhr) {
+ xhr.setRequestHeader('X-HTTP-Method-Override', type);
+ if (beforeSend) return beforeSend.apply(this, arguments);
+ };
+ }
+
+ // Don't process data on a non-GET request.
+ if (params.type !== 'GET' && !options.emulateJSON) {
+ params.processData = false;
+ }
+
+ // If we're sending a `PATCH` request, and we're in an old Internet Explorer
+ // that still has ActiveX enabled by default, override jQuery to use that
+ // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
+ if (params.type === 'PATCH' && window.ActiveXObject &&
+ !(window.external && window.external.msActiveXFilteringEnabled)) {
+ params.xhr = function() {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ };
+ }
+
+ // Make the request, allowing the user to override any Ajax options.
+ var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
+ model.trigger('request', model, xhr, options);
+ return xhr;
+ };
+
+ // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
+ var methodMap = {
+ 'create': 'POST',
+ 'update': 'PUT',
+ 'patch': 'PATCH',
+ 'delete': 'DELETE',
+ 'read': 'GET'
+ };
+
+ // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
+ // Override this if you'd like to use a different library.
+ Backbone.ajax = function() {
+ return Backbone.$.ajax.apply(Backbone.$, arguments);
+ };
+
+ // Backbone.Router
+ // ---------------
+
+ // Routers map faux-URLs to actions, and fire events when routes are
+ // matched. Creating a new one sets its `routes` hash, if not set statically.
+ var Router = Backbone.Router = function(options) {
+ options || (options = {});
+ if (options.routes) this.routes = options.routes;
+ this._bindRoutes();
+ this.initialize.apply(this, arguments);
+ };
+
+ // Cached regular expressions for matching named param parts and splatted
+ // parts of route strings.
+ var optionalParam = /\((.*?)\)/g;
+ var namedParam = /(\(\?)?:\w+/g;
+ var splatParam = /\*\w+/g;
+ var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
+
+ // Set up all inheritable **Backbone.Router** properties and methods.
+ _.extend(Router.prototype, Events, {
+
+ // Initialize is an empty function by default. Override it with your own
+ // initialization logic.
+ initialize: function(){},
+
+ // Manually bind a single named route to a callback. For example:
+ //
+ // this.route('search/:query/p:num', 'search', function(query, num) {
+ // ...
+ // });
+ //
+ route: function(route, name, callback) {
+ if (!_.isRegExp(route)) route = this._routeToRegExp(route);
+ if (_.isFunction(name)) {
+ callback = name;
+ name = '';
+ }
+ if (!callback) callback = this[name];
+ var router = this;
+ Backbone.history.route(route, function(fragment) {
+ var args = router._extractParameters(route, fragment);
+ callback && callback.apply(router, args);
+ router.trigger.apply(router, ['route:' + name].concat(args));
+ router.trigger('route', name, args);
+ Backbone.history.trigger('route', router, name, args);
+ });
+ return this;
+ },
+
+ // Simple proxy to `Backbone.history` to save a fragment into the history.
+ navigate: function(fragment, options) {
+ Backbone.history.navigate(fragment, options);
+ return this;
+ },
+
+ // Bind all defined routes to `Backbone.history`. We have to reverse the
+ // order of the routes here to support behavior where the most general
+ // routes can be defined at the bottom of the route map.
+ _bindRoutes: function() {
+ if (!this.routes) return;
+ this.routes = _.result(this, 'routes');
+ var route, routes = _.keys(this.routes);
+ while ((route = routes.pop()) != null) {
+ this.route(route, this.routes[route]);
+ }
+ },
+
+ // Convert a route string into a regular expression, suitable for matching
+ // against the current location hash.
+ _routeToRegExp: function(route) {
+ route = route.replace(escapeRegExp, '\\$&')
+ .replace(optionalParam, '(?:$1)?')
+ .replace(namedParam, function(match, optional){
+ return optional ? match : '([^\/]+)';
+ })
+ .replace(splatParam, '(.*?)');
+ return new RegExp('^' + route + '$');
+ },
+
+ // Given a route, and a URL fragment that it matches, return the array of
+ // extracted decoded parameters. Empty or unmatched parameters will be
+ // treated as `null` to normalize cross-browser behavior.
+ _extractParameters: function(route, fragment) {
+ var params = route.exec(fragment).slice(1);
+ return _.map(params, function(param) {
+ return param ? decodeURIComponent(param) : null;
+ });
+ }
+
+ });
+
+ // Backbone.History
+ // ----------------
+
+ // Handles cross-browser history management, based on either
+ // [pushState](http://diveintohtml5.info/history.html) and real URLs, or
+ // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
+ // and URL fragments. If the browser supports neither (old IE, natch),
+ // falls back to polling.
+ var History = Backbone.History = function() {
+ this.handlers = [];
+ _.bindAll(this, 'checkUrl');
+
+ // Ensure that `History` can be used outside of the browser.
+ if (typeof window !== 'undefined') {
+ this.location = window.location;
+ this.history = window.history;
+ }
+ };
+
+ // Cached regex for stripping a leading hash/slash and trailing space.
+ var routeStripper = /^[#\/]|\s+$/g;
+
+ // Cached regex for stripping leading and trailing slashes.
+ var rootStripper = /^\/+|\/+$/g;
+
+ // Cached regex for detecting MSIE.
+ var isExplorer = /msie [\w.]+/;
+
+ // Cached regex for removing a trailing slash.
+ var trailingSlash = /\/$/;
+
+ // Has the history handling already been started?
+ History.started = false;
+
+ // Set up all inheritable **Backbone.History** properties and methods.
+ _.extend(History.prototype, Events, {
+
+ // The default interval to poll for hash changes, if necessary, is
+ // twenty times a second.
+ interval: 50,
+
+ // Gets the true hash value. Cannot use location.hash directly due to bug
+ // in Firefox where location.hash will always be decoded.
+ getHash: function(window) {
+ var match = (window || this).location.href.match(/#(.*)$/);
+ return match ? match[1] : '';
+ },
+
+ // Get the cross-browser normalized URL fragment, either from the URL,
+ // the hash, or the override.
+ getFragment: function(fragment, forcePushState) {
+ if (fragment == null) {
+ if (this._hasPushState || !this._wantsHashChange || forcePushState) {
+ fragment = this.location.pathname;
+ var root = this.root.replace(trailingSlash, '');
+ if (!fragment.indexOf(root)) fragment = fragment.substr(root.length);
+ } else {
+ fragment = this.getHash();
+ }
+ }
+ return fragment.replace(routeStripper, '');
+ },
+
+ // Start the hash change handling, returning `true` if the current URL matches
+ // an existing route, and `false` otherwise.
+ start: function(options) {
+ if (History.started) throw new Error("Backbone.history has already been started");
+ History.started = true;
+
+ // Figure out the initial configuration. Do we need an iframe?
+ // Is pushState desired ... is it available?
+ this.options = _.extend({}, {root: '/'}, this.options, options);
+ this.root = this.options.root;
+ this._wantsHashChange = this.options.hashChange !== false;
+ this._wantsPushState = !!this.options.pushState;
+ this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState);
+ var fragment = this.getFragment();
+ var docMode = document.documentMode;
+ var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
+
+ // Normalize root to always include a leading and trailing slash.
+ this.root = ('/' + this.root + '/').replace(rootStripper, '/');
+
+ if (oldIE && this._wantsHashChange) {
+ this.iframe = Backbone.$('').hide().appendTo('body')[0].contentWindow;
+ this.navigate(fragment);
+ }
+
+ // Depending on whether we're using pushState or hashes, and whether
+ // 'onhashchange' is supported, determine how we check the URL state.
+ if (this._hasPushState) {
+ Backbone.$(window).on('popstate', this.checkUrl);
+ } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
+ Backbone.$(window).on('hashchange', this.checkUrl);
+ } else if (this._wantsHashChange) {
+ this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
+ }
+
+ // Determine if we need to change the base url, for a pushState link
+ // opened by a non-pushState browser.
+ this.fragment = fragment;
+ var loc = this.location;
+ var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
+
+ // If we've started off with a route from a `pushState`-enabled browser,
+ // but we're currently in a browser that doesn't support it...
+ if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
+ this.fragment = this.getFragment(null, true);
+ this.location.replace(this.root + this.location.search + '#' + this.fragment);
+ // Return immediately as browser will do redirect to new url
+ return true;
+
+ // Or if we've started out with a hash-based route, but we're currently
+ // in a browser where it could be `pushState`-based instead...
+ } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
+ this.fragment = this.getHash().replace(routeStripper, '');
+ this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
+ }
+
+ if (!this.options.silent) return this.loadUrl();
+ },
+
+ // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
+ // but possibly useful for unit testing Routers.
+ stop: function() {
+ Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
+ clearInterval(this._checkUrlInterval);
+ History.started = false;
+ },
+
+ // Add a route to be tested when the fragment changes. Routes added later
+ // may override previous routes.
+ route: function(route, callback) {
+ this.handlers.unshift({route: route, callback: callback});
+ },
+
+ // Checks the current URL to see if it has changed, and if it has,
+ // calls `loadUrl`, normalizing across the hidden iframe.
+ checkUrl: function(e) {
+ var current = this.getFragment();
+ if (current === this.fragment && this.iframe) {
+ current = this.getFragment(this.getHash(this.iframe));
+ }
+ if (current === this.fragment) return false;
+ if (this.iframe) this.navigate(current);
+ this.loadUrl() || this.loadUrl(this.getHash());
+ },
+
+ // Attempt to load the current URL fragment. If a route succeeds with a
+ // match, returns `true`. If no defined routes matches the fragment,
+ // returns `false`.
+ loadUrl: function(fragmentOverride) {
+ var fragment = this.fragment = this.getFragment(fragmentOverride);
+ var matched = _.any(this.handlers, function(handler) {
+ if (handler.route.test(fragment)) {
+ handler.callback(fragment);
+ return true;
+ }
+ });
+ return matched;
+ },
+
+ // Save a fragment into the hash history, or replace the URL state if the
+ // 'replace' option is passed. You are responsible for properly URL-encoding
+ // the fragment in advance.
+ //
+ // The options object can contain `trigger: true` if you wish to have the
+ // route callback be fired (not usually desirable), or `replace: true`, if
+ // you wish to modify the current URL without adding an entry to the history.
+ navigate: function(fragment, options) {
+ if (!History.started) return false;
+ if (!options || options === true) options = {trigger: options};
+ fragment = this.getFragment(fragment || '');
+ if (this.fragment === fragment) return;
+ this.fragment = fragment;
+ var url = this.root + fragment;
+
+ // If pushState is available, we use it to set the fragment as a real URL.
+ if (this._hasPushState) {
+ this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
+
+ // If hash changes haven't been explicitly disabled, update the hash
+ // fragment to store history.
+ } else if (this._wantsHashChange) {
+ this._updateHash(this.location, fragment, options.replace);
+ if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
+ // Opening and closing the iframe tricks IE7 and earlier to push a
+ // history entry on hash-tag change. When replace is true, we don't
+ // want this.
+ if(!options.replace) this.iframe.document.open().close();
+ this._updateHash(this.iframe.location, fragment, options.replace);
+ }
+
+ // If you've told us that you explicitly don't want fallback hashchange-
+ // based history, then `navigate` becomes a page refresh.
+ } else {
+ return this.location.assign(url);
+ }
+ if (options.trigger) this.loadUrl(fragment);
+ },
+
+ // Update the hash location, either replacing the current entry, or adding
+ // a new one to the browser history.
+ _updateHash: function(location, fragment, replace) {
+ if (replace) {
+ var href = location.href.replace(/(javascript:|#).*$/, '');
+ location.replace(href + '#' + fragment);
+ } else {
+ // Some browsers require that `hash` contains a leading #.
+ location.hash = '#' + fragment;
+ }
+ }
+
+ });
+
+ // Create the default Backbone.history.
+ Backbone.history = new History;
+
+ // Helpers
+ // -------
+
+ // Helper function to correctly set up the prototype chain, for subclasses.
+ // Similar to `goog.inherits`, but uses a hash of prototype properties and
+ // class properties to be extended.
+ var extend = function(protoProps, staticProps) {
+ var parent = this;
+ var child;
+
+ // The constructor function for the new subclass is either defined by you
+ // (the "constructor" property in your `extend` definition), or defaulted
+ // by us to simply call the parent's constructor.
+ if (protoProps && _.has(protoProps, 'constructor')) {
+ child = protoProps.constructor;
+ } else {
+ child = function(){ return parent.apply(this, arguments); };
+ }
+
+ // Add static properties to the constructor function, if supplied.
+ _.extend(child, parent, staticProps);
+
+ // Set the prototype chain to inherit from `parent`, without calling
+ // `parent`'s constructor function.
+ var Surrogate = function(){ this.constructor = child; };
+ Surrogate.prototype = parent.prototype;
+ child.prototype = new Surrogate;
+
+ // Add prototype properties (instance properties) to the subclass,
+ // if supplied.
+ if (protoProps) _.extend(child.prototype, protoProps);
+
+ // Set a convenience property in case the parent's prototype is needed
+ // later.
+ child.__super__ = parent.prototype;
+
+ return child;
+ };
+
+ // Set up inheritance for the model, collection, router, view and history.
+ Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
+
+ // Throw an error when a URL is needed, and none is supplied.
+ var urlError = function() {
+ throw new Error('A "url" property or function must be specified');
+ };
+
+ // Wrap an optional error callback with a fallback error event.
+ var wrapError = function (model, options) {
+ var error = options.error;
+ options.error = function(resp) {
+ if (error) error(model, resp, options);
+ model.trigger('error', model, resp, options);
+ };
+ };
+
+}).call(this);
diff --git a/bower_components/backbone.babysitter/public/javascripts/jquery.js b/bower_components/backbone.babysitter/public/javascripts/jquery.js
new file mode 100644
index 0000000..e2c203f
--- /dev/null
+++ b/bower_components/backbone.babysitter/public/javascripts/jquery.js
@@ -0,0 +1,9597 @@
+/*!
+ * jQuery JavaScript Library v1.9.1
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-2-4
+ */
+(function( window, undefined ) {
+
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//"use strict";
+var
+ // The deferred used on DOM ready
+ readyList,
+
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // Support: IE<9
+ // For `typeof node.method` instead of `node.method !== undefined`
+ core_strundefined = typeof undefined,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ document = window.document,
+ location = window.location,
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$,
+
+ // [[Class]] -> type pairs
+ class2type = {},
+
+ // List of deleted data cache ids, so we can reuse them
+ core_deletedIds = [],
+
+ core_version = "1.9.1",
+
+ // Save a reference to some core methods
+ core_concat = core_deletedIds.concat,
+ core_push = core_deletedIds.push,
+ core_slice = core_deletedIds.slice,
+ core_indexOf = core_deletedIds.indexOf,
+ core_toString = class2type.toString,
+ core_hasOwn = class2type.hasOwnProperty,
+ core_trim = core_version.trim,
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context, rootjQuery );
+ },
+
+ // Used for matching numbers
+ core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
+
+ // Used for splitting on whitespace
+ core_rnotwhite = /\S+/g,
+
+ // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
+
+ // JSON RegExp
+ rvalidchars = /^[\],:{}\s]*$/,
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
+
+ // Matches dashed string for camelizing
+ rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ },
+
+ // The ready event handler
+ completed = function( event ) {
+
+ // readyState === "complete" is good enough for us to call the dom ready in oldIE
+ if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
+ detach();
+ jQuery.ready();
+ }
+ },
+ // Clean-up method for dom ready events
+ detach = function() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", completed, false );
+ window.removeEventListener( "load", completed, false );
+
+ } else {
+ document.detachEvent( "onreadystatechange", completed );
+ window.detachEvent( "onload", completed );
+ }
+ };
+
+jQuery.fn = jQuery.prototype = {
+ // The current version of jQuery being used
+ jquery: core_version,
+
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+
+ // scripts is true for back-compat
+ jQuery.merge( this, jQuery.parseHTML(
+ match[1],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ toArray: function() {
+ return core_slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+ ret.context = this.context;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+ },
+
+ slice: function() {
+ return this.pushStack( core_slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: core_push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var src, copyIsArray, copy, name, options, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger("ready").off("ready");
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return String( obj );
+ }
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ core_toString.call(obj) ] || "object" :
+ typeof obj;
+ },
+
+ isPlainObject: function( obj ) {
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !core_hasOwn.call(obj, "constructor") &&
+ !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || core_hasOwn.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ // data: string of html
+ // context (optional): If specified, the fragment will be created in this context, defaults to document
+ // keepScripts (optional): If true, will include scripts passed in the html string
+ parseHTML: function( data, context, keepScripts ) {
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+ context = context || document;
+
+ var parsed = rsingleTag.exec( data ),
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+ if ( scripts ) {
+ jQuery( scripts ).remove();
+ }
+ return jQuery.merge( [], parsed.childNodes );
+ },
+
+ parseJSON: function( data ) {
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ return window.JSON.parse( data );
+ }
+
+ if ( data === null ) {
+ return data;
+ }
+
+ if ( typeof data === "string" ) {
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ if ( data ) {
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+ .replace( rvalidtokens, "]" )
+ .replace( rvalidbraces, "")) ) {
+
+ return ( new Function( "return " + data ) )();
+ }
+ }
+ }
+
+ jQuery.error( "Invalid JSON: " + data );
+ },
+
+ // Cross-browser xml parsing
+ parseXML: function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data , "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+ },
+
+ noop: function() {},
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && jQuery.trim( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var value,
+ i = 0,
+ length = obj.length,
+ isArray = isArraylike( obj );
+
+ if ( args ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Use native String.trim function wherever possible
+ trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
+ function( text ) {
+ return text == null ?
+ "" :
+ core_trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArraylike( Object(arr) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ core_push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( core_indexOf ) {
+ return core_indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var l = second.length,
+ i = first.length,
+ j = 0;
+
+ if ( typeof l === "number" ) {
+ for ( ; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var retVal,
+ ret = [],
+ i = 0,
+ length = elems.length;
+ inv = !!inv;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value,
+ i = 0,
+ length = elems.length,
+ isArray = isArraylike( elems ),
+ ret = [];
+
+ // Go through the array, translating each of the items to their
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return core_concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var args, proxy, tmp;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = core_slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ // Multifunctional method to get and set values of a collection
+ // The value/s can optionally be executed if it's a function
+ access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ length = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < length; i++ ) {
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+ },
+
+ now: function() {
+ return ( new Date() ).getTime();
+ }
+});
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed, false );
+
+ // If IE event model is used
+ } else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", completed );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", completed );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch(e) {}
+
+ if ( top && top.doScroll ) {
+ (function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch(e) {
+ return setTimeout( doScrollCheck, 50 );
+ }
+
+ // detach all dom ready events
+ detach();
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ })();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+ var length = obj.length,
+ type = jQuery.type( obj );
+
+ if ( jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.nodeType === 1 && length ) {
+ return true;
+ }
+
+ return type === "array" || type !== "function" &&
+ ( length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj );
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( list && ( !fired || stack ) ) {
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var action = tuple[ 0 ],
+ fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+ }
+ });
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[0] ] = function() {
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = core_slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
+ if( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+ } else if ( !( --remaining ) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+jQuery.support = (function() {
+
+ var support, all, a,
+ input, select, fragment,
+ opt, eventName, isSupported, i,
+ div = document.createElement("div");
+
+ // Setup
+ div.setAttribute( "className", "t" );
+ div.innerHTML = "
a";
+
+ // Support tests won't run in some limited or non-browser environments
+ all = div.getElementsByTagName("*");
+ a = div.getElementsByTagName("a")[ 0 ];
+ if ( !all || !a || !all.length ) {
+ return {};
+ }
+
+ // First batch of tests
+ select = document.createElement("select");
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName("input")[ 0 ];
+
+ a.style.cssText = "top:1px;float:left;opacity:.5";
+ support = {
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ getSetAttribute: div.className !== "t",
+
+ // IE strips leading whitespace when .innerHTML is used
+ leadingWhitespace: div.firstChild.nodeType === 3,
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ tbody: !div.getElementsByTagName("tbody").length,
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ htmlSerialize: !!div.getElementsByTagName("link").length,
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ style: /top/.test( a.getAttribute("style") ),
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ hrefNormalized: a.getAttribute("href") === "/a",
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ opacity: /^0.5/.test( a.style.opacity ),
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ cssFloat: !!a.style.cssFloat,
+
+ // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+ checkOn: !!input.value,
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ optSelected: opt.selected,
+
+ // Tests for enctype support on a form (#6743)
+ enctype: !!document.createElement("form").enctype,
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>",
+
+ // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
+ boxModel: document.compatMode === "CSS1Compat",
+
+ // Will be defined later
+ deleteExpando: true,
+ noCloneEvent: true,
+ inlineBlockNeedsLayout: false,
+ shrinkWrapBlocks: false,
+ reliableMarginRight: true,
+ boxSizingReliable: true,
+ pixelPosition: false
+ };
+
+ // Make sure checked status is properly cloned
+ input.checked = true;
+ support.noCloneChecked = input.cloneNode( true ).checked;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Support: IE<9
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+
+ // Check if we can trust getAttribute("value")
+ input = document.createElement("input");
+ input.setAttribute( "value", "" );
+ support.input = input.getAttribute( "value" ) === "";
+
+ // Check if an input maintains its value after becoming a radio
+ input.value = "t";
+ input.setAttribute( "type", "radio" );
+ support.radioValue = input.value === "t";
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ input.setAttribute( "checked", "t" );
+ input.setAttribute( "name", "t" );
+
+ fragment = document.createDocumentFragment();
+ fragment.appendChild( input );
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ support.appendChecked = input.checked;
+
+ // WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<9
+ // Opera does not clone events (and typeof div.attachEvent === undefined).
+ // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
+ if ( div.attachEvent ) {
+ div.attachEvent( "onclick", function() {
+ support.noCloneEvent = false;
+ });
+
+ div.cloneNode( true ).click();
+ }
+
+ // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php
+ for ( i in { submit: true, change: true, focusin: true }) {
+ div.setAttribute( eventName = "on" + i, "t" );
+
+ support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
+ }
+
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, marginDiv, tds,
+ divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ container = document.createElement("div");
+ container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
+
+ body.appendChild( container ).appendChild( div );
+
+ // Support: IE8
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ div.innerHTML = "
t
";
+ tds = div.getElementsByTagName("td");
+ tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Support: IE8
+ // Check if empty table cells still have offsetWidth/Height
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+ // Check box-sizing and margin behavior
+ div.innerHTML = "";
+ div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
+ support.boxSizing = ( div.offsetWidth === 4 );
+ support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
+
+ // Use window.getComputedStyle because jsdom on node.js will break without it.
+ if ( window.getComputedStyle ) {
+ support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. (#3333)
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ marginDiv = div.appendChild( document.createElement("div") );
+ marginDiv.style.cssText = div.style.cssText = divReset;
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
+ div.style.width = "1px";
+
+ support.reliableMarginRight =
+ !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+ }
+
+ if ( typeof div.style.zoom !== core_strundefined ) {
+ // Support: IE<8
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ div.innerHTML = "";
+ div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+ // Support: IE6
+ // Check if elements with layout shrink-wrap their children
+ div.style.display = "block";
+ div.innerHTML = "";
+ div.firstChild.style.width = "5px";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+
+ if ( support.inlineBlockNeedsLayout ) {
+ // Prevent IE 6 from affecting layout for positioned elements #11048
+ // Prevent IE from shrinking the body in IE 7 mode #12869
+ // Support: IE<8
+ body.style.zoom = 1;
+ }
+ }
+
+ body.removeChild( container );
+
+ // Null elements to avoid leaks in IE
+ container = div = tds = marginDiv = null;
+ });
+
+ // Null elements to avoid leaks in IE
+ all = select = fragment = opt = a = input = null;
+
+ return support;
+})();
+
+var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ){
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, ret,
+ internalKey = jQuery.expando,
+ getByName = typeof name === "string",
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ cache[ id ] = {};
+
+ // Avoids exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ if ( !isNode ) {
+ cache[ id ].toJSON = jQuery.noop;
+ }
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( getByName ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+}
+
+function internalRemoveData( elem, name, pvt ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var i, l, thisCache,
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ } else {
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+ }
+
+ for ( i = 0, l = name.length; i < l; i++ ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
+ delete cache[ id ];
+
+ // When all else fails, null
+ } else {
+ cache[ id ] = null;
+ }
+}
+
+jQuery.extend({
+ cache: {},
+
+ // Unique for each copy of jQuery on the page
+ // Non-digits removed to match rinlinejQuery
+ expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
+
+ // The following elements throw uncatchable exceptions if you
+ // attempt to add expando properties to them.
+ noData: {
+ "embed": true,
+ // Ban all objects except for Flash (which handle expandos)
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+ "applet": true
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return internalData( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ return internalRemoveData( elem, name );
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return internalData( elem, name, data, true );
+ },
+
+ _removeData: function( elem, name ) {
+ return internalRemoveData( elem, name, true );
+ },
+
+ // A method for determining if a DOM node can handle the data expando
+ acceptData: function( elem ) {
+ // Do not set data on non-element because it will not be cleared (#8335).
+ if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
+ return false;
+ }
+
+ var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ // nodes accept data unless otherwise specified; rejection can be conditional
+ return !noData || noData !== true && elem.getAttribute("classid") === noData;
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var attrs, name,
+ elem = this[0],
+ i = 0,
+ data = null;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ attrs = elem.attributes;
+ for ( ; i < attrs.length; i++ ) {
+ name = attrs[i].name;
+
+ if ( !name.indexOf( "data-" ) ) {
+ name = jQuery.camelCase( name.slice(5) );
+
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ return jQuery.access( this, function( value ) {
+
+ if ( value === undefined ) {
+ // Try to fetch any internally stored data first
+ return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
+ }
+
+ this.each(function() {
+ jQuery.data( this, key, value );
+ });
+ }, null, value, arguments.length > 1, null, true );
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray(data) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ hooks.cur = fn;
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ jQuery._removeData( elem, type + "queue" );
+ jQuery._removeData( elem, key );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while( i-- ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+var nodeHook, boolHook,
+ rclass = /[\t\r\n]/g,
+ rreturn = /\r/g,
+ rfocusable = /^(?:input|select|textarea|button|object)$/i,
+ rclickable = /^(?:a|area)$/i,
+ rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,
+ ruseDefault = /^(?:checked|selected)$/i,
+ getSetAttribute = jQuery.support.getSetAttribute,
+ getSetInput = jQuery.support.input;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ },
+
+ prop: function( name, value ) {
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ },
+
+ addClass: function( value ) {
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
+ });
+ }
+
+ if ( proceed ) {
+ // The disjunction here is for better compressibility (see removeClass)
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ " "
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+ elem.className = jQuery.trim( cur );
+
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = arguments.length === 0 || typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
+ });
+ }
+ if ( proceed ) {
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ ""
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+ elem.className = value ? jQuery.trim( cur ) : "";
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isBool = typeof stateVal === "boolean";
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ state = stateVal,
+ classNames = value.match( core_rnotwhite ) || [];
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space separated list
+ state = isBool ? state : !self.hasClass( className );
+ self[ state ? "addClass" : "removeClass" ]( className );
+ }
+
+ // Toggle whole class name
+ } else if ( type === core_strundefined || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // If the element has a class name or if we're passed "false",
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ var ret, hooks, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val,
+ self = jQuery(this);
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, self.val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map(val, function ( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ // attributes.value is undefined in Blackberry 4.7 but
+ // uses .value. See #6932
+ var val = elem.attributes.value;
+ return !val || val.specified ? elem.value : elem.text;
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var values = jQuery.makeArray( value );
+
+ jQuery(elem).find("option").each(function() {
+ this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+ });
+
+ if ( !values.length ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ },
+
+ attr: function( elem, name, value ) {
+ var hooks, notxml, ret,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === core_strundefined ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( notxml ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+
+ } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+
+ // In IE9+, Flash objects don't have .getAttribute (#12945)
+ // Support: IE9+
+ if ( typeof elem.getAttribute !== core_strundefined ) {
+ ret = elem.getAttribute( name );
+ }
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( core_rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( (name = attrNames[i++]) ) {
+ propName = jQuery.propFix[ name ] || name;
+
+ // Boolean attributes get special treatment (#10870)
+ if ( rboolean.test( name ) ) {
+ // Set corresponding property to false for boolean attributes
+ // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8
+ if ( !getSetAttribute && ruseDefault.test( name ) ) {
+ elem[ jQuery.camelCase( "default-" + name ) ] =
+ elem[ propName ] = false;
+ } else {
+ elem[ propName ] = false;
+ }
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ } else {
+ jQuery.attr( elem, name, "" );
+ }
+
+ elem.removeAttribute( getSetAttribute ? name : propName );
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to default in case type is set after value during creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ },
+
+ propFix: {
+ tabindex: "tabIndex",
+ readonly: "readOnly",
+ "for": "htmlFor",
+ "class": "className",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ cellpadding: "cellPadding",
+ rowspan: "rowSpan",
+ colspan: "colSpan",
+ usemap: "useMap",
+ frameborder: "frameBorder",
+ contenteditable: "contentEditable"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ return ( elem[ name ] = value );
+ }
+
+ } else {
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ return elem[ name ];
+ }
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ var attributeNode = elem.getAttributeNode("tabindex");
+
+ return attributeNode && attributeNode.specified ?
+ parseInt( attributeNode.value, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ undefined;
+ }
+ }
+ }
+});
+
+// Hook for boolean attributes
+boolHook = {
+ get: function( elem, name ) {
+ var
+ // Use .prop to determine if this attribute is understood as boolean
+ prop = jQuery.prop( elem, name ),
+
+ // Fetch it accordingly
+ attr = typeof prop === "boolean" && elem.getAttribute( name ),
+ detail = typeof prop === "boolean" ?
+
+ getSetInput && getSetAttribute ?
+ attr != null :
+ // oldIE fabricates an empty string for missing boolean attributes
+ // and conflates checked/selected into attroperties
+ ruseDefault.test( name ) ?
+ elem[ jQuery.camelCase( "default-" + name ) ] :
+ !!attr :
+
+ // fetch an attribute node for properties not recognized as boolean
+ elem.getAttributeNode( name );
+
+ return detail && detail.value !== false ?
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ // IE<8 needs the *property* name
+ elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+ // Use defaultChecked and defaultSelected for oldIE
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+ }
+
+ return name;
+ }
+};
+
+// fix oldIE value attroperty
+if ( !getSetInput || !getSetAttribute ) {
+ jQuery.attrHooks.value = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ return jQuery.nodeName( elem, "input" ) ?
+
+ // Ignore the value *property* by using defaultValue
+ elem.defaultValue :
+
+ ret && ret.specified ? ret.value : undefined;
+ },
+ set: function( elem, value, name ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ // Does not return so that setAttribute is also used
+ elem.defaultValue = value;
+ } else {
+ // Use nodeHook if defined (#1954); otherwise setAttribute is fine
+ return nodeHook && nodeHook.set( elem, value, name );
+ }
+ }
+ };
+}
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ?
+ ret.value :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ elem.setAttributeNode(
+ (ret = elem.ownerDocument.createAttribute( name ))
+ );
+ }
+
+ ret.value = value += "";
+
+ // Break association with cloned elements by also using setAttribute (#9646)
+ return name === "value" || value === elem.getAttribute( name ) ?
+ value :
+ undefined;
+ }
+ };
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ get: nodeHook.get,
+ set: function( elem, value, name ) {
+ nodeHook.set( elem, value === "" ? false : value, name );
+ }
+ };
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ });
+ });
+}
+
+
+// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !jQuery.support.hrefNormalized ) {
+ jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ get: function( elem ) {
+ var ret = elem.getAttribute( name, 2 );
+ return ret == null ? undefined : ret;
+ }
+ });
+ });
+
+ // href/src property should get the full normalized URL (#10299/#12915)
+ jQuery.each([ "href", "src" ], function( i, name ) {
+ jQuery.propHooks[ name ] = {
+ get: function( elem ) {
+ return elem.getAttribute( name, 4 );
+ }
+ };
+ });
+}
+
+if ( !jQuery.support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Note: IE uppercases css property names, but if we were to .toLowerCase()
+ // .cssText, that would destroy case senstitivity in URL's, like in "background"
+ return elem.style.cssText || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = value + "" );
+ }
+ };
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+ jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ });
+}
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+ jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ get: function( elem ) {
+ // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ }
+ };
+ });
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ });
+});
+var rformElems = /^(?:input|select|textarea)$/i,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+ var tmp, events, t, handleObjIn,
+ special, eventHandle, handleObj,
+ handlers, type, namespaces, origType,
+ elemData = jQuery._data( elem );
+
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ if ( !elemData ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !(events = elemData.events) ) {
+ events = elemData.events = {};
+ }
+ if ( !(eventHandle = elemData.handle) ) {
+ eventHandle = elemData.handle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !(handlers = events[ type ]) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+ var j, handleObj, tmp,
+ origCount, t, events,
+ special, handlers, type,
+ namespaces, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery._removeData( elem, "events" );
+ }
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ var handle, ontype, cur,
+ bubbleType, special, tmp, i,
+ eventPath = [ elem || document ],
+ type = core_hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf(".") >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf(":") < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ event.isTrigger = true;
+ event.namespace = namespaces.join(".");
+ event.namespace_re = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === (elem.ownerDocument || document) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
+ event.preventDefault();
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
+ !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ try {
+ elem[ type ]();
+ } catch ( e ) {
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
+ }
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, ret, handleObj, matched, j,
+ handlerQueue = [],
+ args = core_slice.call( arguments ),
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( (event.result = ret) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var sel, handleObj, matches, i,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ // Black-hole SVG