Commit fed955b1 authored by Addy Osmani's avatar Addy Osmani

Merge pull request #19 from jacobmumm/master

New Example using AngularJS + PersistenceJS
parents 3049562d 1e6515ff
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
font-family: inherit;
vertical-align: baseline;
}
body {
line-height: 1;
color: black;
background: white;
}
ol, ul {
list-style: none;
}
a img {
border: none;
}
html {
background: #eeeeee;
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.4em;
background: #eeeeee;
color: #333333;
}
.clickable{
cursor:pointer;
}
#todoapp {
background: none repeat scroll 0 0 white;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2);
background: none repeat scroll 0 0 white;
margin: 0 auto 40px;
padding: 20px;
width: 480px;
}
#todoapp {
width: 480px;
margin: 0 auto 40px;
background: white;
padding: 20px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 5px 6px 0;
}
#todoapp h1 {
font-size: 36px;
font-weight: bold;
text-align: center;
padding: 20px 0 30px 0;
line-height: 1;
}
#create-todo {
position: relative;
}
#todo-form input {
width: 466px;
font-size: 24px;
font-family: inherit;
line-height: 1.4em;
border: 0;
outline: none;
padding: 6px;
border: 1px solid #999999;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
}
#create-todo input::-webkit-input-placeholder {
font-style: italic;
}
#create-todo span {
position: absolute;
z-index: 999;
width: 170px;
left: 50%;
margin-left: -85px;
}
#todo-list {
margin-top: 10px;
}
#todo-list li {
padding: 12px 20px 11px 0;
position: relative;
font-size: 24px;
line-height: 1.1em;
border-bottom: 1px solid #cccccc;
}
#todo-list li:after {
content: "\0020";
display: block;
height: 0;
clear: both;
overflow: hidden;
visibility: hidden;
}
#todo-list li.editing-true {
padding: 0;
border-bottom: 0;
}
#todo-list .editing-true .display,
#todo-list .edit {
display: none;
}
#todo-list .editing-true .edit {
display: block;
}
#todo-list .editing-true input {
width: 444px;
font-size: 24px;
font-family: inherit;
margin: 0;
line-height: 1.6em;
border: 0;
outline: none;
padding: 10px 7px 0px 27px;
border: 1px solid #999999;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 2px 0 inset;
}
#todo-list .check {
position: relative;
top: 9px;
margin: 0 10px 0 7px;
float: left;
}
#todo-list .done-true .todo-content {
text-decoration: line-through;
color: #777777;
}
#todo-list .todo-destroy {
position: absolute;
right: 5px;
top: 14px;
display: none;
cursor: pointer;
width: 20px;
height: 20px;
background: url(../img/destroy.png) no-repeat 0 0;
}
#todo-list li:hover .todo-destroy {
display: block;
}
#todo-list .todo-destroy:hover {
background-position: 0 -20px;
}
#todo-stats {
*zoom: 1;
margin-top: 10px;
color: #777777;
background: none repeat scroll 0 0 #F4FCE8;
border-radius: 0 0 5px 5px;
border-top: 1px solid #EDEDED;
color: #555555;
display: block;
line-height: 36px;
margin: 20px -20px -20px;
overflow: hidden;
padding: 0 20px;
}
#todo-stats:after {
content: "\0020";
display: block;
height: 0;
clear: both;
overflow: hidden;
visibility: hidden;
}
#todo-stats .todo-count {
float: left;
}
#todo-stats .todo-count .number {
font-weight: bold;
color: #333333;
}
#todo-stats .todo-clear {
float: right;
}
#todoapp #todo-stats {
background: none repeat scroll 0 0 #F4FCE8;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
border-top: 1px solid #EDEDED;
color: #555555;
line-height: 36px;
margin-top: 10px;
padding: 0 20px;
}
#todoapp #todo-stats .todo-clear a {
display: block;
line-height: 20px;
text-decoration: none;
-moz-border-radius: 12px;
-webkit-border-radius: 12px;
-o-border-radius: 12px;
-ms-border-radius: 12px;
-khtml-border-radius: 12px;
border-radius: 12px;
background: rgba(0, 0, 0, 0.1);
color: #555555;
font-size: 11px;
margin-top: 8px;
padding: 0 10px 1px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0 0;
}
/* line 136 */
#todoapp #todo-stats .todo-clear a:hover {
background: rgba(0, 0, 0, 0.15);
-moz-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
-o-box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
box-shadow: rgba(0, 0, 0, 0.3) 0 -1px 0 0;
}
#todo-stats .todo-clear a {
color: #777777;
font-size: 12px;
}
#todo-stats .todo-clear a:visited {
color: #777777;
}
#todo-stats .todo-clear a:hover {
color: #336699;
}
#instructions {
width: 520px;
margin: 10px auto;
color: #777777;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center;
}
#instructions a {
color: #336699;
}
#credits {
width: 520px;
margin: 30px auto;
color: #999;
text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
text-align: center;
}
#credits a {
color: #888;
}
/*
* Fran�ois 'cahnory' Germain
*/
.ui-tooltip, .ui-tooltip-top, .ui-tooltip-right, .ui-tooltip-bottom, .ui-tooltip-left {
color:#ffffff;
cursor:normal;
display:-moz-inline-stack;
display:inline-block;
font-size:12px;
font-family:arial;
padding:.5em 1em;
position:relative;
text-align:center;
text-shadow:0 -1px 1px #111111;
-webkit-border-top-left-radius:4px ;
-webkit-border-top-right-radius:4px ;
-webkit-border-bottom-right-radius:4px ;
-webkit-border-bottom-left-radius:4px ;
-khtml-border-top-left-radius:4px ;
-khtml-border-top-right-radius:4px ;
-khtml-border-bottom-right-radius:4px ;
-khtml-border-bottom-left-radius:4px ;
-moz-border-radius-topleft:4px ;
-moz-border-radius-topright:4px ;
-moz-border-radius-bottomright:4px ;
-moz-border-radius-bottomleft:4px ;
border-top-left-radius:4px ;
border-top-right-radius:4px ;
border-bottom-right-radius:4px ;
border-bottom-left-radius:4px ;
-o-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
-moz-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
-khtml-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
-webkit-box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
box-shadow:0 1px 2px #000000, inset 0 0 0 1px #222222, inset 0 2px #666666, inset 0 -2px 2px #444444;
background-color:#3b3b3b;
background-image:-moz-linear-gradient(top,#555555,#222222);
background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#555555),color-stop(1,#222222));
filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222);
-ms-filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#555555,EndColorStr=#222222);
}
.ui-tooltip:after, .ui-tooltip-top:after, .ui-tooltip-right:after, .ui-tooltip-bottom:after, .ui-tooltip-left:after {
content:"\25B8";
display:block;
font-size:2em;
height:0;
line-height:0;
position:absolute;
}
.ui-tooltip:after, .ui-tooltip-bottom:after {
color:#2a2a2a;
bottom:0;
left:1px;
text-align:center;
text-shadow:1px 0 2px #000000;
-o-transform:rotate(90deg);
-moz-transform:rotate(90deg);
-khtml-transform:rotate(90deg);
-webkit-transform:rotate(90deg);
width:100%;
}
.ui-tooltip-top:after {
bottom:auto;
color:#4f4f4f;
left:-2px;
top:0;
text-align:center;
text-shadow:none;
-o-transform:rotate(-90deg);
-moz-transform:rotate(-90deg);
-khtml-transform:rotate(-90deg);
-webkit-transform:rotate(-90deg);
width:100%;
}
.ui-tooltip-right:after {
color:#222222;
right:-0.375em;
top:50%;
margin-top:-.05em;
text-shadow:0 1px 2px #000000;
-o-transform:rotate(0);
-moz-transform:rotate(0);
-khtml-transform:rotate(0);
-webkit-transform:rotate(0);
}
.ui-tooltip-left:after {
color:#222222;
left:-0.375em;
top:50%;
margin-top:.1em;
text-shadow:0 -1px 2px #000000;
-o-transform:rotate(180deg);
-moz-transform:rotate(180deg);
-khtml-transform:rotate(180deg);
-webkit-transform:rotate(180deg);
}
\ No newline at end of file
<!doctype html>
<html xmlns:ng="http://angularjs.org/" xmlns:my="http://rx.org">
<head>
<meta charset="utf-8">
<title>AngularJS with PersistenceJS Storage Todo App</title>
<link rel="stylesheet" href="css/app.css"/>
</head>
<body>
<div ng:controller="App.Controllers.TodoController" id="todoapp">
<div class="title">
<h1>
Todos
</h1>
</div>
<div class="content">
<div id="todo-form">
</div>
<form id="todo-form" ng:submit="addTodo()">
<input id="new-todo" name="newTodo" my:blur="addTodo()" placeholder="What needs to be done?" type="text">
<span class="ui-tooltip-top" ng:show="showHitEnterHint">
Press Enter to save this task
</span>
</form>
<div id="todos">
<ul id="todo-list">
<li class="todo" ng:class="'editing-' + todo.editing + ' done-' + todo.done" ng:repeat="todo in todos">
<div class="display">
<input ng:change="changeStatus(todo)" class="check" type="checkbox" name="todo.done" / >
<div ng:click="editTodo(todo)" class="todo-content"> {{ todo.content }} </div>
<span class="todo-destroy" ng:click="removeTodo(todo)"></span>
</div>
<div class="edit">
<form ng:submit="finishEditing(todo)">
<input class="todo-input" my:focus="todo.editing" my:blur="finishEditing(todo)" name="todo.content" type="text">
</form>
</div>
</li>
</ul>
</div>
<div id="todo-stats">
<span class="todo-count" ng:show="hasTodos()">
<ng:pluralize count="remainingTodos()" when="{'0' : 'No items left.', '1': '1 item left.', 'other' : '{} items left.' }">
</ng:pluralize>
</span>
<span class="todo-clear" ng:show="hasFinishedTodos()">
<a ng:click="clearCompletedItems()">
Clear <ng:pluralize count="finishedTodos()" when="{'1': '1 completed item', 'other' : '{} completed items' }">
</ng:pluralize>
</a>
</span>
</div>
</div>
</div>
<ul id="instructions">
<li>Click to edit a todo.</li>
</ul>
<div id="credits">
<p>
Originally Created by
<br>
<a href="http://jgn.me/">Jérôme Gravel-Niquet</a>
</p>
<p>
Rewritten to use <a href="http://angularjs.org">AngularJS </a> by
<br>
<a href="http://cburgdorf.wordpress.com/">Christoph Burgdorf</a>
<br>Cleanup, edits: <a href="http://www.linkedin.com/pub/dan-doyon/2/1b0/a83">Dan Doyon</a>
</p>
<p>
Extended for persistent WebSQL storage by <br/>
<a href="http://jacobmumm.com">Jacob Mumm</a><br/>
Using <a href="http://persistencejs.org">PersistenceJS</a>
</p>
</div>
<script src="js/booter.js"></script>
<script src="lib/angular/angular.min.js" ng:autobind></script>
<script src="lib/rx/rx.js"></script>
<script src="lib/rx/rx.angular.js"></script>
<script src="lib/persistence/persistence.js"></script>
<script src="lib/persistence/persistence.store.sql.js"></script>
<script src="lib/persistence/persistence.store.websql.js"></script>
<script src="js/controllers.js"></script>
<script src="js/directive.js"></script>
<script src="js/services.js"></script>
</body>
</html>
var App = {};
App.Controllers = {};
/* App Controllers */
App.Controllers.TodoController = function (persistencejs) {
var self = this;
self.newTodo = "";
self.editTodoStartContent = "";
self.addTodo = function() {
if (self.newTodo.length === 0) return;
self.todos.push({
content: self.newTodo,
done: false,
editing: false
});
persistencejs.add(self.newTodo);
self.newTodo = "";
};
self.editTodo = function(todo) {
angular.forEach(self.todos, function(value) {
value.editing = false;
});
todo.editing = true;
self.editTodoStartContent = todo.content;
};
self.changeStatus = function(todo){
persistencejs.changeStatus(todo);
};
self.finishEditing = function(todo) {
todo.editing = false;
persistencejs.edit(self.editTodoStartContent, todo.content);
};
self.removeTodo = function(todo) {
angular.Array.remove(self.todos, todo);
persistencejs.remove(todo);
};
self.todos = [];
var countTodos = function(done) {
return function() {
return angular.Array.count(self.todos, function(x) {
return x.done === (done === "done");
});
}
};
self.remainingTodos = countTodos("undone");
self.finishedTodos = countTodos("done");
self.clearCompletedItems = function() {
var oldTodos = self.todos;
self.todos = [];
angular.forEach(oldTodos, function(todo) {
if (!todo.done) self.todos.push(todo);
});
};
self.hasFinishedTodos = function() {
return self.finishedTodos() > 0;
};
self.hasTodos = function() {
return self.todos.length > 0;
};
self.loadTodos = function(){
persistencejs.fetchAll(self);
}
self.refresh = function(){ self.$apply(); }
self.loadTodos();
/*
The following code deals with hiding the hint *while* you are typing,
showing it once you did *finish* typing (aka 500 ms since you hit the last key)
*in case* the result is a non empty string
*/
Rx.Observable.FromAngularScope(self, "newTodo")
.Do(function() {
self.showHitEnterHint = false;
})
.Throttle(500)
.Select(function(x) {
return x.length > 0;
})
.ToOutputProperty(self, "showHitEnterHint");
};
App.Controllers.TodoController.$inject = ['persistencejs'];
\ No newline at end of file
angular.directive('my:blur', function(expression, compiledElement) {
var compiler = this;
return function(linkElement) {
var scope = this;
linkElement.bind('blur', function(event) {
scope.$apply(expression, linkElement);
event.stopPropagation();
});
};
});
angular.directive("my:focus", function(expression, compiledElement){
return function(element){
this.$watch(expression, function(){
if(angular.formatter.boolean.parse(expression)){
element[0].focus();
}
}, element);
};
});
angular.service('persistencejs', function() {
persistence.store.websql.config(persistence, 'todo', 'todo database', 5*1024*1024);
var Todo = persistence.define('todo', {
content: 'TEXT',
done: 'BOOL'
});
persistence.schemaSync();
return {
add: function(item){
var t = new Todo();
t.content = item;
t.done = false;
persistence.add(t);
persistence.flush();
},
edit: function(startContent, endContent){
Todo.all().filter('content','=',startContent).one(function(item){
item.content = endContent;
persistence.flush();
});
},
changeStatus: function(item){
Todo.all().filter('content','=',item.content).one(function(todo){
todo.done = item.done;
persistence.flush();
});
},
remove: function(item){
Todo.all().filter('content','=',item.content).destroyAll();
},
fetchAll: function(controller){
Todo.all().list(function(items){
var itemCount = items.length;
var todos = [];
items.forEach(function(item){
todos.push({
content: item.content,
done: item.done,
editing: false
});
if(--itemCount == 0){
controller.todos = todos;
controller.refresh();
}
});
});
},
};
});
\ No newline at end of file
/*
Content-Type: multipart/related; boundary="_"
--_
Content-Location:img0
Content-Transfer-Encoding:base64
R0lGODlhCwAXAKIAAMzMzO/v7/f39////////wAAAAAAAAAAACH5BAUUAAQALAAAAAALABcAAAMrSLoc/AG8FeUUIN+sGebWAnbKSJodqqlsOxJtqYooU9vvk+vcJIcTkg+QAAA7
--_
Content-Location:img1
Content-Transfer-Encoding:base64
R0lGODlhCwAXAKIAAMzMzO/v7/f39////////wAAAAAAAAAAACH5BAUUAAQALAAAAAALABcAAAMrCLTcoM29yN6k9socs91e5X3EyJloipYrO4ohTMqA0Fn2XVNswJe+H+SXAAA7
--_
Content-Location:img2
Content-Transfer-Encoding:base64
R0lGODlhEAAQAPQAAP///wAAAPDw8IqKiuDg4EZGRnp6egAAAFhYWCQkJKysrL6+vhQUFJycnAQEBDY2NmhoaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAAFdyAgAgIJIeWoAkRCCMdBkKtIHIngyMKsErPBYbADpkSCwhDmQCBethRB6Vj4kFCkQPG4IlWDgrNRIwnO4UKBXDufzQvDMaoSDBgFb886MiQadgNABAokfCwzBA8LCg0Egl8jAggGAA1kBIA1BAYzlyILczULC2UhACH5BAkKAAAALAAAAAAQABAAAAV2ICACAmlAZTmOREEIyUEQjLKKxPHADhEvqxlgcGgkGI1DYSVAIAWMx+lwSKkICJ0QsHi9RgKBwnVTiRQQgwF4I4UFDQQEwi6/3YSGWRRmjhEETAJfIgMFCnAKM0KDV4EEEAQLiF18TAYNXDaSe3x6mjidN1s3IQAh+QQJCgAAACwAAAAAEAAQAAAFeCAgAgLZDGU5jgRECEUiCI+yioSDwDJyLKsXoHFQxBSHAoAAFBhqtMJg8DgQBgfrEsJAEAg4YhZIEiwgKtHiMBgtpg3wbUZXGO7kOb1MUKRFMysCChAoggJCIg0GC2aNe4gqQldfL4l/Ag1AXySJgn5LcoE3QXI3IQAh+QQJCgAAACwAAAAAEAAQAAAFdiAgAgLZNGU5joQhCEjxIssqEo8bC9BRjy9Ag7GILQ4QEoE0gBAEBcOpcBA0DoxSK/e8LRIHn+i1cK0IyKdg0VAoljYIg+GgnRrwVS/8IAkICyosBIQpBAMoKy9dImxPhS+GKkFrkX+TigtLlIyKXUF+NjagNiEAIfkECQoAAAAsAAAAABAAEAAABWwgIAICaRhlOY4EIgjH8R7LKhKHGwsMvb4AAy3WODBIBBKCsYA9TjuhDNDKEVSERezQEL0WrhXucRUQGuik7bFlngzqVW9LMl9XWvLdjFaJtDFqZ1cEZUB0dUgvL3dgP4WJZn4jkomWNpSTIyEAIfkECQoAAAAsAAAAABAAEAAABX4gIAICuSxlOY6CIgiD8RrEKgqGOwxwUrMlAoSwIzAGpJpgoSDAGifDY5kopBYDlEpAQBwevxfBtRIUGi8xwWkDNBCIwmC9Vq0aiQQDQuK+VgQPDXV9hCJjBwcFYU5pLwwHXQcMKSmNLQcIAExlbH8JBwttaX0ABAcNbWVbKyEAIfkECQoAAAAsAAAAABAAEAAABXkgIAICSRBlOY7CIghN8zbEKsKoIjdFzZaEgUBHKChMJtRwcWpAWoWnifm6ESAMhO8lQK0EEAV3rFopIBCEcGwDKAqPh4HUrY4ICHH1dSoTFgcHUiZjBhAJB2AHDykpKAwHAwdzf19KkASIPl9cDgcnDkdtNwiMJCshACH5BAkKAAAALAAAAAAQABAAAAV3ICACAkkQZTmOAiosiyAoxCq+KPxCNVsSMRgBsiClWrLTSWFoIQZHl6pleBh6suxKMIhlvzbAwkBWfFWrBQTxNLq2RG2yhSUkDs2b63AYDAoJXAcFRwADeAkJDX0AQCsEfAQMDAIPBz0rCgcxky0JRWE1AmwpKyEAIfkECQoAAAAsAAAAABAAEAAABXkgIAICKZzkqJ4nQZxLqZKv4NqNLKK2/Q4Ek4lFXChsg5ypJjs1II3gEDUSRInEGYAw6B6zM4JhrDAtEosVkLUtHA7RHaHAGJQEjsODcEg0FBAFVgkQJQ1pAwcDDw8KcFtSInwJAowCCA6RIwqZAgkPNgVpWndjdyohACH5BAkKAAAALAAAAAAQABAAAAV5ICACAimc5KieLEuUKvm2xAKLqDCfC2GaO9eL0LABWTiBYmA06W6kHgvCqEJiAIJiu3gcvgUsscHUERm+kaCxyxa+zRPk0SgJEgfIvbAdIAQLCAYlCj4DBw0IBQsMCjIqBAcPAooCBg9pKgsJLwUFOhCZKyQDA3YqIQAh+QQJCgAAACwAAAAAEAAQAAAFdSAgAgIpnOSonmxbqiThCrJKEHFbo8JxDDOZYFFb+A41E4H4OhkOipXwBElYITDAckFEOBgMQ3arkMkUBdxIUGZpEb7kaQBRlASPg0FQQHAbEEMGDSVEAA1QBhAED1E0NgwFAooCDWljaQIQCE5qMHcNhCkjIQAh+QQJCgAAACwAAAAAEAAQAAAFeSAgAgIpnOSoLgxxvqgKLEcCC65KEAByKK8cSpA4DAiHQ/DkKhGKh4ZCtCyZGo6F6iYYPAqFgYy02xkSaLEMV34tELyRYNEsCQyHlvWkGCzsPgMCEAY7Cg04Uk48LAsDhRA8MVQPEF0GAgqYYwSRlycNcWskCkApIyEAOwAAAAAAAAAAAA==
--_--
*/
(function(){
var jsUri = document.location.href.replace(/\/[^\/]+(#.*)?$/, '/') +
document.getElementById('ng-ie-compat').src,
css = '#ng-callout .ng-arrow-left{*background-image:url("mhtml:' + jsUri + '!img0")}#ng-callout .ng-arrow-right{*background-image:url("mhtml:' + jsUri + '!img1")}.ng-input-indicator-wait {*background-image:url("mhtml:' + jsUri + '!img2")}',
s = document.createElement('style');
s.setAttribute('type', 'text/css');
if (s.styleSheet) {
s.styleSheet.cssText = css;
} else {
s.appendChild(document.createTextNode(css));
}
document.getElementsByTagName('head')[0].appendChild(s);
})();
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
AngularJS v0.10.0
(c) 2010-2011 AngularJS http://angularjs.org
License: MIT
*/
'use strict';(function(x,F,A){function k(a,b,c){var d;if(a)if(q(a))for(d in a)d!="prototype"&&d!=mc&&d!=nc&&a.hasOwnProperty(d)&&b.call(c,a[d],d);else if(a.forEach&&a.forEach!==k)a.forEach(b,c);else if(I(a)&&oa(a.length))for(d=0;d<a.length;d++)b.call(c,a[d],d);else for(d in a)b.call(c,a[d],d);return a}function sb(a,b,c){var d=[],e;for(e in a)d.push(e);d.sort();for(e=0;e<d.length;e++)b.call(c,a[d[e]],d[e]);return d}function tb(a){a instanceof z&&(a.stack?a=a.message&&a.stack.indexOf(a.message)===-1?
"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function Oa(){for(var a=S.length,b;a;){a--;b=S[a].charCodeAt(0);if(b==57)return S[a]="A",S.join("");if(b==90)S[a]="0";else return S[a]=String.fromCharCode(b+1),S.join("")}S.unshift("0");return S.join("")}function s(a){k(arguments,function(b){b!==a&&k(b,function(b,d){a[d]=b})});return a}function Pa(a,b){return s(new (s(function(){},{prototype:a})),b)}function p(){}function da(a){return a}function Qa(a){return function(){return a}}
function T(a,b,c){var d;return a[b]||(d=a[b]=function(a,b,g){a=(c||da)(a);v(b)&&(d[a]=s(b,g||{}));return d[a]})}function y(a){return typeof a==pa}function v(a){return typeof a!=pa}function I(a){return a!=null&&typeof a==ub}function u(a){return typeof a==oc}function oa(a){return typeof a==pc}function qa(a){return a instanceof Date}function U(a){return a instanceof Array}function q(a){return typeof a=="function"}function ea(a){return u(a)?a.replace(/^\s*/,"").replace(/\s*$/,""):a}function Ra(a){return a&&
(a.nodeName||a.bind&&a.find)}function Z(a){var b={},a=a.split(","),c;for(c=0;c<a.length;c++)b[a[c]]=!0;return b}function Sa(a,b){this.html=a;this.get=H(b)=="unsafe"?Qa(a):function(){var b=[];vb(a,wb(b));return b.join("")}}function qc(a,b,c){var d=[];k(a,function(a,f,g){d.push(b.call(c,a,f,g))});return d}function xb(a,b){var c=0,d;if(U(a)||u(a))return a.length;else if(I(a))for(d in a)(!b||a.hasOwnProperty(d))&&c++;return c}function yb(a,b){for(var c=0;c<a.length;c++)if(b===a[c])return!0;return!1}function ya(a,
b){for(var c=0;c<a.length;c++)if(b===a[c])return c;return-1}function rc(a){if(a)switch(a.nodeName){case "OPTION":case "PRE":case "TITLE":return!0}return!1}function C(a,b){if(b)if(U(a)){for(;b.length;)b.pop();for(var c=0;c<a.length;c++)b.push(C(a[c]))}else for(c in k(b,function(a,c){delete b[c]}),a)b[c]=C(a[c]);else(b=a)&&(U(a)?b=C(a,[]):qa(a)?b=new Date(a.getTime()):I(a)&&(b=C(a,{})));return b}function $(a,b){if(a===b)return!0;if(a===null||b===null)return!1;var c=typeof a,d;if(c==typeof b&&c=="object")if(a instanceof
Array){if((c=a.length)==b.length){for(d=0;d<c;d++)if(!$(a[d],b[d]))return!1;return!0}}else{c={};for(d in a){if(d.charAt(0)!=="$"&&!q(a[d])&&!$(a[d],b[d]))return!1;c[d]=!0}for(d in b)if(!c[d]&&d.charAt(0)!=="$"&&!q(b[d]))return!1;return!0}return!1}function sc(a){return(a=a&&a[0]&&a[0].nodeName)&&a.charAt(0)!="#"&&!yb(["TR","COL","COLGROUP","TBODY","THEAD","TFOOT"],a)}function ka(a,b,c){for(var d;!sc(a);)if(d=a.parent(),d.length)a=a.parent();else return;if(a[0].$NG_ERROR!==c)(a[0].$NG_ERROR=c)?(a.addClass(b),
a.attr(b,c.message||c)):(a.removeClass(b),a.removeAttr(b))}function M(a,b){var c=arguments.length>2?la.call(arguments,2):[];return q(b)&&!(b instanceof RegExp)?c.length?function(){return arguments.length?b.apply(a,c.concat(la.call(arguments,0))):b.apply(a,c)}:function(){return arguments.length?b.apply(a,arguments):b.call(a)}:b}function ma(a){a&&a.length!==0?(a=H(""+a),a=!(a=="f"||a=="0"||a=="false"||a=="no"||a=="n"||a=="[]")):a=!1;return a}function zb(a){return(new Ab(Ta,Bb,B,O)).compile(a)}function Ua(a){var b=
{},c,d;k((a||"").split("&"),function(a){a&&(c=a.split("="),d=unescape(c[0]),b[d]=v(c[1])?unescape(c[1]):!0)});return b}function Cb(a){var b=[];k(a,function(a,d){b.push(escape(d)+(a===!0?"":"="+escape(a)))});return b.length?b.join("&"):""}function Va(a,b){return encodeURIComponent(a).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(b?null:/%20/g,"+")}function tc(a,b){Db();for(var c=a.getElementsByTagName("script"),d,b=s({ie_compat_id:"ng-ie-compat"},b),e=0;e<
c.length;e++)if(d=(c[e].src||"").match(uc))b.base_url=d[1],b.ie_compat=d[1]+"angular-ie-compat"+(d[2]||"")+".js",s(b,Ua(d[6])),za(n(c[e]),function(a,c){/^ng:/.exec(c)&&(c=c.substring(3).replace(/-/g,"_"),b[c]=a||!0)});return b}function Db(){(Wa=x.jQuery)?(n=Wa,s(Wa.fn,{scope:Eb.scope})):n=Xa;w.element=n}function ra(a,b){if(!q(a))throw new z("Argument '"+(b||"?")+"' is "+("not a function, got "+(typeof a=="object"?a.constructor.name:typeof a)||"required"));}function Q(a,b){var c=[];Ya(c,a,b?"\n ":
null,[]);return c.join("")}function fa(a,b){function c(a){if(u(a)&&a.length===Fb)return ga.toDate(a);else(U(a)||I(a))&&k(a,function(b,d){a[d]=c(b)});return a}if(!u(a))return a;var d;try{return b&&x.JSON&&x.JSON.parse?(d=JSON.parse(a),c(d)):aa(a,!0).primary()()}catch(e){throw vc("fromJson error: ",a,e),e;}}function Ya(a,b,c,d){if(I(b)){if(b===x){a.push("WINDOW");return}if(b===F){a.push("DOCUMENT");return}if(yb(d,b)){a.push("RECURSION");return}d.push(b)}if(b===null)a.push(Aa);else if(b instanceof RegExp)a.push(ga.quoteUnicode(b.toString()));
else if(q(b))return;else if(typeof b==wc)a.push(""+b);else if(oa(b))isNaN(b)?a.push(Aa):a.push(""+b);else if(u(b))return a.push(ga.quoteUnicode(b));else if(I(b))if(U(b)){a.push("[");for(var e=b.length,f=!1,g=0;g<e;g++){var h=b[g];f&&a.push(",");!(h instanceof RegExp)&&(q(h)||y(h))?a.push(Aa):Ya(a,h,c,d);f=!0}a.push("]")}else if(Ra(b))a.push("DOM_ELEMENT");else if(qa(b))a.push(ga.quoteUnicode(w.Date.toString(b)));else{a.push("{");c&&a.push(c);e=!1;f=c?c+" ":!1;g=[];for(h in b)b.hasOwnProperty(h)&&
b[h]!==A&&g.push(h);g.sort();for(h=0;h<g.length;h++){var i=g[h],j=b[i];q(j)||(e&&(a.push(","),c&&a.push(c)),a.push(ga.quote(i)),a.push(":"),Ya(a,j,f,d),e=!0)}a.push("}")}I(b)&&d.pop()}function Za(){this.paths=[];this.children=[];this.linkFns=[];this.newScope=!1}function Ab(a,b,c,d){this.markup=a;this.attrMarkup=b;this.directives=c;this.widgets=d}function xc(a,b){var c,d=a[0].childNodes||[],e;for(c=0;c<d.length;c++){var f=e=d[c];sa(f)=="#text"||b(n(e),c)}}function za(a,b){var c,d=a[0].attributes||
[],e,f,g={};for(c=0;c<d.length;c++)e=d[c],f=e.name,e=e.value,V&&f=="href"&&(e=decodeURIComponent(a[0].getAttribute(f,2))),g[f]=e;sb(g,b)}function $a(a,b){var c=new Gb;(c.$service=Hb(c,a,b)).eager();return c}function Gb(){this.$id=Oa();this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this.$destructor=p;this["this"]=this.$root=this;this.$$asyncQueue=[];this.$$listeners={}}function Ib(a,b){var c=u(a)?W(a):a;ra(c,b);return c}function Hb(a,
b,c){function d(d){if(!(d in c)){var g=b[d];if(!g)throw z("Unknown provider for '"+d+"'.");c[d]=e(a,g)}return c[d]}function e(a,b,c){for(var c=c||[],e=yc(b),j=e.length;j--;)c.unshift(d(e[j]));return b.apply(a,c)}b=b||Ba;c=c||{};a=a||{};d.invoke=e;d.eager=function(){k(b,function(a,b){a.$eager&&d(b);if(a.$creation)throw new z("Failed to register service '"+b+"': $creation property is unsupported. Use $eager:true or see release notes.");})};return d}function ab(a,b){if(a instanceof Array)return b.$inject=
a,b;else{for(var c=0,d=arguments.length-1,e=arguments[d].$inject=[];c<d;c++)e.push(arguments[c]);return arguments[d]}}function G(a,b,c,d){Ba(a,b,{$inject:c,$eager:d})}function yc(a){ra(a);if(!a.$inject){var b=a.$inject=[],c=a.toString().replace(zc,"").match(Ac);k(c[1].split(Bc),function(a){a.replace(Cc,function(a,c){b.push(c)})})}return a.$inject}function Dc(a,b){function c(a){return a.indexOf(r)!=-1}function d(){return t+1<a.length?a.charAt(t+1):!1}function e(a){return"0"<=a&&a<="9"}function f(a){return"a"<=
a&&a<="z"||"A"<=a&&a<="Z"||"_"==a||a=="$"}function g(a){return a=="-"||a=="+"||e(a)}function h(b,c,d){d=d||t;throw z("Lexer Error: "+b+" at column"+(v(c)?"s "+c+"-"+t+" ["+a.substring(c,d)+"]":" "+d)+" in expression ["+a+"].");}function i(){for(var b="",c=t;t<a.length;){var f=H(a.charAt(t));if(f=="."||e(f))b+=f;else{var i=d();if(f=="e"&&g(i))b+=f;else if(g(f)&&i&&e(i)&&b.charAt(b.length-1)=="e")b+=f;else if(g(f)&&(!i||!e(i))&&b.charAt(b.length-1)=="e")h("Invalid exponent");else break}t++}b*=1;o.push({index:c,
text:b,json:!0,fn:function(){return b}})}function j(){for(var b="",c=t,d;t<a.length;){d=a.charAt(t);if(d=="."||f(d)||e(d))b+=d;else break;t++}d=bb[b];o.push({index:c,text:b,json:d,fn:d||s(Lb(b),{assign:function(a,c){return Mb(a,b,c)}})})}function l(b){var c=t;t++;for(var d="",e=b,g=!1;t<a.length;){var f=a.charAt(t);e+=f;if(g)f=="u"?(f=a.substring(t+1,t+5),f.match(/[\da-f]{4}/i)||h("Invalid unicode escape [\\u"+f+"]"),t+=4,d+=String.fromCharCode(parseInt(f,16))):(g=Ec[f],d+=g?g:f),g=!1;else if(f==
"\\")g=!0;else if(f==b){t++;o.push({index:c,text:e,string:d,json:!0,fn:function(){return d.length==m?w.String.toDate(d):d}});return}else d+=f;t++}h("Unterminated quote",c)}for(var m=b?Fb:-1,o=[],D,t=0,k=[],r,K=":";t<a.length;){r=a.charAt(t);if(c("\"'"))l(r);else if(e(r)||c(".")&&e(d()))i();else if(f(r)){if(j(),"{,".indexOf(K)!=-1&&k[0]=="{"&&(D=o[o.length-1]))D.json=D.text.indexOf(".")==-1}else if(c("(){}[].,;:"))o.push({index:t,text:r,json:":[,".indexOf(K)!=-1&&c("{[")||c("}]:,")}),c("{[")&&k.unshift(r),
c("}]")&&k.shift(),t++;else if(r==" "||r=="\r"||r=="\t"||r=="\n"||r=="\u000b"||r=="\u00a0"){t++;continue}else{var L=r+d(),n=bb[r],p=bb[L];p?(o.push({index:t,text:L,fn:p}),t+=2):n?(o.push({index:t,text:r,fn:n,json:"[,:".indexOf(K)!=-1&&c("+-")}),t+=1):h("Unexpected next character ",t,t+1)}K=r}return o}function aa(a,b){function c(a){return function(){var b=a();N.length!==0&&d("is an unexpected token",N[0]);return b}}function d(b,c){throw z("Syntax Error: Token '"+c.text+"' "+b+" at column "+(c.index+
1)+" of the expression ["+a+"] starting at ["+a.substring(c.index)+"].");}function e(){if(N.length===0)throw z("Unexpected end of expression: "+a);return N[0]}function f(a,b,c,d){if(N.length>0){var e=N[0],g=e.text;if(g==a||g==b||g==c||g==d||!a&&!b&&!c&&!d)return e}return!1}function g(a,c,e,g){return(a=f(a,c,e,g))?(b&&!a.json&&d("is not valid json",a),N.shift(),a):!1}function h(a){g(a)||d("is unexpected, expecting ["+a+"]",f())}function i(a,b){return function(c){return a(c,b(c))}}function j(a,b,c){return function(d){return b(d,
a(d),c(d))}}function l(){return w(X)}function m(){for(var a=o(),b;;)if(b=g("||"))a=j(a,b.fn,o());else return a}function o(){var a=D(),b;if(b=g("&&"))a=j(a,b.fn,o());return a}function D(){var a=t(),b;if(b=g("==","!="))a=j(a,b.fn,D());return a}function t(){var a;a=k();for(var b;b=g("+","-");)a=j(a,b.fn,k());if(b=g("<",">","<=",">="))a=j(a,b.fn,t());return a}function k(){for(var a=r(),b;b=g("*","/","%");)a=j(a,b.fn,r());return a}function r(){var a;return g("+")?n():(a=g("-"))?j(u,a.fn,r()):(a=g("!"))?
i(a.fn,r()):n()}function n(){var a;if(g("("))a=cb(),h(")");else if(g("["))a=L();else if(g("{"))a=ha();else{var b=g();(a=b.fn)||d("not a primary expression",b)}for(;b=g("(","[",".");)b.text==="("?a=Kb(a):b.text==="["?a=v(a):b.text==="."?a=Ca(a):d("IMPOSSIBLE");return a}function L(){var a=[];if(e().text!="]"){do a.push(ba());while(g(","))}h("]");return function(b){for(var c=[],d=0;d<a.length;d++)c.push(a[d](b));return c}}function ha(){var a=[];if(e().text!="}"){do{var b=g(),b=b.string||b.text;h(":");
var c=ba();a.push({key:b,value:c})}while(g(","))}h("}");return function(b){for(var c={},d=0;d<a.length;d++){var e=a[d],g=e.value(b);c[e.key]=g}return c}}var u=Qa(0),N=Dc(a,b),ba=function(){var b=m(),c,e;return(e=g("="))?(b.assign||d("implies assignment but ["+a.substring(0,e.index)+"] can not be assigned to",e),c=m(),function(a){return b.assign(a,c(a))}):b},Jb=m,Kb=function(a){var b=[];if(e().text!=")"){do b.push(ba());while(g(","))}h(")");return function(c){for(var d=[],e=0;e<b.length;e++)d.push(b[e](c));
e=a(c)||p;return e.apply?e.apply(c,d):e(d[0],d[1],d[2],d[3],d[4])}},Ca=function(a){var b=g().text,c=Lb(b);return s(function(b){return c(a(b))},{assign:function(c,d){return Mb(a(c),b,d)}})},v=function(a){var b=ba();h("]");return s(function(c){var d=a(c),c=b(c);return d?d[c]:A},{assign:function(c,d){return a(c)[b(c)]=d}})},cb=function(){for(var a=ba(),b;;)if(b=g("|"))a=j(a,b.fn,l());else return a},x=function(a){for(var b=g(),c=b.text.split("."),e,f=0;f<c.length;f++)e=c[f],a&&(a=a[e]);q(a)||d("should be a function",
b);return a},w=function(a){for(var b=x(a),c=[];;)if(g(":"))c.push(ba());else{var d=function(a,d){for(var e=[d],g=0;g<c.length;g++)e.push(c[g](a));return b.apply(a,e)};return function(){return d}}};b&&(ba=m,Kb=Ca=v=Jb=cb=x=w=function(){d("is not valid json",{text:a,index:0})});return{assignable:c(Jb),primary:c(n),statements:c(function(){for(var a=[];;)if(N.length>0&&!f("}",")",";","]")&&a.push(cb()),!g(";"))return a.length==1?a[0]:function(b){for(var c,d=0;d<a.length;d++){var e=a[d];e&&(c=e(b))}return c}}),
validator:c(function(){return w(db)}),formatter:c(function(){function a(b){return function(a,c){for(var d=[c],g=0;g<e.length;g++)d.push(e[g](a));return b.apply(a,d)}}var b=g(),c=ia[b.text],e=[];for(c||d("is not a valid formatter.",b);;)if(b=g(":"))e.push(ba());else return Qa({format:a(c.format),parse:a(c.parse)})}),filter:c(l)}}function Mb(a,b,c){for(var b=b.split("."),d=0;b.length>1;d++){var e=b.shift(),f=a[e];f||(f={},a[e]=f);a=f}return a[b.shift()]=c}function Da(a,b,c){if(!b)return a;for(var b=
b.split("."),d,e=a,f=b.length,g=0;g<f;g++)if(d=b[g],a&&(a=(e=a)[d]),y(a)&&d.charAt(0)=="$"){var h=ca.typeOf(e);if(d=(h=w[h.charAt(0).toUpperCase()+h.substring(1)])?h[[d.substring(1)]]:Fc)return M(e,d,e)}return!c&&q(a)?M(e,a):a}function Lb(a){var b=Nb[a];if(b)return b;var c="var l, fn, t;\n";k(a.split("."),function(a){a=Ob[a]?'["'+a+'"]':"."+a;c+="if(!s) return s;\nl=s;\ns=s"+a+';\nif(typeof s=="function" && !(s instanceof RegExp)) s = function(){ return l'+a+".apply(l, arguments); };\n";a.charAt(1)==
"$"&&(a=a.substr(2),c+='if(!s) {\n t = angular.Global.typeOf(l);\n fn = (angular[t.charAt(0).toUpperCase() + t.substring(1)]||{})["'+a+'"];\n if (fn) s = function(){ return fn.apply(l, [l].concat(Array.prototype.slice.call(arguments, 0))); };\n}\n')});c+="return s;";b=Function("s",c);b.toString=function(){return c};return Nb[a]=b}function W(a){if(q(a))return a;var b=Pb[a];b||(b=Pb[a]=aa(a).statements());return b}function Qb(a,b){this.template=a+="#";this.defaults=b||{};var c=this.urlParams={};k(a.split(/\W/),
function(b){b&&a.match(RegExp(":"+b+"\\W"))&&(c[b]=!0)})}function Ea(a){this.xhr=a}function Gc(a,b,c,d,e){function f(a){try{a.apply(null,la.call(arguments,1))}finally{if(ta--,ta===0)for(;r.length;)try{r.pop()()}catch(b){e.error(b)}}}function g(a,b){(function Ca(){k(K,function(a){a()});L=b(Ca,a)})()}var h=this,i=b[0],j=a.location,l=a.setTimeout,m=a.clearTimeout,o={},D;h.isMock=!1;var t=0,ta=0,r=[];h.xhr=function(b,e,g,i,j){ta++;if(H(b)=="json"){var m=("angular_"+Math.random()+"_"+t++).replace(/\d\./,
"");a[m]=function(b){a[m].data=b};var o=h.addJs(e.replace("JSON_CALLBACK",m),null,function(){a[m].data?f(i,200,a[m].data):f(i);delete a[m];c[0].removeChild(o)})}else{var l=new d;l.open(b,e,!0);k(j,function(a,b){a&&l.setRequestHeader(b,a)});l.onreadystatechange=function(){l.readyState==4&&f(i,l.status==1223?204:l.status||200,l.responseText)};l.send(g||"")}};h.notifyWhenNoOutstandingRequests=function(a){k(K,function(a){a()});ta===0?a():r.push(a)};var K=[],L;h.addPollFn=function(a){y(L)&&g(100,l);K.push(a);
return a};h.setUrl=function(a){var b=D;b.match(/#/)||(b+="#");a.match(/#/)||(a+="#");if(b!=a)j.href=a};h.getUrl=function(){return D=j.href};h.onHashChange=function(b){var c=a.document.documentMode;if("onhashchange"in a&&(y(c)||c>=8))n(a).bind("hashchange",b);else{var d=h.getUrl();h.addPollFn(function(){d!=h.getUrl()&&(b(),d=h.getUrl())})}return b};var ha={},s="";h.cookies=function(a,b){var c,d,g,f;if(a)if(b===A)i.cookie=escape(a)+"=;expires=Thu, 01 Jan 1970 00:00:00 GMT";else{if(u(b))i.cookie=escape(a)+
"="+escape(b),c=a.length+b.length+1,c>4096&&e.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+c+" > 4096 bytes)!"),ha.length>20&&e.warn("Cookie '"+a+"' possibly not set or overflowed because too many cookies were already set ("+ha.length+" > 20 )")}else{if(i.cookie!==s){s=i.cookie;c=s.split("; ");ha={};for(g=0;g<c.length;g++)d=c[g],f=d.indexOf("="),f>0&&(ha[unescape(d.substring(0,f))]=unescape(d.substring(f+1)))}return ha}};h.defer=function(a,b){var c;ta++;c=l(function(){delete o[c];
f(a)},b||0);o[c]=!0;return c};h.defer.cancel=function(a){if(o[a])return delete o[a],m(a),f(p),!0};var N=p;h.hover=function(a){N=a};h.bind=function(){b.bind("mouseover",function(a){N(n(V?a.srcElement:a.target),!0);return!0});b.bind("mouseleave mouseout click dblclick keypress keyup",function(a){N(n(a.target),!1);return!0})};h.addCss=function(a){var b=n(i.createElement("link"));b.attr("rel","stylesheet");b.attr("type","text/css");b.attr("href",a);c.append(b)};h.addJs=function(a,b,d){var e=i.createElement("script");
e.type="text/javascript";e.src=a;if(b)e.id=b;if(V)e.onreadystatechange=function(){/loaded|complete/.test(e.readyState)&&d&&d()};else if(d)e.onload=e.onerror=d;c[0].appendChild(e);return e}}function vb(a,b){function c(a,c,e,f){c=H(c);if(Rb[c])for(;g.last()&&Sb[g.last()];)d("",g.last());Tb[c]&&g.last()==c&&d("",c);(f=Ub[c]||!!f)||g.push(c);var h={};e.replace(Hc,function(a,b,c,d,e){h[b]=eb(c||d||e||"")});b.start&&b.start(c,h,f)}function d(a,c){var d=0,e;if(c=H(c))for(d=g.length-1;d>=0;d--)if(g[d]==c)break;
if(d>=0){for(e=g.length-1;e>=d;e--)b.end&&b.end(g[e]);g.length=d}}var e,f,g=[],h=a;for(g.last=function(){return g[g.length-1]};a;){f=!0;if(!g.last()||!Vb[g.last()]){if(a.indexOf("<\!--")===0)e=a.indexOf("--\>"),e>=0&&(b.comment&&b.comment(a.substring(4,e)),a=a.substring(e+3),f=!1);else if(Ic.test(a)){if(e=a.match(Wb))a=a.substring(e[0].length),e[0].replace(Wb,d),f=!1}else if(Jc.test(a)&&(e=a.match(Xb)))a=a.substring(e[0].length),e[0].replace(Xb,c),f=!1;f&&(e=a.indexOf("<"),f=e<0?a:a.substring(0,e),
a=e<0?"":a.substring(e),b.chars&&b.chars(eb(f)))}else a=a.replace(RegExp("(.*)<\\s*\\/\\s*"+g.last()+"[^>]*>","i"),function(a,c){c=c.replace(Kc,"$1").replace(Lc,"$1");b.chars&&b.chars(eb(c));return""}),d("",g.last());if(a==h)throw"Parse Error: "+a;h=a}d()}function eb(a){fb.innerHTML=a.replace(/</g,"&lt;");return fb.innerText||fb.textContent||""}function Yb(a){return a.replace(/&/g,"&amp;").replace(Mc,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"&lt;").replace(/>/g,"&gt;")}function wb(a){var b=
!1,c=M(a,a.push);return{start:function(a,e,f){a=H(a);!b&&Vb[a]&&(b=a);!b&&Zb[a]==!0&&(c("<"),c(a),k(e,function(a,b){var d=H(b);if(Nc[d]==!0&&($b[d]!==!0||a.match(Oc)))c(" "),c(b),c('="'),c(Yb(a)),c('"')}),c(f?"/>":">"))},end:function(a){a=H(a);!b&&Zb[a]==!0&&(c("</"),c(a),c(">"));a==b&&(b=!1)},chars:function(a){b||c(Yb(a))}}}function Pc(a){var b={},a=a[0].style,c,d;if(typeof a.length=="number")for(c=0;c<a.length;c++)d=a[c],b[d]=a[d];else for(d in a)c=a[d],1*d!=d&&d!="cssText"&&c&&typeof c=="string"&&
c!="false"&&(b[d]=c);return b}function Xa(a){if(u(a)&&a.charAt(0)!="<")throw new z("selectors not implemented");return new Y(a)}function Y(a){if(a instanceof Y)return a;else if(u(a)){var b=F.createElement("div");b.innerHTML="<div>&nbsp;</div>"+a;b.removeChild(b.firstChild);gb(this,b.childNodes);this.remove()}else gb(this,a)}function ua(a){ac(a);for(var b=0,a=a.childNodes||[];b<a.length;b++)ua(a[b])}function ac(a){var b=a[Fa],c=Ga[b];c&&(k(c.bind||{},function(b,c){Qc(a,c,b)}),delete Ga[b],a[Fa]=A)}
function hb(a,b,c){var d=a[Fa],d=Ga[d||-1];if(v(c))d||(a[Fa]=d=Rc++,d=Ga[d]={}),d[b]=c;else return d?d[b]:null}function ib(a,b){var c;return(" "+a.className+" ").replace(/[\n\t]/g," ").indexOf(" "+b+" ")>-1}function bc(a,b){b&&k(b.split(" "),function(b){a.className=ea((" "+a.className+" ").replace(/[\n\t]/g," ").replace(" "+ea(b)+" "," "))})}function cc(a,b){b&&k(b.split(" "),function(b){if(!ib(a,b))a.className=ea(a.className+" "+ea(b))})}function gb(a,b){if(b)for(var b=!b.nodeName&&v(b.length)&&
(!b||!b.document||!b.location||!b.alert||!b.setInterval)?b:[b],c=0;c<b.length;c++)a.push(b[c])}function jb(a){var b=typeof a,c=a;if(b=="object")if(typeof(c=a.$hashKey)=="function")c=a.$hashKey();else if(c===A)c=a.$hashKey=Oa();return b+":"+c}function dc(){}function ja(a,b){w[a]=w[a]||{};k(b,function(b){s(w[a],b)})}function ec(a,b,c,d,e){var f=a<0,a=Math.abs(a),g=a+"",h="",i=[];if(g.indexOf("e")!==-1)h=g;else{g=(g.split(fc)[1]||"").length;y(e)&&(e=Math.min(Math.max(b.minFrac,g),b.maxFrac));var g=Math.pow(10,
e),a=Math.round(a*g)/g,a=(""+a).split(fc),g=a[0],a=a[1]||"",j=0,l=b.lgSize,m=b.gSize;if(g.length>=l+m)for(var j=g.length-l,o=0;o<j;o++)(j-o)%m===0&&o!==0&&(h+=c),h+=g.charAt(o);for(o=j;o<g.length;o++)(g.length-o)%l===0&&o!==0&&(h+=c),h+=g.charAt(o);for(;a.length<e;)a+="0";e&&(h+=d+a.substr(0,e))}i.push(f?b.negPre:b.posPre);i.push(h);i.push(f?b.negSuf:b.posSuf);return i.join("")}function R(a,b,c){var d="";a<0&&(d="-",a=-a);for(a=""+a;a.length<b;)a="0"+a;c&&(a=a.substr(a.length-b));return d+a}function E(a,
b,c,d){return function(e){e=e["get"+a]();if(c>0||e>-c)e+=c;e===0&&c==-12&&(e=12);return R(e,b,d)}}function Ha(a,b){return function(c,d){var e=c["get"+a](),f=Ia(b?"SHORT"+a:a);return d[f][e]}}function na(a,b){return{format:a,parse:b||a}}function gc(a){return v(a)&&a!==null?""+a:a}function kb(a){var b=hc[a];if(!b){var c=[];k(Ja(a),function(a){var b=Ka(a);c.push(b?function(a,c){var d,i;try{i=a.$eval(b)}catch(j){a.$service("$exceptionHandler")(j),d=Q(j)}ka(c,lb,d);return d?d:i}:function(){return a})});
hc[a]=b=function(a,b,f){var g=[],h=a.hasOwnProperty("$element"),i=a.$element;a.$element=b;try{for(var j=0;j<c.length;j++){var l=c[j](a,b);Ra(l)?l="":I(l)&&(l=Q(l,f));g.push(l)}return g.join("")}finally{h?a.$element=i:delete a.$element}}}return b}function mb(a){return function(b){return function(c){this.$watch(b,function(b,e,f){a(b.$index)&&(c.removeClass(U(f)?f.join(" "):f),c.addClass(U(e)?e.join(" "):e))})}}}function Ja(a){for(var b=[],c=0,d;(d=a.indexOf("{{",c))>-1;)c<d&&b.push(a.substr(c,d-c)),
c=d,d=a.indexOf("}}",d),d=d<0?a.length:d+2,b.push(a.substr(c,d-c)),c=d;c!=a.length&&b.push(a.substr(c,a.length-c));return b.length===0?[a]:b}function Ka(a){return(a=a.replace(/\n/gm," ").match(/^\{\{(.*)\}\}$/))?a[1]:null}function va(a,b){var c=b.attr("name"),d,e;if(c){d=aa(c).assignable();e=d.assign;if(!e)throw new z("Expression '"+c+"' is not assignable.");return{get:function(){return d(a)},set:function(b){b!==A&&e(a,b)}}}}function ic(a,b){var c=va(a,b),d=b.attr("ng:format")||La,e=aa(d).formatter()();
if(c)return{get:function(){return e.format(a,c.get())},set:function(b){return c.set(e.parse(a,b))}}}function jc(a,b){function c(){var c=ea(b.val());if(b[0].disabled||b[0].readOnly)ka(b,wa,null),m.markValid(b);else{var d=Pa(a,{$element:b}),c=l&&!c?"Required":c?e(d,c):null;ka(b,wa,c);(j=c)?m.markInvalid(b):m.markValid(b)}}var d=b.attr("ng:validate")||La,e=aa(d).validator()(),f=b.attr("ng:required"),g=b.attr("ng:format")||La,g=aa(g).formatter()(),h,i,j,l,m=a.$service("$invalidWidgets")||{markValid:p,
markInvalid:p};if(!e)throw"Validator named '"+d+"' not found.";h=g.format;i=g.parse;f?a.$watch(f,function(a,b){l=b;c()}):l=f==="";b.data(nb,c);return{get:function(){j&&ka(b,wa,null);try{var d=i(a,b.val());c();return d}catch(e){j=e,ka(b,wa,e)}},set:function(d){var e=b.val(),d=h(a,d);e!=d&&b.val(d||"");c()}}}function Ma(a){return function(b,c){var d=c.get();!d&&v(a)&&(d=C(a));y(b.get())&&v(d)&&b.set(d)}}function xa(a,b,c,d,e){return ab("$defer",function(f,g){var h=this,i=b(h,g),j=c(h,g),l=g.attr("ng:change")||
p,m;i&&(d.call(h,i,j,g),h.$eval(g.attr("ng:init")||p),g.bind(a,function(a){function b(){var a=j.get();if(!e||a!=m)i.set(a),m=i.get(),h.$eval(l)}a.type=="keydown"?f(b):h.$apply(b)}),h.$watch(i.get,function(a,b){$(m,b)||j.set(m=b)}))})}function ob(a){this.directives(!0);this.descend(!0);return Sc[H(a[0].type)]||p}if(typeof F.getAttribute==pa)F.getAttribute=function(){};var H=function(a){return u(a)?a.toLowerCase():a},Ia=function(a){return u(a)?a.toUpperCase():a},Fc=A,nb="$validate",wc="boolean",mc=
"length",nc="name",Aa="null",pc="number",ub="object",oc="string",pa="undefined",lb="ng-exception",wa="ng-validation-error",La="noop",z=x.Error,V=parseInt((/msie (\d+)/.exec(H(navigator.userAgent))||[])[1],10),n,Wa,la=[].slice,P=[].push,vc=x.console?M(x.console,x.console.error||p):p,w=x.angular||(x.angular={}),Ta=T(w,"markup"),Bb=T(w,"attrMarkup"),B=T(w,"directive"),O=T(w,"widget",H),db=T(w,"validator"),X=T(w,"filter"),ia=T(w,"formatter"),Ba=T(w,"service");T(w,"callbacks");var sa,uc=/^(|.*\/)angular(-.*?)?(\.min)?.js(\?[^#]*)?(#(.*))?$/,
S=["0","0","0"],Fb=24;sa=V<9?function(a){a=a.nodeName?a:a[0];return a.scopeName&&a.scopeName!="HTML"?Ia(a.scopeName+":"+a.nodeName):a.nodeName}:function(a){return a.nodeName?a.nodeName:a[0].nodeName};w.toJson=Q;w.fromJson=fa;Za.prototype={link:function(a,b){var c=b;this.newScope&&(c=q(this.newScope)?b.$new(this.newScope(b)):b.$new(),a.data("$scope",c));k(this.linkFns,function(b){try{c.$service.invoke(c,b,[a])}catch(d){c.$service("$exceptionHandler")(d)}});var d,e=a[0].childNodes,f=this.children,g=
this.paths,h=g.length;for(d=0;d<h;d++)f[d].link(n(e[g[d]]),c)},addLinkFn:function(a){if(a){if(!a.$inject)a.$inject=[];this.linkFns.push(a)}},addChild:function(a,b){b&&(this.paths.push(a),this.children.push(b))},empty:function(){return this.linkFns.length===0&&this.paths.length===0}};Ab.prototype={compile:function(a){var a=n(a),b=0,c,d=a.parent();if(a.length>1)throw z("Cannot compile multiple element roots: "+n("<div>").append(a.clone()).html());if(d&&d[0])for(var d=d[0],e=0;e<d.childNodes.length;e++)d.childNodes[e]==
a[0]&&(b=e);c=this.templatize(a,b)||new Za;return function(b,d){var e=d?Eb.clone.call(a):a,b=b||$a();e.data("$scope",b);b.$element=e;(d||p)(e,b);c.link(e,b);return b}},templatize:function(a,b){var c=this,d,e,f=c.directives,g=!0,h=!0,i=sa(a),j=i.indexOf(":")>0?H(i).replace(":","-"):"",l,m={compile:M(c,c.compile),descend:function(a){v(a)&&(g=a);return g},directives:function(a){v(a)&&(h=a);return h},scope:function(a){if(v(a))l.newScope=l.newScope||a;return l.newScope}};a.addClass(j);l=new Za;za(a,function(b,
e){if(!d&&(d=c.widgets("@"+e)))a.addClass("ng-attr-widget"),d=M(m,d,b,a)});if(!d&&(d=c.widgets(i)))j&&a.addClass("ng-widget"),d=M(m,d,a);d&&(h=g=!1,i=a.parent(),l.addLinkFn(d.call(m,a)),i&&i[0]&&(a=n(i[0].childNodes[b])));if(g)for(var o=0,D=a[0].childNodes;o<D.length;o++)sa(D[o])=="#text"&&k(c.markup,function(b){if(o<D.length){var c=n(D[o]);b.call(m,c.text(),c,a)}});h&&(za(a,function(b,d){k(c.attrMarkup,function(c){c.call(m,b,d,a)})}),za(a,function(b,c){if(e=f[c])a.addClass("ng-directive"),l.addLinkFn(f[c].call(m,
b,a))}));g&&xc(a,function(a,b){l.addChild(b,c.templatize(a,b))});return l.empty()?null:l}};Gb.prototype={$new:function(a,b){var c=function(){};c.prototype=this;c=new c;c["this"]=c;c.$$listeners={};c.$parent=this;c.$id=Oa();c.$$asyncQueue=[];c.$$phase=c.$$watchers=c.$$nextSibling=c.$$childHead=c.$$childTail=null;c.$$prevSibling=this.$$childTail;this.$$childHead?this.$$childTail=this.$$childTail.$$nextSibling=c:this.$$childHead=this.$$childTail=c;if(a){var d=a.prototype,e;for(e in d)c[e]=M(c,d[e]);
this.$service.invoke(c,a,b)}return c},$watch:function(a,b){var c=Ib(a,"watch"),d=this.$$watchers,e={fn:Ib(b||p,"listener"),last:Number.NaN,get:c};if(!d)d=this.$$watchers=[];d.unshift(e);return function(){pb.remove(d,e)}},$digest:function(){var a,b,c,d,e,f,g=100,h;if(this.$$phase)throw z(this.$$phase+" already in progress");do{f=!1;h=this;do{h.$$phase="$digest";for(d=h.$$asyncQueue;d.length;)try{h.$eval(d.shift())}catch(i){h.$service("$exceptionHandler")(i)}if(d=h.$$watchers)for(e=d.length;e--;)try{if(a=
d[e],(b=a.get(h))!==(c=a.last)&&!$(b,c))f=!0,a.fn(h,a.last=C(b),c)}catch(j){h.$service("$exceptionHandler")(j)}h.$$phase=null;if(!(d=h.$$childHead||h!==this&&h.$$nextSibling))for(;h!==this&&!(d=h.$$nextSibling);)h=h.$parent}while(h=d);if(!g--)throw z("100 $digest() iterations reached. Aborting!");}while(f)},$destroy:function(){if(this.$root!=this){this.$emit("$destroy");var a=this.$parent;if(a.$$childHead==this)a.$$childHead=this.$$nextSibling;if(a.$$childTail==this)a.$$childTail=this.$$prevSibling;
if(this.$$prevSibling)this.$$prevSibling.$$nextSibling=this.$$nextSibling;if(this.$$nextSibling)this.$$nextSibling.$$prevSibling=this.$$prevSibling}},$eval:function(a){return(u(a)?W(a):a||p)(this)},$evalAsync:function(a){this.$$asyncQueue.push(a)},$apply:function(a){try{return this.$eval(a)}catch(b){this.$service("$exceptionHandler")(b)}finally{this.$root.$digest()}},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);return function(){pb.remove(c,b)}},$emit:function(a,
b){var c=[],d,e=!1,f=this,g={name:a,targetScope:f,cancel:function(){e=!0}},h=[g].concat(la.call(arguments,1)),i,j;do{d=f.$$listeners[a]||c;g.currentScope=f;i=0;for(j=d.length;i<j;i++)try{if(d[i].apply(null,h),e)return}catch(l){f.$service("$exceptionHandler")(l)}f=f.$parent}while(f)},$broadcast:function(a,b){var c=this,d=this,e={name:a,targetScope:this},f=[e].concat(la.call(arguments,1));do if(c=d,e.currentScope=c,k(c.$$listeners[a],function(a){try{a.apply(null,f)}catch(b){c.$service("$exceptionHandler")(b)}}),
!(d=c.$$childHead||c!==this&&c.$$nextSibling))for(;c!==this&&!(d=c.$$nextSibling);)c=c.$parent;while(c=d)}};var Ac=/^function\s*[^\(]*\(([^\)]*)\)/m,Bc=/,/,Cc=/^\s*(.+?)\s*$/,zc=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,bb={"null":function(){return null},"true":function(){return!0},"false":function(){return!1},$undefined:p,"+":function(a,b,c){return(v(b)?b:0)+(v(c)?c:0)},"-":function(a,b,c){return(v(b)?b:0)-(v(c)?c:0)},"*":function(a,b,c){return b*c},"/":function(a,b,c){return b/c},"%":function(a,b,c){return b%
c},"^":function(a,b,c){return b^c},"=":p,"==":function(a,b,c){return b==c},"!=":function(a,b,c){return b!=c},"<":function(a,b,c){return b<c},">":function(a,b,c){return b>c},"<=":function(a,b,c){return b<=c},">=":function(a,b,c){return b>=c},"&&":function(a,b,c){return b&&c},"||":function(a,b,c){return b||c},"&":function(a,b,c){return b&c},"|":function(a,b,c){return c(a,b)},"!":function(a,b){return!b}},Ec={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'},Nb={},Pb={},Ob={};k("abstract,boolean,break,byte,case,catch,char,class,const,continue,debugger,default,delete,do,double,else,enum,export,extends,false,final,finally,float,for,function,goto,if,implements,import,ininstanceof,intinterface,long,native,new,null,package,private,protected,public,return,short,static,super,switch,synchronized,this,throw,throws,transient,true,try,typeof,var,volatile,void,undefined,while,with".split(/,/),
function(a){Ob[a]=!0});Qb.prototype={url:function(a){var b=this,c=this.template,d,a=a||{};k(this.urlParams,function(e,g){d=Va(a[g]||b.defaults[g]||"",!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+");c=c.replace(RegExp(":"+g+"(\\W)"),d+"$1")});var c=c.replace(/\/?#$/,""),e=[];sb(a,function(a,c){b.urlParams[c]||e.push(Va(c)+"="+Va(a))});c=c.replace(/\/*$/,"");return c+(e.length?"?"+e.join("&"):"")}};Ea.DEFAULT_ACTIONS={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},
remove:{method:"DELETE"},"delete":{method:"DELETE"}};Ea.prototype={route:function(a,b,c){function d(a){var c={};k(b||{},function(b,d){c[d]=b.charAt&&b.charAt(0)=="@"?Da(a,b.substr(1)):b});return c}function e(a){C(a||{},this)}var f=this,g=new Qb(a),c=s({},Ea.DEFAULT_ACTIONS,c);k(c,function(h,i){var j=h.method=="POST"||h.method=="PUT";e[i]=function(a,b,c,i){var t={},n,r=p,K=null;switch(arguments.length){case 4:K=i,r=c;case 3:case 2:if(q(b)){if(q(a)){r=a;K=b;break}r=b;K=c}else{t=a;n=b;r=c;break}case 1:q(a)?
r=a:j?n=a:t=a;break;case 0:break;default:throw"Expected between 0-4 arguments [params, data, success, error], got "+arguments.length+" arguments.";}var L=this instanceof e?this:h.isArray?[]:new e(n);f.xhr(h.method,g.url(s({},h.params||{},d(n),t)),n,function(a,b){if(b)h.isArray?(L.length=0,k(b,function(a){L.push(new e(a))})):C(b,L);(r||p)(L)},K||h.verifyCache,h.verifyCache);return L};e.bind=function(d){return f.route(a,s({},b,d),c)};e.prototype["$"+i]=function(a,b,c){var g=d(this),f=p,h;switch(arguments.length){case 3:g=
a;f=b;h=c;break;case 2:case 1:q(a)?(f=a,h=b):(g=a,f=b||p);case 0:break;default:throw"Expected between 1-3 arguments [params, success, error], got "+arguments.length+" arguments.";}e[i].call(this,g,j?this:A,f,h)}});return e}};var Tc=x.XMLHttpRequest||function(){try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(b){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(c){}throw new z("This browser does not support XMLHttpRequest.");
},Xb=/^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,Wb=/^<\s*\/\s*([\w:-]+)[^>]*>/,Hc=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,Jc=/^</,Ic=/^<\s*\//,Kc=/<\!--(.*?)--\>/g,Lc=/<!\[CDATA\[(.*?)]]\>/g,Oc=/^((ftp|https?):\/\/|mailto:|#)/,Mc=/([^\#-~| |!])/g,Ub=Z("area,br,col,hr,img"),Rb=Z("address,blockquote,center,dd,del,dir,div,dl,dt,hr,ins,li,map,menu,ol,p,pre,script,table,tbody,td,tfoot,th,thead,tr,ul"),Sb=Z("a,abbr,acronym,b,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,q,s,samp,small,span,strike,strong,sub,sup,tt,u,var"),
Tb=Z("colgroup,dd,dt,li,p,td,tfoot,th,thead,tr"),Vb=Z("script,style"),Zb=s({},Ub,Rb,Sb,Tb),$b=Z("background,href,longdesc,src,usemap"),Nc=s({},$b,Z("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,span,start,summary,target,title,type,valign,value,vspace,width")),fb=F.createElement("pre"),Ga={},Fa="ng-"+(new Date).getTime(),
Rc=1,Uc=x.document.addEventListener?function(a,b,c){a.addEventListener(b,c,!1)}:function(a,b,c){a.attachEvent("on"+b,c)},Qc=x.document.removeEventListener?function(a,b,c){a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent("on"+b,c)},Eb=Y.prototype={ready:function(a){function b(){c||(c=!0,a())}var c=!1;this.bind("DOMContentLoaded",b);Xa(x).bind("load",b)},toString:function(){var a=[];k(this,function(b){a.push(""+b)});return"["+a.join(", ")+"]"},eq:function(a){return a>=0?n(this[a]):n(this[this.length+
a])},length:0,push:P,sort:[].sort,splice:[].splice},Vc=Z("multiple,selected,checked,disabled,readonly");k({data:hb,scope:function(a){for(var b;a&&!(b=n(a).data("$scope"));)a=a.parentNode;return b},removeAttr:function(a,b){a.removeAttribute(b)},hasClass:ib,css:function(a,b,c){if(v(c))a.style[b]=c;else return a.style[b]},attr:function(a,b,c){if(b==="class")if(v(c))a.className=c;else return a.className;else if(Vc[b])if(v(c))a[b]=!!c;else return a[b];else if(v(c))a.setAttribute(b,c);else if(a.getAttribute)return a=
a.getAttribute(b,2),a===null?A:a},text:s(V<9?function(a,b){if(a.nodeType==3){if(y(b))return a.nodeValue;a.nodeValue=b}else{if(y(b))return a.innerText;a.innerText=b}}:function(a,b){if(y(b))return a.textContent;a.textContent=b},{$dv:""}),val:function(a,b){if(y(b))return a.value;a.value=b},html:function(a,b){if(y(b))return a.innerHTML;for(var c=0,d=a.childNodes;c<d.length;c++)ua(d[c]);a.innerHTML=b}},function(a,b){Y.prototype[b]=function(b,d){var e,f;if((a.length==2?b:d)===A)if(I(b)){for(e=0;e<this.length;e++)for(f in b)a(this[e],
f,b[f]);return this}else{if(this.length)return a(this[0],b,d)}else{for(e=0;e<this.length;e++)a(this[e],b,d);return this}return a.$dv}});k({removeData:ac,dealoc:ua,bind:function(a,b,c){var d=hb(a,"bind");d||hb(a,"bind",d={});k(b.split(" "),function(b){var f=d[b];if(!f)d[b]=f=function(b){if(!b.preventDefault)b.preventDefault=function(){b.returnValue=!1};if(!b.stopPropagation)b.stopPropagation=function(){b.cancelBubble=!0};if(!b.target)b.target=b.srcElement||F;k(f.fns,function(c){c.call(a,b)})},f.fns=
[],Uc(a,b,f);f.fns.push(c)})},replaceWith:function(a,b){var c,d=a.parentNode;ua(a);k(new Y(b),function(b){c?d.insertBefore(b,c.nextSibling):d.replaceChild(b,a);c=b})},children:function(a){var b=[];k(a.childNodes,function(a){a.nodeName!="#text"&&b.push(a)});return b},append:function(a,b){k(new Y(b),function(b){a.nodeType===1&&a.appendChild(b)})},prepend:function(a,b){if(a.nodeType===1){var c=a.firstChild;k(new Y(b),function(b){c?a.insertBefore(b,c):(a.appendChild(b),c=b)})}},remove:function(a){ua(a);
var b=a.parentNode;b&&b.removeChild(a)},after:function(a,b){var c=a,d=a.parentNode;k(new Y(b),function(a){d.insertBefore(a,c.nextSibling);c=a})},addClass:cc,removeClass:bc,toggleClass:function(a,b,c){y(c)&&(c=!ib(a,b));(c?cc:bc)(a,b)},parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},next:function(a){return a.nextSibling},find:function(a,b){return a.getElementsByTagName(b)},clone:function(a){return a.cloneNode(!0)}},function(a,b){Y.prototype[b]=function(b,d){for(var e,f=0;f<this.length;f++)e==
A?(e=a(this[f],b,d),e!==A&&(e=n(e))):gb(e,a(this[f],b,d));return e==A?this:e}});var ca={typeOf:function(a){if(a===null)return Aa;var b=typeof a;if(b==ub){if(a instanceof Array)return"array";if(qa(a))return"date";if(a.nodeType==1)return"element"}return b}},P={copy:C,size:xb,equals:$},Wc={extend:s},pb={indexOf:ya,sum:function(a,b){for(var c=qb.compile(b),d=0,e=0;e<a.length;e++){var f=1*c(a[e]);isNaN(f)||(d+=f)}return d},remove:function(a,b){var c=ya(a,b);c>=0&&a.splice(c,1);return b},filter:function(a,
b){var c=[];c.check=function(a){for(var b=0;b<c.length;b++)if(!c[b](a))return!1;return!0};var d=function(a,b){if(b.charAt(0)==="!")return!d(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return(""+a).toLowerCase().indexOf(b)>-1;case "object":for(var c in a)if(c.charAt(0)!=="$"&&d(a[c],b))return!0;return!1;case "array":for(c=0;c<a.length;c++)if(d(a[c],b))return!0;return!1;default:return!1}};switch(typeof b){case "boolean":case "number":case "string":b={$:b};case "object":for(var e in b)e==
"$"?function(){var a=(""+b[e]).toLowerCase();a&&c.push(function(b){return d(b,a)})}():function(){var a=e,g=(""+b[e]).toLowerCase();g&&c.push(function(b){return d(Da(b,a),g)})}();break;case "function":c.push(b);break;default:return a}for(var f=[],g=0;g<a.length;g++){var h=a[g];c.check(h)&&f.push(h)}return f},add:function(a,b){a.push(y(b)?{}:b);return a},count:function(a,b){if(!b)return a.length;var c=qb.compile(b),d=0;k(a,function(a){c(a)&&d++});return d},orderBy:function(a,b,c){function d(a,b){return ma(b)?
function(b,c){return a(c,b)}:a}if(!b)return a;for(var b=U(b)?b:[b],b=qc(b,function(a){var b=!1,c=a||da;if(u(a)){if(a.charAt(0)=="+"||a.charAt(0)=="-")b=a.charAt(0)=="-",a=a.substring(1);c=W(a)}return d(function(a,b){var d;d=c(a);var e=c(b),g=typeof d,f=typeof e;g==f?(g=="string"&&(d=d.toLowerCase()),g=="string"&&(e=e.toLowerCase()),d=d===e?0:d<e?-1:1):d=g<f?-1:1;return d},b)}),e=[],f=0;f<a.length;f++)e.push(a[f]);return e.sort(d(function(a,c){for(var d=0;d<b.length;d++){var e=b[d](a,c);if(e!==0)return e}return 0},
c))},limitTo:function(a,b){var b=parseInt(b,10),c=[],d,e;b>0?(d=0,e=b):(d=a.length+b,e=a.length);for(;d<e;d++)c.push(a[d]);return c}},Xc=/^(\d{4})-(\d\d)-(\d\d)(?:T(\d\d)(?:\:(\d\d)(?:\:(\d\d)(?:\.(\d{3}))?)?)?Z)?$/,ga={quote:function(a){return'"'+a.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/\t/g,"\\t").replace(/\v/g,"\\v")+'"'},quoteUnicode:function(a){for(var a=w.String.quote(a),b=[],c=0;c<a.length;c++){var d=a.charCodeAt(c);
d<128?b.push(a.charAt(c)):(d="000"+d.toString(16),b.push("\\u"+d.substring(d.length-4)))}return b.join("")},toDate:function(a){var b;if(u(a)&&(b=a.match(Xc)))a=new Date(0),a.setUTCFullYear(b[1],b[2]-1,b[3]),a.setUTCHours(b[4]||0,b[5]||0,b[6]||0,b[7]||0);return a}},kc={toString:function(a){if(!a)return a;var b=a.toISOString?a.toISOString():"";return b.length==24?b:R(a.getUTCFullYear(),4)+"-"+R(a.getUTCMonth()+1,2)+"-"+R(a.getUTCDate(),2)+"T"+R(a.getUTCHours(),2)+":"+R(a.getUTCMinutes(),2)+":"+R(a.getUTCSeconds(),
2)+"."+R(a.getUTCMilliseconds(),3)+"Z"}},qb={compile:function(a){return q(a)?a:a?W(a):da}};dc.prototype={put:function(a,b){var c=jb(a),d=this[c];this[c]=b;return d},get:function(a){return this[jb(a)]},remove:function(a){var a=jb(a),b=this[a];delete this[a];return b}};ja("Global",[ca]);ja("Collection",[ca,P]);ja("Array",[ca,P,pb]);ja("Object",[ca,P,Wc]);ja("String",[ca,ga]);ja("Date",[ca,kc]);w.Date.toString=kc.toString;ja("Function",[ca,P,qb]);X.currency=function(a,b){var c=this.$service("$locale").NUMBER_FORMATS;
this.$element.toggleClass("ng-format-negative",a<0);if(y(b))b=c.CURRENCY_SYM;return ec(a,c.PATTERNS[1],c.GROUP_SEP,c.DECIMAL_SEP,2).replace(/\u00A4/g,b)};var fc=".";X.number=function(a,b){if(isNaN(a)||!isFinite(a))return"";var c=this.$service("$locale").NUMBER_FORMATS;return ec(a,c.PATTERNS[0],c.GROUP_SEP,c.DECIMAL_SEP,b)};var Yc={yyyy:E("FullYear",4),yy:E("FullYear",2,0,!0),y:E("FullYear",1),MMMM:Ha("Month"),MMM:Ha("Month",!0),MM:E("Month",2,1),M:E("Month",1,1),dd:E("Date",2),d:E("Date",1),HH:E("Hours",
2),H:E("Hours",1),hh:E("Hours",2,-12),h:E("Hours",1,-12),mm:E("Minutes",2),m:E("Minutes",1),ss:E("Seconds",2),s:E("Seconds",1),EEEE:Ha("Day"),EEE:Ha("Day",!0),a:function(a,b){return a.getHours()<12?b.AMPMS[0]:b.AMPMS[1]},Z:function(a){a=a.getTimezoneOffset();return R(a/60,2)+R(Math.abs(a%60),2)}},Zc=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,$c=/^\d+$/;X.date=function(a,b){var c=this.$service("$locale"),b=c.DATETIME_FORMATS[b]||b;u(a)&&(a=$c.test(a)?parseInt(a,
10):ga.toDate(a));oa(a)&&(a=new Date(a));if(!qa(a))return a;var d=a.toLocaleDateString(),e;if(b&&u(b)){for(var d="",f=[],g;b;)(g=Zc.exec(b))?(f=f.concat(la.call(g,1)),b=f.pop()):(f.push(b),b=null);k(f,function(b){e=Yc[b];d+=e?e(a,c.DATETIME_FORMATS):b.replace(/(^'|'$)/g,"").replace(/''/g,"'")})}return d};X.json=function(a){this.$element.addClass("ng-monospace");return Q(a,!0)};X.lowercase=H;X.uppercase=Ia;X.html=function(a,b){return new Sa(a,b)};var ad=/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
bd=/^mailto:/;X.linky=function(a){if(!a)return a;for(var b=a,c=[],d=wb(c),e,f;a=b.match(ad);)e=a[0],a[2]==a[3]&&(e="mailto:"+e),f=a.index,d.chars(b.substr(0,f)),d.start("a",{href:e}),d.chars(a[0].replace(bd,"")),d.end("a"),b=b.substring(f+a[0].length);d.chars(b);return new Sa(c.join(""))};var cd=/^\s*[-+]?\d*(\.\d*)?\s*$/;ia.noop=na(da,da);ia.json=na(Q,function(a){return fa(a||"null")});ia["boolean"]=na(gc,ma);ia.number=na(gc,function(a){if(a==null||cd.exec(a))return a===null||a===""?null:1*a;else throw"Not a number";
});ia.list=na(function(a){return a?a.join(", "):a},function(a){var b=[];k((a||"").split(","),function(a){(a=ea(a))&&b.push(a)});return b});ia.trim=na(function(a){return a?ea(""+a):""});s(db,{noop:function(){return null},regexp:function(a,b,c){return a.match(b)?null:c||"Value does not match expected format "+b+"."},number:function(a,b,c){var d=1*a;return d==a?typeof b!=pa&&d<b?"Value can not be less than "+b+".":typeof b!=pa&&d>c?"Value can not be greater than "+c+".":null:"Not a number"},integer:function(a,
b,c){return(b=db.number(a,b,c))?b:!(""+a).match(/^\s*[\d+]*\s*$/)||a!=Math.round(a)?"Not a whole number":null},date:function(a){var b=(a=/^(\d\d?)\/(\d\d?)\/(\d\d\d\d)$/.exec(a))?new Date(a[3],a[1]-1,a[2]):0;return b&&b.getFullYear()==a[3]&&b.getMonth()==a[1]-1&&b.getDate()==a[2]?null:"Value is not a date. (Expecting format: 12/31/2009)."},email:function(a){return a.match(/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/)?null:"Email needs to be in username@host.com format."},phone:function(a){return a.match(/^1\(\d\d\d\)\d\d\d-\d\d\d\d$/)?
null:a.match(/^\+\d{2,3} (\(\d{1,5}\))?[\d ]+\d$/)?null:"Phone number needs to be in 1(987)654-3210 format in North America or +999 (123) 45678 906 internationally."},url:function(a){return a.match(/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/)?null:"URL needs to be in http://server[:port]/path format."},json:function(a){try{return fa(a),null}catch(b){return b.toString()}},asynchronous:function(a,b,c){if(a){var d=this.$element,e=d.data("$asyncValidator");e||
d.data("$asyncValidator",e={inputs:{}});e.current=a;var f=e.inputs[a],g=this.$service("$invalidWidgets");f?f.inFlight?g.markInvalid(this.$element):(c||p)(f.response):(e.inputs[a]=f={inFlight:!0},g.markInvalid(this.$element),d.addClass("ng-input-indicator-wait"),b(a,function(b,c){f.response=c;f.error=b;f.inFlight=!1;e.current==a&&(d.removeClass("ng-input-indicator-wait"),g.markValid(d));d.data(nb)()}));return f.error}}});G("$cookieStore",function(a){return{get:function(b){return fa(a[b])},put:function(b,
c){a[b]=Q(c)},remove:function(b){delete a[b]}}},["$cookies"]);G("$cookies",function(a){var b=this,c={},d={},e,f=!1;a.addPollFn(function(){var g=a.cookies();e!=g&&(e=g,C(g,d),C(g,c),f&&b.$apply())})();f=!0;this.$watch(function(){var b,e,f;for(b in d)y(c[b])&&a.cookies(b,A);for(b in c)e=c[b],u(e)?e!==d[b]&&(a.cookies(b,e),f=!0):v(d[b])?c[b]=d[b]:delete c[b];if(f)for(b in e=a.cookies(),c)c[b]!==e[b]&&(y(e[b])?delete c[b]:c[b]=e[b])});return c},["$browser"]);G("$defer",function(a){var b=this;return function(c,
d){a.defer(function(){b.$apply(c)},d)}},["$browser"]);G("$document",function(a){return n(a.document)},["$window"]);G("$exceptionHandler",function(a){return function(b){a.error(b)}},["$log"]);G("$hover",function(a,b){var c,d,e=n(b[0].body);a.hover(function(a,b){if(b&&(d=a.attr(lb)||a.attr(wa))){c||(c={callout:n('<div id="ng-callout"></div>'),arrow:n("<div></div>"),title:n('<div class="ng-title"></div>'),content:n('<div class="ng-content"></div>')},c.callout.append(c.arrow),c.callout.append(c.title),
c.callout.append(c.content),e.append(c.callout));var h=e[0].getBoundingClientRect(),i=a[0].getBoundingClientRect(),h=h.right-i.right-10;c.title.text(a.hasClass("ng-exception")?"EXCEPTION:":"Validation error...");c.content.text(d);h<300?(c.arrow.addClass("ng-arrow-right"),c.arrow.css({left:"301px"}),c.callout.css({position:"fixed",left:i.left-10-300-4+"px",top:i.top-3+"px",width:"300px"})):(c.arrow.addClass("ng-arrow-left"),c.callout.css({position:"fixed",left:i.right+10+"px",top:i.top-3+"px",width:"300px"}))}else c&&
(c.callout.remove(),c=null)})},["$browser","$document"],!0);G("$invalidWidgets",function(){function a(b){if(b==x.document)return!1;b=b.parentNode;return!b||a(b)}var b=[];b.markValid=function(a){a=ya(b,a);a!=-1&&b.splice(a,1)};b.markInvalid=function(a){ya(b,a)===-1&&b.push(a)};b.visible=function(){var a=0;k(b,function(b){var e=a,b=b[0].getBoundingClientRect(),f=b.height||b.bottom||0-b.top||0;a=e+((b.width||b.right||0-b.left||0)>0&&f>0?1:0)});return a};this.$watch(function(){for(var c=0;c<b.length;){var d=
b[c];a(d[0])?(b.splice(c,1),d.dealoc&&d.dealoc()):c++}});return b});var dd=/^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,ed=/^([^\?]*)?(\?([^\?]*))?$/,lc={http:80,https:443,ftp:21};G("$location",function(a){function b(b){if(u(b)){var c=s,l=g,m={},o=dd.exec(b);if(o)m.href=b.replace(/#$/,""),m.protocol=o[1],m.host=o[3]||"",m.port=o[5]||lc[m.protocol]||null,m.path=o[6]||"",m.search=Ua(o[8]),m.hash=o[10]||"",s(m,f(m.hash));c(l,m)}else{v(b.hash)&&
s(b,u(b.hash)?f(b.hash):b.hash);s(g,b);if(v(b.hashPath||b.hashSearch))g.hash=e(g);g.href=d(g)}a.setUrl(g.href);C(g,h)}function c(a,c){var d={};u(a)?(d.hashPath=a,d.hashSearch=c||{}):d.hashSearch=a;d.hash=e(d);b({hash:d})}function d(a){var b=Cb(a.search),c=a.port==lc[a.protocol]?null:a.port;return a.protocol+"://"+a.host+(c?":"+c:"")+a.path+(b?"?"+b:"")+(a.hash?"#"+a.hash:"")}function e(a){var b=Cb(a.hashSearch);return escape(a.hashPath).replace(/%21/gi,"!").replace(/%3A/gi,":").replace(/%24/gi,"$")+
(b?"?"+b:"")}function f(a){var b={},c=ed.exec(a);if(c)b.hash=a,b.hashPath=unescape(c[1]||""),b.hashSearch=Ua(c[3]);return b}var g={update:b,updateHash:c},h={};a.onHashChange(M(this,this.$apply,function(){b(a.getUrl())}))();this.$watch(function(){if(!$(g,h)){if(g.href==h.href)if(g.hash!=h.hash){var a=f(g.hash);c(a.hashPath,a.hashSearch)}else g.hash=e(g),g.href=d(g);b(g.href)}});return g},["$browser"]);G("$log",function(a){function b(b){var d=a.console||{},e=d[b]||d.log||p;return e.apply?function(){var a=
[];k(arguments,function(b){a.push(tb(b))});return e.apply(d,a)}:e}return{log:b("log"),warn:b("warn"),info:b("info"),error:b("error")}},["$window"]);G("$resource",function(a){a=new Ea(a);return M(a,a.route)},["$xhr.cache"]);G("$route",function(a,b){function c(){var b,c;k(e,function(d,e){if(!c&&(b=f(a.hashPath,e)))c=Pa(d,{params:s({},a.hashSearch,b),pathParams:b}),c.$route=d});return c||e[null]&&Pa(e[null],{params:{},pathParams:{}})}function d(a,b){var c=[];k((a||"").split(":"),function(a,d){if(d==
0)c.push(a);else{var e=a.match(/(\w+)(.*)/),g=e[1];c.push(b[g]);c.push(e[2]||"");delete b[g]}});return c.join("")}var e={},f=function(a,b,c){var d="^"+b.replace(/[\.\\\(\)\^\$]/g,"$1")+"$",e=[],g={};k(b.split(/\W/),function(a){if(a){var b=RegExp(":"+a+"([\\W])");d.match(b)&&(d=d.replace(b,"([^/]*)$1"),e.push(a))}});var f=a.match(RegExp(d));f&&(k(e,function(a,b){g[a]=f[b+1]}),c&&this.$set(c,g));return f?g:null},g=this,h=this,i=0,j=!0,l={routes:e,parent:function(a){a&&(g=a)},when:function(a,b){if(y(a))return e;
var c=e[a];c||(c=e[a]={reloadOnSearch:!0});b&&s(c,b);i++;return c},otherwise:function(a){l.when(null,a)},reload:function(){i++;j=!1}};this.$watch(function(){return i+a.hash},function(){var e=c(),f=l.current;if(e&&f&&e.$route===f.$route&&$(e.pathParams,f.pathParams)&&!e.reloadOnSearch&&j)l.current=e,C(e.params,b),f.scope&&f.scope.$emit("$routeUpdate");else{j=!0;h.$broadcast("$beforeRouteChange",e,f);f&&f.scope&&f.scope.$destroy();if(l.current=e)e.redirectTo?a.update(u(e.redirectTo)?{hashSearch:e.params,
hashPath:d(e.redirectTo,e.params)}:{hash:e.redirectTo(e.pathParams,a.hash,a.hashPath,a.hashSearch)}):(C(e.params,b),e.scope=g.$new(e.controller));h.$broadcast("$afterRouteChange",e,f)}});return l},["$location","$routeParams"]);Ba("$routeParams",function(){return{}});G("$window",M(x,da,x));G("$xhr.bulk",function(a,b,c){function d(b,c,g,h,i){q(g)&&(i=h,h=g,g=null);var j;k(d.urls,function(a){if(q(a.match)?a.match(c):a.match.exec(c))j=a});if(j){if(!j.requests)j.requests=[];b={method:b,url:c,data:g,success:h};
if(i)b.error=i;j.requests.push(b)}else a(b,c,g,h,i)}d.urls={};d.flush=function(e,f){ra(e=e||p,0);ra(f=f||p,1);k(d.urls,function(d,f){var i=d.requests;if(i&&i.length)d.requests=[],d.callbacks=[],a("POST",f,{requests:i},function(a,d){k(d,function(a,d){try{a.status==200?(i[d].success||p)(a.status,a.response):q(i[d].error)?i[d].error(a.status,a.response):b(i[d],a)}catch(e){c.error(e)}});e()},function(a,d){k(i,function(e){try{q(e.error)?e.error(a,d):b(e,d)}catch(g){c.error(g)}})})})};this.$watch(function(){d.flush()});
return d},["$xhr","$xhr.error","$log"]);G("$xhr.cache",function(a,b,c,d){function e(a,h,i,j,l,m,o){q(i)?(q(j)?(o=m,m=l,l=j):(m=j,o=l,l=null),j=i,i=null):q(l)||(o=m,m=l,l=null);if(a=="GET"){var n;if(n=e.data[h])if(o?j(200,C(n.value)):b(function(){j(200,C(n.value))}),!m)return;(m=f[h])?(m.successes.push(j),m.errors.push(l)):(f[h]={successes:[j],errors:[l]},e.delegate(a,h,i,function(a,b){a==200&&(e.data[h]={value:b});var c=f[h].successes;delete f[h];k(c,function(c){try{(c||p)(a,C(b))}catch(e){d.error(e)}})},
function(b,e){var j=f[h].errors,l=f[h].successes;delete f[h];k(j,function(f,j){try{q(f)?f(b,C(e)):c({method:a,url:h,data:i,success:l[j]},{status:b,body:e})}catch(m){d.error(m)}})}))}else e.data={},e.delegate(a,h,i,j,l)}var f={};e.data={};e.delegate=a;return e},["$xhr.bulk","$defer","$xhr.error","$log"]);G("$xhr.error",function(a){return function(b,c){a.error("ERROR: XHR: "+b.url,b,c)}},["$log"]);G("$xhr",function(a,b,c){function d(d,h,i,j,l){q(i)&&(l=j,j=i,i=null);i&&I(i)&&(i=Q(i));a.xhr(d,h,i,function(a,
f){try{u(f)&&(f.match(/^\)\]\}',\n/)&&(f=f.substr(6)),/^\s*[\[\{]/.exec(f)&&/[\}\]]\s*$/.exec(f)&&(f=fa(f,!0))),e.$apply(function(){200<=a&&a<300?j(a,f):q(l)?l(a,f):b({method:d,url:h,data:i,success:j},{status:a,body:f})})}catch(k){c.error(k)}},s({"X-XSRF-TOKEN":a.cookies()["XSRF-TOKEN"]},f.common,f[H(d)]))}var e=this,f={common:{Accept:"application/json, text/plain, */*","X-Requested-With":"XMLHttpRequest"},post:{"Content-Type":"application/x-www-form-urlencoded"},get:{},head:{},put:{},"delete":{},
patch:{}};d.defaults={headers:f};return d},["$browser","$xhr.error","$log"]);G("$locale",function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),
SHORTMONTH:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),DAY:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),SHORTDAY:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(","),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(a){return a===1?"one":"other"}}});B("ng:init",function(a){return function(){this.$eval(a)}});
B("ng:controller",function(a){this.scope(function(b){b=Da(b,a,!0)||Da(x,a,!0);ra(b,a);return b});return p});B("ng:bind",function(a,b){b.addClass("ng-binding");var c=aa(a).statements();return function(a){var b=p,f=p;this.$watch(function(g){var h,i,j,l;l=g.hasOwnProperty("$element");var m=g.$element;g.$element=a;try{i=c(g)}catch(k){g.$service("$exceptionHandler")(k),h=tb(k)}finally{l?g.$element=m:delete g.$element}if(g=i instanceof Sa)i=(j=i).html;if(!(b===i&&f==h)&&(l=Ra(i),!g&&!l&&I(i)&&(i=Q(i,!0)),
i!=b||h!=f))b=i,f=h,ka(a,lb,h),h&&(i=h),g?a.html(j.get()):l?(a.html(""),a.append(i)):a.text(i==A?"":i)})}});var hc={};B("ng:bind-template",function(a,b){b.addClass("ng-binding");var c=kb(a);return function(a){var b;this.$watch(function(f){f=c(f,a,!0);f!=b&&(a.text(f),b=f)})}});var fd={disabled:"disabled",readonly:"readOnly",checked:"checked",selected:"selected",multiple:"multiple"};B("ng:bind-attr",function(a){return function(b){var c={};this.$watch(function(d){var e=d.$eval(a),f;for(f in e){var g=
kb(e[f])(d,b),h=fd[H(f)];c[f]!==g&&(c[f]=g,h?(ma(g)?(b.attr(h,h),b.attr("ng-"+h,g)):(b.removeAttr(h),b.removeAttr("ng-"+h)),(b.data(nb)||p)()):b.attr(f,g))}})}});B("ng:click",function(a){return function(b){var c=this;b.bind("click",function(b){c.$apply(a);b.stopPropagation()})}});B("ng:submit",function(a){return function(b){var c=this;b.bind("submit",function(b){c.$apply(a);b.preventDefault()})}});B("ng:class",mb(function(){return!0}));B("ng:class-odd",mb(function(a){return a%2===0}));B("ng:class-even",
mb(function(a){return a%2===1}));B("ng:show",function(a){return function(b){this.$watch(a,function(a,d){b.css("display",ma(d)?"":"none")})}});B("ng:hide",function(a){return function(b){this.$watch(a,function(a,d){b.css("display",ma(d)?"none":"")})}});B("ng:style",function(a){return function(b){var c=Pc(b);this.$watch(function(d){var d=d.$eval(a)||{},e,f={};for(e in d)c[e]===A&&(c[e]=""),f[e]=d[e];for(e in c)f[e]=f[e]||c[e];b.css(f)})}});B("ng:cloak",function(a,b){b.removeAttr("ng:cloak");b.removeClass("ng-cloak")});
Ta("{{}}",function(a,b,c){var d=Ja(a);if(d.length>1||Ka(d[0])!==null)if(rc(c[0]))c.attr("ng:bind-template",a);else{var e=b,f;k(Ja(a),function(a){var b=Ka(a);b?(f=n("<span>"),f.attr("ng:bind",b)):f=n(F.createTextNode(a));V&&a.charAt(0)==" "&&(f=n("<span>&nbsp;</span>"),b=f.html(),f.text(a.substr(1)),f.html(b+f.html()));e.after(f);e=f});b.remove()}});Ta("option",function(a,b,c){H(sa(c))=="option"&&(V<=7?vb(c[0].outerHTML,{start:function(b,e){y(e.value)&&c.attr("value",a)}}):c[0].getAttribute("value")==
null&&c.attr("value",a))});var rb={};k("src,href,checked,disabled,multiple,readonly,selected".split(","),function(a){rb["ng:"+a]=a});Bb("{{}}",function(a,b,c){if(!B(b)&&!B("@"+b)){V&&b=="src"&&(a=decodeURI(a));var d=Ja(a);if(d.length>1||Ka(d[0])!==null||rb[b])c.removeAttr(b),d=fa(c.attr("ng:bind-attr")||"{}"),d[rb[b]||b]=a,c.attr("ng:bind-attr",Q(d))}});var P=xa("keydown change",va,jc,Ma(),!0),Sc={text:P,textarea:P,hidden:P,password:P,checkbox:xa("click",ic,function(a,b){var c=b[0];return{get:function(){return!!c.checked},
set:function(a){c.checked=ma(a)}}},Ma(!1)),radio:xa("click",ic,function(a,b){var c=b[0];return{get:function(){return c.checked?c.value:null},set:function(a){c.checked=a==c.value}}},function(a,b,c){var d=a.get(),e=b.get(),c=c[0];c.checked=!1;c.name=this.$id+"@"+c.name;y(d)&&a.set(d=null);d==null&&e!==null&&a.set(e);b.set(d)}),"select-one":xa("change",va,jc,Ma(null)),"select-multiple":xa("change",va,function(a,b){var c=b.attr("ng:format")||La,d=aa(c).formatter()();return{get:function(){var c=[];k(b[0].options,
function(b){b.selected&&c.push(d.parse(a,b.value))});return c},set:function(c){var f={};k(c,function(b){f[d.format(a,b)]=!0});k(b[0].options,function(a){a.selected=f[a.value]})}}},Ma([]))};O("input",ob);O("textarea",ob);var gd=/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/;O("select",function(a){this.descend(!0);this.directives(!0);var b=a.attr("multiple"),c=a.attr("ng:options"),d=W(a.attr("ng:change")||
""),e;if(!c)return ob.call(this,a);if(!(e=c.match(gd)))throw z("Expected ng:options in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '"+c+"'.");var f=W(e[2]||e[1]),g=e[4]||e[6],h=e[5],i=W(e[3]||""),j=W(e[2]?e[1]:g),l=W(e[7]),m=n(F.createElement("option")),o=n(F.createElement("optgroup")),D=!1;return function(c){var e=[[{element:c,label:""}]],r=this,p=va(r,a);k(c.children(),function(a){a.value==""&&(D={label:n(a).text(),id:""})});c.html("");c.bind("change",function(){var a,
f=l(r)||[],i=c.val(),m=r.$new(),k,o,n,D,s,q;if(b){k=[];D=0;for(q=e.length;D<q;D++){a=e[D];n=1;for(s=a.length;n<s;n++)if((o=a[n].element)[0].selected)h&&(m[h]=i),m[g]=f[o.val()],k.push(j(m))}}else i=="?"?k=A:i==""?k=null:(m[g]=f[i],h&&(m[h]=i),k=j(m));v(k)&&p.get()!==k&&(d(r),p.set(k));r.$root.$apply()});r.$watch(function(a){var d={"":[]},k=[""],n,r,q,u,v,w,x=l(a)||[],y=x,C,H,A,z,J,a=a.$new(),B=p.get(),G,E=!1,F,I;try{if(b){if(E=new dc,B&&oa(A=B.length))for(J=0;J<A;J++)E.put(B[J],!0)}else if(B===null||
D)d[""].push(s({selected:B===null,id:"",label:""},D)),E=!0;if(h){y=[];for(C in x)x.hasOwnProperty(C)&&y.push(C);y.sort()}for(J=0;A=y.length,J<A;J++){a[g]=x[h?a[h]=y[J]:J];n=i(a)||"";if(!(r=d[n]))r=d[n]=[],k.push(n);b?G=!!E.remove(j(a)):(G=B===j(a),E=E||G);r.push({id:h?y[J]:J,label:f(a)||"",selected:G})}k.sort();!b&&!E&&d[""].unshift({id:"?",label:"",selected:!0});z=0;for(H=k.length;z<H;z++){n=k[z];r=d[n];if(e.length<=z)e.push(v=[u={element:o.clone().attr("label",n),label:r.label}]),c.append(u.element);
else if(v=e[z],u=v[0],u.label!=n)u.element.attr("label",u.label=n);F=null;J=0;for(A=r.length;J<A;J++)if(q=r[J],w=v[J+1]){F=w.element;if(w.label!==q.label)F.text(w.label=q.label);if(w.id!==q.id)F.val(w.id=q.id);w.selected!==q.selected&&F.attr("selected",q.selected)}else(I=m.clone()).val(q.id).attr("selected",q.selected).text(q.label),v.push(w={element:I,label:q.label,id:q.id,checked:q.selected}),F?F.after(I):u.element.append(I),F=I;for(J++;v.length>J;)v.pop().element.remove()}for(;e.length>z;)e.pop()[0].element.remove()}finally{a.$destroy()}})}});
O("ng:include",function(a){var b=this,c=a.attr("src"),d=a.attr("scope")||"",e=a[0].getAttribute("onload")||"";if(a[0]["ng:compiled"])this.descend(!0),this.directives(!0);else return a[0]["ng:compiled"]=!0,s(function(a,g){var h=0,i=[],j,l;this.$watch(c,function(){h++});this.$watch(function(a){a=a.$eval(d);a!==l&&(l=a,h++)});this.$watch(function(){return h},function(h){for(var l=h.$eval(c),k=h.$eval(d);i.length;)i.pop().$destroy();l?a("GET",l,null,function(a,c){g.html(c);k?j=k:i.push(j=h.$new());b.compile(g)(j);
h.$eval(e)},!1,!0):(j=null,g.html(""))})},{$inject:["$xhr.cache"]})});O("ng:switch",function(a){var b=a.attr("on"),c=a.attr("change"),d={},e,f=a.children(),g=f.length,h,i;if(!b)throw new z("Missing 'on' attribute.");for(;g--;)h=n(f[g]),h.remove(),i=h.attr("ng:switch-when"),u(i)?d[i]=this.compile(h):u(h.attr("ng:switch-default"))&&(e=this.compile(h));f=null;a.html("");return function(a){var f=0,g,h;this.$watch(b,function(b,i){a.html("");if(h=d[i]||e)f++,g&&g.$destroy(),g=b.$new(),g.$eval(c)});this.$watch(function(){return f},
function(){a.html("");h&&h(g,function(b){a.append(b)})})}});O("a",function(){this.descend(!0);this.directives(!0);return function(a){var b=(a.attr("ng:bind-attr")||"").indexOf('"href":')!==-1;!b&&!a.attr("name")&&!a.attr("href")&&a.attr("href","");a.attr("href")===""&&!b&&a.bind("click",function(a){a.preventDefault()})}});O("@ng:repeat",function(a,b){b.removeAttr("ng:repeat");b.replaceWith(n("<\!-- ng:repeat: "+a+" --\>"));var c=this.compile(b);return function(b){var e=a.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
f,g,h,i;if(!e)throw z("Expected ng:repeat in form of '_item_ in _collection_' but got '"+a+"'.");f=e[1];g=e[2];e=f.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);if(!e)throw z("'item' in 'item in collection' should be identifier or (key, value) but got '"+keyValue+"'.");h=e[3]||e[1];i=e[2];var j=[],l=[b],k=this;this.$watch(function(a){var b=0,d=j.length,a=a.$eval(g),e=xb(a,!0),f=F.createDocumentFragment(),q=d<e?l[d]:null,p,s;for(s in a)if(a.hasOwnProperty(s))b<d?(p=j[b],p[h]=a[s],i&&(p[i]=s),
p.$position=b==0?"first":b==e-1?"last":"middle",p.$eval()):(p=k.$new(),p[h]=a[s],i&&(p[i]=s),p.$index=b,p.$position=b==0?"first":b==e-1?"last":"middle",j.push(p),c(p,function(a){a.attr("ng:repeat-index",b);f.appendChild(a[0]);p.$digest();l[b+1]=a})),b++;for(q&&q.after(n(f));j.length>b;)j.pop().$destroy(),l.pop().remove()})}});O("@ng:non-bindable",p);O("ng:view",function(a){var b=this;if(a[0]["ng:compiled"])b.descend(!0),b.directives(!0);else return a[0]["ng:compiled"]=!0,ab("$xhr.cache","$route",
function(a,d,e){var f=0;this.$on("$afterRouteChange",function(){f++});this.$watch(function(){return f},function(){var f=d.current&&d.current.template;f?a("GET",f,function(a,c){e.html(c);b.compile(e)(d.current.scope)}):e.html("")})})});O("ng:pluralize",function(a){var b=a.attr("count"),c=a.attr("when"),d=a.attr("offset")||0;return ab("$locale",function(a,f){var g=this,h=g.$eval(c),i={};k(h,function(a,c){i[c]=kb(a.replace(/{}/g,"{{"+b+"-"+d+"}}"))});g.$watch(function(){var c=parseFloat(g.$eval(b));
return isNaN(c)?"":(h[c]||(c=a.pluralCat(c-d)),i[c](g,f,!0))},function(a,b){f.text(b)})})});var Na;Ba("$browser",function(a){Na||(Na=new Gc(x,n(x.document),n(x.document.body),Tc,a),Na.bind());return Na},{$inject:["$log"]});s(w,{compile:zb,scope:$a,copy:C,extend:s,equals:$,forEach:k,injector:Hb,noop:p,bind:M,toJson:Q,fromJson:fa,identity:da,isUndefined:y,isDefined:v,isString:u,isFunction:q,isObject:I,isNumber:oa,isArray:U,version:{full:"0.10.0",major:0,minor:10,dot:0,codeName:"chicken-hands"},isDate:qa,
lowercase:H,uppercase:Ia});Db();Xa(F).ready(function(){var a=tc(F),b=F,c=a.autobind;c&&(b=u(c)?b.getElementById(c):b,b=zb(b)($a()),c=b.$service("$browser"),a.css?c.addCss(a.base_url+a.css):V<8&&c.addJs(a.ie_compat,a.ie_compat_id),b.$apply())})})(window,document);angular.element(document).find("head").append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],.ng-cloak{display:none;}.ng-format-negative{color:red;}.ng-exception{border:2px solid #FF0000;font-family:"Courier New",Courier,monospace;font-size:smaller;white-space:pre;}.ng-validation-error{border:2px solid #FF0000;}#ng-callout{margin:0;padding:0;border:0;outline:0;font-size:13px;font-weight:normal;font-family:Verdana,Arial,Helvetica,sans-serif;vertical-align:baseline;background:transparent;text-decoration:none;}#ng-callout .ng-arrow-left{background-image:url("data:image/gif;base64,R0lGODlhCwAXAKIAAMzMzO/v7/f39////////wAAAAAAAAAAACH5BAUUAAQALAAAAAALABcAAAMrSLoc/AG8FeUUIN+sGebWAnbKSJodqqlsOxJtqYooU9vvk+vcJIcTkg+QAAA7");background-repeat:no-repeat;background-position:left top;position:absolute;z-index:101;left:-12px;height:23px;width:10px;top:-3px;}#ng-callout .ng-arrow-right{background-image:url("data:image/gif;base64,R0lGODlhCwAXAKIAAMzMzO/v7/f39////////wAAAAAAAAAAACH5BAUUAAQALAAAAAALABcAAAMrCLTcoM29yN6k9socs91e5X3EyJloipYrO4ohTMqA0Fn2XVNswJe+H+SXAAA7");background-repeat:no-repeat;background-position:left top;position:absolute;z-index:101;height:23px;width:11px;top:-2px;}#ng-callout{position:absolute;z-index:100;border:2px solid #CCCCCC;background-color:#fff;}#ng-callout .ng-content{padding:10px 10px 10px 10px;color:#333333;}#ng-callout .ng-title{background-color:#CCCCCC;text-align:left;padding-left:8px;padding-bottom:5px;padding-top:2px;font-weight:bold;}.ng-input-indicator-wait{background-image:url("data:image/png;base64,R0lGODlhEAAQAPQAAP///wAAAPDw8IqKiuDg4EZGRnp6egAAAFhYWCQkJKysrL6+vhQUFJycnAQEBDY2NmhoaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAAFdyAgAgIJIeWoAkRCCMdBkKtIHIngyMKsErPBYbADpkSCwhDmQCBethRB6Vj4kFCkQPG4IlWDgrNRIwnO4UKBXDufzQvDMaoSDBgFb886MiQadgNABAokfCwzBA8LCg0Egl8jAggGAA1kBIA1BAYzlyILczULC2UhACH5BAkKAAAALAAAAAAQABAAAAV2ICACAmlAZTmOREEIyUEQjLKKxPHADhEvqxlgcGgkGI1DYSVAIAWMx+lwSKkICJ0QsHi9RgKBwnVTiRQQgwF4I4UFDQQEwi6/3YSGWRRmjhEETAJfIgMFCnAKM0KDV4EEEAQLiF18TAYNXDaSe3x6mjidN1s3IQAh+QQJCgAAACwAAAAAEAAQAAAFeCAgAgLZDGU5jgRECEUiCI+yioSDwDJyLKsXoHFQxBSHAoAAFBhqtMJg8DgQBgfrEsJAEAg4YhZIEiwgKtHiMBgtpg3wbUZXGO7kOb1MUKRFMysCChAoggJCIg0GC2aNe4gqQldfL4l/Ag1AXySJgn5LcoE3QXI3IQAh+QQJCgAAACwAAAAAEAAQAAAFdiAgAgLZNGU5joQhCEjxIssqEo8bC9BRjy9Ag7GILQ4QEoE0gBAEBcOpcBA0DoxSK/e8LRIHn+i1cK0IyKdg0VAoljYIg+GgnRrwVS/8IAkICyosBIQpBAMoKy9dImxPhS+GKkFrkX+TigtLlIyKXUF+NjagNiEAIfkECQoAAAAsAAAAABAAEAAABWwgIAICaRhlOY4EIgjH8R7LKhKHGwsMvb4AAy3WODBIBBKCsYA9TjuhDNDKEVSERezQEL0WrhXucRUQGuik7bFlngzqVW9LMl9XWvLdjFaJtDFqZ1cEZUB0dUgvL3dgP4WJZn4jkomWNpSTIyEAIfkECQoAAAAsAAAAABAAEAAABX4gIAICuSxlOY6CIgiD8RrEKgqGOwxwUrMlAoSwIzAGpJpgoSDAGifDY5kopBYDlEpAQBwevxfBtRIUGi8xwWkDNBCIwmC9Vq0aiQQDQuK+VgQPDXV9hCJjBwcFYU5pLwwHXQcMKSmNLQcIAExlbH8JBwttaX0ABAcNbWVbKyEAIfkECQoAAAAsAAAAABAAEAAABXkgIAICSRBlOY7CIghN8zbEKsKoIjdFzZaEgUBHKChMJtRwcWpAWoWnifm6ESAMhO8lQK0EEAV3rFopIBCEcGwDKAqPh4HUrY4ICHH1dSoTFgcHUiZjBhAJB2AHDykpKAwHAwdzf19KkASIPl9cDgcnDkdtNwiMJCshACH5BAkKAAAALAAAAAAQABAAAAV3ICACAkkQZTmOAiosiyAoxCq+KPxCNVsSMRgBsiClWrLTSWFoIQZHl6pleBh6suxKMIhlvzbAwkBWfFWrBQTxNLq2RG2yhSUkDs2b63AYDAoJXAcFRwADeAkJDX0AQCsEfAQMDAIPBz0rCgcxky0JRWE1AmwpKyEAIfkECQoAAAAsAAAAABAAEAAABXkgIAICKZzkqJ4nQZxLqZKv4NqNLKK2/Q4Ek4lFXChsg5ypJjs1II3gEDUSRInEGYAw6B6zM4JhrDAtEosVkLUtHA7RHaHAGJQEjsODcEg0FBAFVgkQJQ1pAwcDDw8KcFtSInwJAowCCA6RIwqZAgkPNgVpWndjdyohACH5BAkKAAAALAAAAAAQABAAAAV5ICACAimc5KieLEuUKvm2xAKLqDCfC2GaO9eL0LABWTiBYmA06W6kHgvCqEJiAIJiu3gcvgUsscHUERm+kaCxyxa+zRPk0SgJEgfIvbAdIAQLCAYlCj4DBw0IBQsMCjIqBAcPAooCBg9pKgsJLwUFOhCZKyQDA3YqIQAh+QQJCgAAACwAAAAAEAAQAAAFdSAgAgIpnOSonmxbqiThCrJKEHFbo8JxDDOZYFFb+A41E4H4OhkOipXwBElYITDAckFEOBgMQ3arkMkUBdxIUGZpEb7kaQBRlASPg0FQQHAbEEMGDSVEAA1QBhAED1E0NgwFAooCDWljaQIQCE5qMHcNhCkjIQAh+QQJCgAAACwAAAAAEAAQAAAFeSAgAgIpnOSoLgxxvqgKLEcCC65KEAByKK8cSpA4DAiHQ/DkKhGKh4ZCtCyZGo6F6iYYPAqFgYy02xkSaLEMV34tELyRYNEsCQyHlvWkGCzsPgMCEAY7Cg04Uk48LAsDhRA8MVQPEF0GAgqYYwSRlycNcWskCkApIyEAOwAAAAAAAAAAAA==");background-position:right;background-repeat:no-repeat;}</style>');
\ No newline at end of file
/**
* Copyright (c) 2010 Zef Hemel <zef@zef.me>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
if (typeof exports !== 'undefined') {
exports.createPersistence = function() {
return initPersistence({})
}
var singleton;
exports.__defineGetter__("persistence", function () {
if (!singleton)
singleton = exports.createPersistence();
return singleton;
});
}
else {
window = window || {};
window.persistence = initPersistence(window.persistence || {});
}
function initPersistence(persistence) {
if (persistence.isImmutable) // already initialized
return persistence;
/**
* Check for immutable fields
*/
persistence.isImmutable = function(fieldName) {
return (fieldName == "id");
};
/**
* Default implementation for entity-property
*/
persistence.defineProp = function(scope, field, setterCallback, getterCallback) {
scope.__defineSetter__(field, function (value) {
setterCallback(value);
});
scope.__defineGetter__(field, function () {
return getterCallback();
});
};
/**
* Default implementation for entity-property setter
*/
persistence.set = function(scope, fieldName, value) {
if (persistence.isImmutable(fieldName)) throw new Error("immutable field: "+fieldName);
scope[fieldName] = value;
};
/**
* Default implementation for entity-property getter
*/
persistence.get = function(arg1, arg2) {
return (arguments.length == 1) ? arg1 : arg1[arg2];
};
(function () {
var entityMeta = {};
var entityClassCache = {};
persistence.getEntityMeta = function() { return entityMeta; }
// Per-session data
persistence.trackedObjects = {};
persistence.objectsToRemove = {};
persistence.objectsRemoved = []; // {id: ..., type: ...}
persistence.globalPropertyListeners = {}; // EntityType__prop -> QueryColleciton obj
persistence.queryCollectionCache = {}; // entityName -> uniqueString -> QueryCollection
persistence.getObjectsToRemove = function() { return this.objectsToRemove; };
persistence.getTrackedObjects = function() { return this.trackedObjects; };
// Public Extension hooks
persistence.entityDecoratorHooks = [];
persistence.flushHooks = [];
persistence.schemaSyncHooks = [];
// Enable debugging (display queries using console.log etc)
persistence.debug = true;
persistence.subscribeToGlobalPropertyListener = function(coll, entityName, property) {
var key = entityName + '__' + property;
if(key in this.globalPropertyListeners) {
var listeners = this.globalPropertyListeners[key];
for(var i = 0; i < listeners.length; i++) {
if(listeners[i] === coll) {
return;
}
}
this.globalPropertyListeners[key].push(coll);
} else {
this.globalPropertyListeners[key] = [coll];
}
}
persistence.unsubscribeFromGlobalPropertyListener = function(coll, entityName, property) {
var key = entityName + '__' + property;
var listeners = this.globalPropertyListeners[key];
for(var i = 0; i < listeners.length; i++) {
if(listeners[i] === coll) {
listeners.splice(i, 1);
return;
}
}
}
persistence.propertyChanged = function(obj, property, oldValue, newValue) {
if(!this.trackedObjects[obj.id]) return; // not yet added, ignore for now
var entityName = obj._type;
var key = entityName + '__' + property;
if(key in this.globalPropertyListeners) {
var listeners = this.globalPropertyListeners[key];
for(var i = 0; i < listeners.length; i++) {
var coll = listeners[i];
var dummyObj = obj._data;
dummyObj[property] = oldValue;
var matchedBefore = coll._filter.match(dummyObj);
dummyObj[property] = newValue;
var matchedAfter = coll._filter.match(dummyObj);
if(matchedBefore != matchedAfter) {
coll.triggerEvent('change', coll, obj);
}
}
}
}
persistence.objectRemoved = function(obj) {
var entityName = obj._type;
if(this.queryCollectionCache[entityName]) {
var colls = this.queryCollectionCache[entityName];
for(var key in colls) {
if(colls.hasOwnProperty(key)) {
var coll = colls[key];
if(coll._filter.match(obj)) { // matched the filter -> was part of collection
coll.triggerEvent('change', coll, obj);
}
}
}
}
}
/**
* Retrieves metadata about entity, mostly for internal use
*/
function getMeta(entityName) {
return entityMeta[entityName];
}
persistence.getMeta = getMeta;
/**
* A database session
*/
function Session(conn) {
this.trackedObjects = {};
this.objectsToRemove = {};
this.objectsRemoved = [];
this.globalPropertyListeners = {}; // EntityType__prop -> QueryColleciton obj
this.queryCollectionCache = {}; // entityName -> uniqueString -> QueryCollection
this.conn = conn;
}
Session.prototype = persistence; // Inherit everything from the root persistence object
persistence.Session = Session;
/**
* Define an entity
*
* @param entityName
* the name of the entity (also the table name in the database)
* @param fields
* an object with property names as keys and SQLite types as
* values, e.g. {name: "TEXT", age: "INT"}
* @return the entity's constructor
*/
persistence.define = function (entityName, fields) {
if (entityMeta[entityName]) { // Already defined, ignore
return getEntity(entityName);
}
var meta = {
name: entityName,
fields: fields,
isMixin: false,
indexes: [],
hasMany: {},
hasOne: {}
};
entityMeta[entityName] = meta;
return getEntity(entityName);
};
/**
* Checks whether an entity exists
*
* @param entityName
* the name of the entity (also the table name in the database)
* @return `true` if the entity exists, otherwise `false`
*/
persistence.isDefined = function (entityName) {
return !!entityMeta[entityName];
}
/**
* Define a mixin
*
* @param mixinName
* the name of the mixin
* @param fields
* an object with property names as keys and SQLite types as
* values, e.g. {name: "TEXT", age: "INT"}
* @return the entity's constructor
*/
persistence.defineMixin = function (mixinName, fields) {
var Entity = this.define(mixinName, fields);
Entity.meta.isMixin = true;
return Entity;
};
persistence.isTransaction = function(obj) {
return !obj || (obj && obj.executeSql);
};
persistence.isSession = function(obj) {
return !obj || (obj && obj.schemaSync);
};
/**
* Adds the object to tracked entities to be persisted
*
* @param obj
* the object to be tracked
*/
persistence.add = function (obj) {
if(!obj) return;
if (!this.trackedObjects[obj.id]) {
this.trackedObjects[obj.id] = obj;
if(obj._new) {
for(var p in obj._data) {
if(obj._data.hasOwnProperty(p)) {
this.propertyChanged(obj, p, undefined, obj._data[p]);
}
}
}
}
return this;
};
/**
* Marks the object to be removed (on next flush)
* @param obj object to be removed
*/
persistence.remove = function(obj) {
if (!this.objectsToRemove[obj.id]) {
this.objectsToRemove[obj.id] = obj;
}
this.objectsRemoved.push({id: obj.id, entity: obj._type});
this.objectRemoved(obj);
return this;
};
/**
* Clean the persistence context of cached entities and such.
*/
persistence.clean = function () {
this.trackedObjects = {};
this.objectsToRemove = {};
this.objectsRemoved = [];
this.globalPropertyListeners = {};
this.queryCollectionCache = {};
};
/**
* asynchronous sequential version of Array.prototype.forEach
* @param array the array to iterate over
* @param fn the function to apply to each item in the array, function
* has two argument, the first is the item value, the second a
* callback function
* @param callback the function to call when the forEach has ended
*/
persistence.asyncForEach = function(array, fn, callback) {
array = array.slice(0); // Just to be sure
function processOne() {
var item = array.pop();
fn(item, function(result, err) {
if(array.length > 0) {
processOne();
} else {
callback(result, err);
}
});
}
if(array.length > 0) {
processOne();
} else {
callback();
}
};
/**
* asynchronous parallel version of Array.prototype.forEach
* @param array the array to iterate over
* @param fn the function to apply to each item in the array, function
* has two argument, the first is the item value, the second a
* callback function
* @param callback the function to call when the forEach has ended
*/
persistence.asyncParForEach = function(array, fn, callback) {
var completed = 0;
var arLength = array.length;
if(arLength === 0) {
callback();
}
for(var i = 0; i < arLength; i++) {
fn(array[i], function(result, err) {
completed++;
if(completed === arLength) {
callback(result, err);
}
});
}
};
/**
* Retrieves or creates an entity constructor function for a given
* entity name
* @return the entity constructor function to be invoked with `new fn()`
*/
function getEntity(entityName) {
if (entityClassCache[entityName]) {
return entityClassCache[entityName];
}
var meta = entityMeta[entityName];
/**
* @constructor
*/
function Entity (session, obj, noEvents) {
var args = argspec.getArgs(arguments, [
{ name: "session", optional: true, check: persistence.isSession, defaultValue: persistence },
{ name: "obj", optional: true, check: function(obj) { return obj; }, defaultValue: {} }
]);
if (meta.isMixin)
throw new Error("Cannot instantiate mixin");
session = args.session;
obj = args.obj;
var that = this;
this.id = obj.id || persistence.createUUID();
this._new = true;
this._type = entityName;
this._dirtyProperties = {};
this._data = {};
this._data_obj = {}; // references to objects
this._session = session || persistence;
this.subscribers = {}; // observable
for ( var field in meta.fields) {
(function () {
if (meta.fields.hasOwnProperty(field)) {
var f = field; // Javascript scopes/closures SUCK
persistence.defineProp(that, f, function(val) {
// setterCallback
var oldValue = that._data[f];
if(oldValue !== val || (oldValue && val && oldValue.getTime && val.getTime)) { // Don't mark properties as dirty and trigger events unnecessarily
that._data[f] = val;
that._dirtyProperties[f] = oldValue;
that.triggerEvent('set', that, f, val);
that.triggerEvent('change', that, f, val);
session.propertyChanged(that, f, oldValue, val);
}
}, function() {
// getterCallback
return that._data[f];
});
that._data[field] = defaultValue(meta.fields[field]);
}
}());
}
for ( var it in meta.hasOne) {
if (meta.hasOne.hasOwnProperty(it)) {
(function () {
var ref = it;
var mixinClass = meta.hasOne[it].type.meta.isMixin ? ref + '_class' : null;
persistence.defineProp(that, ref, function(val) {
// setterCallback
var oldValue = that._data[ref];
var oldValueObj = that._data_obj[ref] || session.trackedObjects[that._data[ref]];
if (val == null) {
that._data[ref] = null;
that._data_obj[ref] = undefined;
if (mixinClass)
that[mixinClass] = '';
} else if (val.id) {
that._data[ref] = val.id;
that._data_obj[ref] = val;
if (mixinClass)
that[mixinClass] = val._type;
session.add(val);
session.add(that);
} else { // let's assume it's an id
that._data[ref] = val;
}
that._dirtyProperties[ref] = oldValue;
that.triggerEvent('set', that, ref, val);
that.triggerEvent('change', that, ref, val);
// Inverse
if(meta.hasOne[ref].inverseProperty) {
var newVal = that[ref];
if(newVal) {
var inverse = newVal[meta.hasOne[ref].inverseProperty];
if(inverse.list && inverse._filter) {
inverse.triggerEvent('change', that, ref, val);
}
}
if(oldValueObj) {
console.log("OldValue", oldValueObj);
var inverse = oldValueObj[meta.hasOne[ref].inverseProperty];
if(inverse.list && inverse._filter) {
inverse.triggerEvent('change', that, ref, val);
}
}
}
}, function() {
// getterCallback
if (!that._data[ref]) {
return null;
} else if(that._data_obj[ref] !== undefined) {
return that._data_obj[ref];
} else if(that._data[ref] && session.trackedObjects[that._data[ref]]) {
that._data_obj[ref] = session.trackedObjects[that._data[ref]];
return that._data_obj[ref];
} else {
throw new Error("Property '" + ref + "' with id: " + that._data[ref] + " not fetched, either prefetch it or fetch it manually.");
}
});
}());
}
}
for ( var it in meta.hasMany) {
if (meta.hasMany.hasOwnProperty(it)) {
(function () {
var coll = it;
if (meta.hasMany[coll].manyToMany) {
persistence.defineProp(that, coll, function(val) {
// setterCallback
if(val && val._items) {
// Local query collection, just add each item
// TODO: this is technically not correct, should clear out existing items too
var items = val._items;
for(var i = 0; i < items.length; i++) {
persistence.get(that, coll).add(items[i]);
}
} else {
throw new Error("Not yet supported.");
}
}, function() {
// getterCallback
if (that._data[coll]) {
return that._data[coll];
} else {
var rel = meta.hasMany[coll];
var inverseMeta = rel.type.meta;
var inv = inverseMeta.hasMany[rel.inverseProperty];
var direct = rel.mixin ? rel.mixin.meta.name : meta.name;
var inverse = inv.mixin ? inv.mixin.meta.name : inverseMeta.name;
var queryColl = new persistence.ManyToManyDbQueryCollection(session, inverseMeta.name);
queryColl.initManyToMany(that, coll);
queryColl._manyToManyFetch = {
table: rel.tableName,
prop: direct + '_' + coll,
inverseProp: inverse + '_' + rel.inverseProperty,
id: that.id
};
that._data[coll] = queryColl;
return session.uniqueQueryCollection(queryColl);
}
});
} else { // one to many
persistence.defineProp(that, coll, function(val) {
// setterCallback
if(val && val._items) {
// Local query collection, just add each item
// TODO: this is technically not correct, should clear out existing items too
var items = val._items;
for(var i = 0; i < items.length; i++) {
persistence.get(that, coll).add(items[i]);
}
} else {
throw new Error("Not yet supported.");
}
}, function() {
// getterCallback
if (that._data[coll]) {
return that._data[coll];
} else {
var queryColl = session.uniqueQueryCollection(new persistence.DbQueryCollection(session, meta.hasMany[coll].type.meta.name).filter(meta.hasMany[coll].inverseProperty, '=', that));
that._data[coll] = queryColl;
return queryColl;
}
});
}
}());
}
}
if(this.initialize) {
this.initialize();
}
for ( var f in obj) {
if (obj.hasOwnProperty(f)) {
if(f !== 'id') {
persistence.set(that, f, obj[f]);
}
}
}
} // Entity
Entity.prototype = new Observable();
Entity.meta = meta;
Entity.prototype.equals = function(other) {
return this.id == other.id;
};
Entity.prototype.toJSON = function() {
var json = {id: this.id};
for(var p in this._data) {
if(this._data.hasOwnProperty(p)) {
if (typeof this._data[p] == "object" && this._data[p] != null) {
if (this._data[p].toJSON != undefined) {
json[p] = this._data[p].toJSON();
}
} else {
json[p] = this._data[p];
}
}
}
return json;
};
/**
* Select a subset of data as a JSON structure (Javascript object)
*
* A property specification is passed that selects the
* properties to be part of the resulting JSON object. Examples:
* ['id', 'name'] -> Will return an object with the id and name property of this entity
* ['*'] -> Will return an object with all the properties of this entity, not recursive
* ['project.name'] -> will return an object with a project property which has a name
* property containing the project name (hasOne relationship)
* ['project.[id, name]'] -> will return an object with a project property which has an
* id and name property containing the project name
* (hasOne relationship)
* ['tags.name'] -> will return an object with an array `tags` property containing
* objects each with a single property: name
*
* @param tx database transaction to use, leave out to start a new one
* @param props a property specification
* @param callback(result)
*/
Entity.prototype.selectJSON = function(tx, props, callback) {
var that = this;
var args = argspec.getArgs(arguments, [
{ name: "tx", optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: "props", optional: false },
{ name: "callback", optional: false }
]);
tx = args.tx;
props = args.props;
callback = args.callback;
if(!tx) {
this._session.transaction(function(tx) {
that.selectJSON(tx, props, callback);
});
return;
}
var includeProperties = {};
props.forEach(function(prop) {
var current = includeProperties;
var parts = prop.split('.');
for(var i = 0; i < parts.length; i++) {
var part = parts[i];
if(i === parts.length-1) {
if(part === '*') {
current.id = true;
for(var p in meta.fields) {
if(meta.fields.hasOwnProperty(p)) {
current[p] = true;
}
}
for(var p in meta.hasOne) {
if(meta.hasOne.hasOwnProperty(p)) {
current[p] = true;
}
}
for(var p in meta.hasMany) {
if(meta.hasMany.hasOwnProperty(p)) {
current[p] = true;
}
}
} else if(part[0] === '[') {
part = part.substring(1, part.length-1);
var propList = part.split(/,\s*/);
propList.forEach(function(prop) {
current[prop] = true;
});
} else {
current[part] = true;
}
} else {
current[part] = current[part] || {};
current = current[part];
}
}
});
buildJSON(this, tx, includeProperties, callback);
};
function buildJSON(that, tx, includeProperties, callback) {
var session = that._session;
var properties = [];
var meta = getMeta(that._type);
var fieldSpec = meta.fields;
for(var p in includeProperties) {
if(includeProperties.hasOwnProperty(p)) {
properties.push(p);
}
}
var cheapProperties = [];
var expensiveProperties = [];
properties.forEach(function(p) {
if(includeProperties[p] === true && !meta.hasMany[p]) { // simple, loaded field
cheapProperties.push(p);
} else {
expensiveProperties.push(p);
}
});
var itemData = that._data;
var item = {};
cheapProperties.forEach(function(p) {
if(p === 'id') {
item.id = that.id;
} else if(meta.hasOne[p]) {
item[p] = itemData[p] ? {id: itemData[p]} : null;
} else {
item[p] = persistence.entityValToJson(itemData[p], fieldSpec[p]);
}
});
properties = expensiveProperties.slice();
persistence.asyncForEach(properties, function(p, callback) {
if(meta.hasOne[p]) {
that.fetch(tx, p, function(obj) {
if(obj) {
buildJSON(obj, tx, includeProperties[p], function(result) {
item[p] = result;
callback();
});
} else {
item[p] = null;
callback();
}
});
} else if(meta.hasMany[p]) {
persistence.get(that, p).list(function(objs) {
item[p] = [];
persistence.asyncForEach(objs, function(obj, callback) {
var obj = objs.pop();
if(includeProperties[p] === true) {
item[p].push({id: obj.id});
callback();
} else {
buildJSON(obj, tx, includeProperties[p], function(result) {
item[p].push(result);
callback();
});
}
}, callback);
});
}
}, function() {
callback(item);
});
}; // End of buildJson
Entity.prototype.fetch = function(tx, rel, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'rel', optional: false, check: argspec.hasType('string') },
{ name: 'callback', optional: false, check: argspec.isCallback() }
]);
tx = args.tx;
rel = args.rel;
callback = args.callback;
var that = this;
var session = this._session;
if(!tx) {
session.transaction(function(tx) {
that.fetch(tx, rel, callback);
});
return;
}
if(!this._data[rel]) { // null
if(callback) {
callback(null);
}
} else if(this._data_obj[rel]) { // already loaded
if(callback) {
callback(this._data_obj[rel]);
}
} else {
var type = meta.hasOne[rel].type;
if (type.meta.isMixin) {
type = getEntity(this._data[rel + '_class']);
}
type.load(session, tx, this._data[rel], function(obj) {
that._data_obj[rel] = obj;
if(callback) {
callback(obj);
}
});
}
};
/**
* Currently this is only required when changing JSON properties
*/
Entity.prototype.markDirty = function(prop) {
this._dirtyProperties[prop] = true;
};
/**
* Returns a QueryCollection implementation matching all instances
* of this entity in the database
*/
Entity.all = function(session) {
var args = argspec.getArgs(arguments, [
{ name: 'session', optional: true, check: persistence.isSession, defaultValue: persistence }
]);
session = args.session;
return session.uniqueQueryCollection(new AllDbQueryCollection(session, entityName));
};
Entity.fromSelectJSON = function(session, tx, jsonObj, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'session', optional: true, check: persistence.isSession, defaultValue: persistence },
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'jsonObj', optional: false },
{ name: 'callback', optional: false, check: argspec.isCallback() }
]);
session = args.session;
tx = args.tx;
jsonObj = args.jsonObj;
callback = args.callback;
if(!tx) {
session.transaction(function(tx) {
Entity.fromSelectJSON(session, tx, jsonObj, callback);
});
return;
}
if(typeof jsonObj === 'string') {
jsonObj = JSON.parse(jsonObj);
}
if(!jsonObj) {
callback(null);
return;
}
function loadedObj(obj) {
if(!obj) {
obj = new Entity(session);
if(jsonObj.id) {
obj.id = jsonObj.id;
}
}
session.add(obj);
var expensiveProperties = [];
for(var p in jsonObj) {
if(jsonObj.hasOwnProperty(p)) {
if(p === 'id') {
continue;
} else if(meta.fields[p]) { // regular field
persistence.set(obj, p, persistence.jsonToEntityVal(jsonObj[p], meta.fields[p]));
} else if(meta.hasOne[p] || meta.hasMany[p]){
expensiveProperties.push(p);
}
}
}
persistence.asyncForEach(expensiveProperties, function(p, callback) {
if(meta.hasOne[p]) {
meta.hasOne[p].type.fromSelectJSON(session, tx, jsonObj[p], function(result) {
persistence.set(obj, p, result);
callback();
});
} else if(meta.hasMany[p]) {
var coll = persistence.get(obj, p);
var ar = jsonObj[p].slice(0);
var PropertyEntity = meta.hasMany[p].type;
// get all current items
coll.list(tx, function(currentItems) {
persistence.asyncForEach(ar, function(item, callback) {
PropertyEntity.fromSelectJSON(session, tx, item, function(result) {
// Check if not already in collection
for(var i = 0; i < currentItems.length; i++) {
if(currentItems[i].id === result.id) {
callback();
return;
}
}
coll.add(result);
callback();
});
}, function() {
callback();
});
});
}
}, function() {
callback(obj);
});
}
if(jsonObj.id) {
Entity.load(session, tx, jsonObj.id, loadedObj);
} else {
loadedObj(new Entity(session));
}
};
Entity.load = function(session, tx, id, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'session', optional: true, check: persistence.isSession, defaultValue: persistence },
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'id', optional: false, check: argspec.hasType('string') },
{ name: 'callback', optional: true, check: argspec.isCallback(), defaultValue: function(){} }
]);
Entity.findBy(args.session, args.tx, "id", args.id, args.callback);
};
Entity.findBy = function(session, tx, property, value, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'session', optional: true, check: persistence.isSession, defaultValue: persistence },
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'property', optional: false, check: argspec.hasType('string') },
{ name: 'value', optional: false },
{ name: 'callback', optional: true, check: argspec.isCallback(), defaultValue: function(){} }
]);
session = args.session;
tx = args.tx;
property = args.property;
value = args.value;
callback = args.callback;
if(property === 'id' && value in session.trackedObjects) {
callback(session.trackedObjects[value]);
return;
}
if(!tx) {
session.transaction(function(tx) {
Entity.findBy(session, tx, property, value, callback);
});
return;
}
Entity.all(session).filter(property, "=", value).one(tx, function(obj) {
callback(obj);
});
}
Entity.index = function(cols,options) {
var opts = options || {};
if (typeof cols=="string") {
cols = [cols];
}
opts.columns = cols;
meta.indexes.push(opts);
};
/**
* Declares a one-to-many or many-to-many relationship to another entity
* Whether 1:N or N:M is chosed depends on the inverse declaration
* @param collName the name of the collection (becomes a property of
* Entity instances
* @param otherEntity the constructor function of the entity to define
* the relation to
* @param inverseRel the name of the inverse property (to be) defined on otherEntity
*/
Entity.hasMany = function (collName, otherEntity, invRel) {
var otherMeta = otherEntity.meta;
if (otherMeta.hasMany[invRel]) {
// other side has declared it as a one-to-many relation too -> it's in
// fact many-to-many
var tableName = meta.name + "_" + collName + "_" + otherMeta.name;
var inverseTableName = otherMeta.name + '_' + invRel + '_' + meta.name;
if (tableName > inverseTableName) {
// Some arbitrary way to deterministically decide which table to generate
tableName = inverseTableName;
}
meta.hasMany[collName] = {
type: otherEntity,
inverseProperty: invRel,
manyToMany: true,
tableName: tableName
};
otherMeta.hasMany[invRel] = {
type: Entity,
inverseProperty: collName,
manyToMany: true,
tableName: tableName
};
delete meta.hasOne[collName];
delete meta.fields[collName + "_class"]; // in case it existed
} else {
meta.hasMany[collName] = {
type: otherEntity,
inverseProperty: invRel
};
otherMeta.hasOne[invRel] = {
type: Entity,
inverseProperty: collName
};
if (meta.isMixin)
otherMeta.fields[invRel + "_class"] = persistence.typeMapper ? persistence.typeMapper.classNameType : "TEXT";
}
}
Entity.hasOne = function (refName, otherEntity, inverseProperty) {
meta.hasOne[refName] = {
type: otherEntity,
inverseProperty: inverseProperty
};
if (otherEntity.meta.isMixin)
meta.fields[refName + "_class"] = persistence.typeMapper ? persistence.typeMapper.classNameType : "TEXT";
};
Entity.is = function(mixin){
var mixinMeta = mixin.meta;
if (!mixinMeta.isMixin)
throw new Error("not a mixin: " + mixin);
mixin.meta.mixedIns = mixin.meta.mixedIns || [];
mixin.meta.mixedIns.push(meta);
for (var field in mixinMeta.fields) {
if (mixinMeta.fields.hasOwnProperty(field))
meta.fields[field] = mixinMeta.fields[field];
}
for (var it in mixinMeta.hasOne) {
if (mixinMeta.hasOne.hasOwnProperty(it))
meta.hasOne[it] = mixinMeta.hasOne[it];
}
for (var it in mixinMeta.hasMany) {
if (mixinMeta.hasMany.hasOwnProperty(it)) {
mixinMeta.hasMany[it].mixin = mixin;
meta.hasMany[it] = mixinMeta.hasMany[it];
}
}
}
// Allow decorator functions to add more stuff
var fns = persistence.entityDecoratorHooks;
for(var i = 0; i < fns.length; i++) {
fns[i](Entity);
}
entityClassCache[entityName] = Entity;
return Entity;
}
persistence.jsonToEntityVal = function(value, type) {
if(type) {
switch(type) {
case 'DATE':
if(typeof value === 'number') {
return new Date(value * 1000);
} else {
return null;
}
break;
default:
return value;
}
} else {
return value;
}
};
persistence.entityValToJson = function(value, type) {
if(type) {
switch(type) {
case 'DATE':
if(value) {
value = new Date(value);
return Math.round(value.getTime() / 1000);
} else {
return null;
}
break;
default:
return value;
}
} else {
return value;
}
};
/**
* Dumps the entire database into an object (that can be serialized to JSON for instance)
* @param tx transaction to use, use `null` to start a new one
* @param entities a list of entity constructor functions to serialize, use `null` for all
* @param callback (object) the callback function called with the results.
*/
persistence.dump = function(tx, entities, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'entities', optional: true, check: function(obj) { return !obj || (obj && obj.length && !obj.apply); }, defaultValue: null },
{ name: 'callback', optional: false, check: argspec.isCallback(), defaultValue: function(){} }
]);
tx = args.tx;
entities = args.entities;
callback = args.callback;
if(!entities) { // Default: all entity types
entities = [];
for(var e in entityClassCache) {
if(entityClassCache.hasOwnProperty(e)) {
entities.push(entityClassCache[e]);
}
}
}
var result = {};
persistence.asyncParForEach(entities, function(Entity, callback) {
Entity.all().list(tx, function(all) {
var items = [];
persistence.asyncParForEach(all, function(e, callback) {
var rec = {};
var fields = Entity.meta.fields;
for(var f in fields) {
if(fields.hasOwnProperty(f)) {
rec[f] = persistence.entityValToJson(e._data[f], fields[f]);
}
}
var refs = Entity.meta.hasOne;
for(var r in refs) {
if(refs.hasOwnProperty(r)) {
rec[r] = e._data[r];
}
}
var colls = Entity.meta.hasMany;
var collArray = [];
for(var coll in colls) {
if(colls.hasOwnProperty(coll)) {
collArray.push(coll);
}
}
persistence.asyncParForEach(collArray, function(collP, callback) {
var coll = persistence.get(e, collP);
coll.list(tx, function(results) {
rec[collP] = results.map(function(r) { return r.id; });
callback();
});
}, function() {
rec.id = e.id;
items.push(rec);
callback();
});
}, function() {
result[Entity.meta.name] = items;
callback();
});
});
}, function() {
callback(result);
});
};
/**
* Loads a set of entities from a dump object
* @param tx transaction to use, use `null` to start a new one
* @param dump the dump object
* @param callback the callback function called when done.
*/
persistence.load = function(tx, dump, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'dump', optional: false },
{ name: 'callback', optional: true, check: argspec.isCallback(), defaultValue: function(){} }
]);
tx = args.tx;
dump = args.dump;
callback = args.callback;
var finishedCount = 0;
var collItemsToAdd = [];
var session = this;
for(var entityName in dump) {
if(dump.hasOwnProperty(entityName)) {
var Entity = getEntity(entityName);
var fields = Entity.meta.fields;
var instances = dump[entityName];
for(var i = 0; i < instances.length; i++) {
var instance = instances[i];
var ent = new Entity();
ent.id = instance.id;
for(var p in instance) {
if(instance.hasOwnProperty(p)) {
if (persistence.isImmutable(p)) {
ent[p] = instance[p];
} else if(Entity.meta.hasMany[p]) { // collection
var many = Entity.meta.hasMany[p];
if(many.manyToMany && Entity.meta.name < many.type.meta.name) { // Arbitrary way to avoid double adding
continue;
}
var coll = persistence.get(ent, p);
if(instance[p].length > 0) {
instance[p].forEach(function(it) {
collItemsToAdd.push({Entity: Entity, coll: coll, id: it});
});
}
} else {
persistence.set(ent, p, persistence.jsonToEntityVal(instance[p], fields[p]));
}
}
}
this.add(ent);
}
}
}
session.flush(tx, function() {
persistence.asyncForEach(collItemsToAdd, function(collItem, callback) {
collItem.Entity.load(session, tx, collItem.id, function(obj) {
collItem.coll.add(obj);
callback();
});
}, function() {
session.flush(tx, callback);
});
});
};
/**
* Dumps the entire database to a JSON string
* @param tx transaction to use, use `null` to start a new one
* @param entities a list of entity constructor functions to serialize, use `null` for all
* @param callback (jsonDump) the callback function called with the results.
*/
persistence.dumpToJson = function(tx, entities, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'entities', optional: true, check: function(obj) { return obj && obj.length && !obj.apply; }, defaultValue: null },
{ name: 'callback', optional: false, check: argspec.isCallback(), defaultValue: function(){} }
]);
tx = args.tx;
entities = args.entities;
callback = args.callback;
this.dump(tx, entities, function(obj) {
callback(JSON.stringify(obj));
});
};
/**
* Loads data from a JSON string (as dumped by `dumpToJson`)
* @param tx transaction to use, use `null` to start a new one
* @param jsonDump JSON string
* @param callback the callback function called when done.
*/
persistence.loadFromJson = function(tx, jsonDump, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'jsonDump', optional: false },
{ name: 'callback', optional: true, check: argspec.isCallback(), defaultValue: function(){} }
]);
tx = args.tx;
jsonDump = args.jsonDump;
callback = args.callback;
this.load(tx, JSON.parse(jsonDump), callback);
};
/**
* Generates a UUID according to http://www.ietf.org/rfc/rfc4122.txt
*/
function createUUID () {
if(persistence.typeMapper && persistence.typeMapper.newUuid) {
return persistence.typeMapper.newUuid();
}
var s = [];
var hexDigits = "0123456789ABCDEF";
for ( var i = 0; i < 32; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[12] = "4";
s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1);
var uuid = s.join("");
return uuid;
}
persistence.createUUID = createUUID;
function defaultValue(type) {
if(persistence.typeMapper && persistence.typeMapper.defaultValue) {
return persistence.typeMapper.defaultValue(type);
}
switch(type) {
case "TEXT": return "";
case "BOOL": return false;
default:
if(type.indexOf("INT") !== -1) {
return 0;
} else if(type.indexOf("CHAR") !== -1) {
return "";
} else {
return null;
}
}
}
function arrayContains(ar, item) {
var l = ar.length;
for(var i = 0; i < l; i++) {
var el = ar[i];
if(el.equals && el.equals(item)) {
return true;
} else if(el === item) {
return true;
}
}
return false;
}
function arrayRemove(ar, item) {
var l = ar.length;
for(var i = 0; i < l; i++) {
var el = ar[i];
if(el.equals && el.equals(item)) {
ar.splice(i, 1);
} else if(el === item) {
ar.splice(i, 1);
}
}
}
////////////////// QUERY COLLECTIONS \\\\\\\\\\\\\\\\\\\\\\\
function Subscription(obj, eventType, fn) {
this.obj = obj;
this.eventType = eventType;
this.fn = fn;
}
Subscription.prototype.unsubscribe = function() {
this.obj.removeEventListener(this.eventType, this.fn);
};
/**
* Simple observable function constructor
* @constructor
*/
function Observable() {
this.subscribers = {};
}
Observable.prototype.addEventListener = function (eventType, fn) {
if (!this.subscribers[eventType]) {
this.subscribers[eventType] = [];
}
this.subscribers[eventType].push(fn);
return new Subscription(this, eventType, fn);
};
Observable.prototype.removeEventListener = function(eventType, fn) {
var subscribers = this.subscribers[eventType];
for ( var i = 0; i < subscribers.length; i++) {
if(subscribers[i] == fn) {
this.subscribers[eventType].splice(i, 1);
return true;
}
}
return false;
};
Observable.prototype.triggerEvent = function (eventType) {
if (!this.subscribers[eventType]) { // No subscribers to this event type
return;
}
var subscribers = this.subscribers[eventType].slice(0);
for(var i = 0; i < subscribers.length; i++) {
subscribers[i].apply(null, arguments);
}
};
/*
* Each filter has 4 methods:
* - sql(prefix, values) -- returns a SQL representation of this filter,
* possibly pushing additional query arguments to `values` if ?'s are used
* in the query
* - match(o) -- returns whether the filter matches the object o.
* - makeFit(o) -- attempts to adapt the object o in such a way that it matches
* this filter.
* - makeNotFit(o) -- the oppositive of makeFit, makes the object o NOT match
* this filter
*/
/**
* Default filter that does not filter on anything
* currently it generates a 1=1 SQL query, which is kind of ugly
*/
function NullFilter () {
}
NullFilter.prototype.match = function (o) {
return true;
};
NullFilter.prototype.makeFit = function(o) {
};
NullFilter.prototype.makeNotFit = function(o) {
};
NullFilter.prototype.toUniqueString = function() {
return "NULL";
};
NullFilter.prototype.subscribeGlobally = function() { };
NullFilter.prototype.unsubscribeGlobally = function() { };
/**
* Filter that makes sure that both its left and right filter match
* @param left left-hand filter object
* @param right right-hand filter object
*/
function AndFilter (left, right) {
this.left = left;
this.right = right;
}
AndFilter.prototype.match = function (o) {
return this.left.match(o) && this.right.match(o);
};
AndFilter.prototype.makeFit = function(o) {
this.left.makeFit(o);
this.right.makeFit(o);
};
AndFilter.prototype.makeNotFit = function(o) {
this.left.makeNotFit(o);
this.right.makeNotFit(o);
};
AndFilter.prototype.toUniqueString = function() {
return this.left.toUniqueString() + " AND " + this.right.toUniqueString();
};
AndFilter.prototype.subscribeGlobally = function(coll, entityName) {
this.left.subscribeGlobally(coll, entityName);
this.right.subscribeGlobally(coll, entityName);
};
AndFilter.prototype.unsubscribeGlobally = function(coll, entityName) {
this.left.unsubscribeGlobally(coll, entityName);
this.right.unsubscribeGlobally(coll, entityName);
};
/**
* Filter that makes sure that either its left and right filter match
* @param left left-hand filter object
* @param right right-hand filter object
*/
function OrFilter (left, right) {
this.left = left;
this.right = right;
}
OrFilter.prototype.match = function (o) {
return this.left.match(o) || this.right.match(o);
};
OrFilter.prototype.makeFit = function(o) {
this.left.makeFit(o);
this.right.makeFit(o);
};
OrFilter.prototype.makeNotFit = function(o) {
this.left.makeNotFit(o);
this.right.makeNotFit(o);
};
OrFilter.prototype.toUniqueString = function() {
return this.left.toUniqueString() + " OR " + this.right.toUniqueString();
};
OrFilter.prototype.subscribeGlobally = function(coll, entityName) {
this.left.subscribeGlobally(coll, entityName);
this.right.subscribeGlobally(coll, entityName);
};
OrFilter.prototype.unsubscribeGlobally = function(coll, entityName) {
this.left.unsubscribeGlobally(coll, entityName);
this.right.unsubscribeGlobally(coll, entityName);
};
/**
* Filter that checks whether a certain property matches some value, based on an
* operator. Supported operators are '=', '!=', '<', '<=', '>' and '>='.
* @param property the property name
* @param operator the operator to compare with
* @param value the literal value to compare to
*/
function PropertyFilter (property, operator, value) {
this.property = property;
this.operator = operator.toLowerCase();
this.value = value;
}
PropertyFilter.prototype.match = function (o) {
var value = this.value;
var propValue = persistence.get(o, this.property);
if(value && value.getTime) { // DATE
// TODO: Deal with arrays of dates for 'in' and 'not in'
value = Math.round(value.getTime() / 1000) * 1000; // Deal with precision
if(propValue && propValue.getTime) { // DATE
propValue = Math.round(propValue.getTime() / 1000) * 1000; // Deal with precision
}
}
switch (this.operator) {
case '=':
return propValue === value;
break;
case '!=':
return propValue !== value;
break;
case '<':
return propValue < value;
break;
case '<=':
return propValue <= value;
break;
case '>':
return propValue > value;
break;
case '>=':
return propValue >= value;
break;
case 'in':
return arrayContains(value, propValue);
break;
case 'not in':
return !arrayContains(value, propValue);
break;
}
};
PropertyFilter.prototype.makeFit = function(o) {
if(this.operator === '=') {
persistence.set(o, this.property, this.value);
} else {
throw new Error("Sorry, can't perform makeFit for other filters than =");
}
};
PropertyFilter.prototype.makeNotFit = function(o) {
if(this.operator === '=') {
persistence.set(o, this.property, null);
} else {
throw new Error("Sorry, can't perform makeNotFit for other filters than =");
}
};
PropertyFilter.prototype.subscribeGlobally = function(coll, entityName) {
persistence.subscribeToGlobalPropertyListener(coll, entityName, this.property);
};
PropertyFilter.prototype.unsubscribeGlobally = function(coll, entityName) {
persistence.unsubscribeFromGlobalPropertyListener(coll, entityName, this.property);
};
PropertyFilter.prototype.toUniqueString = function() {
var val = this.value;
if(val && val._type) {
val = val.id;
}
return this.property + this.operator + val;
};
persistence.NullFilter = NullFilter;
persistence.AndFilter = AndFilter;
persistence.OrFilter = OrFilter;
persistence.PropertyFilter = PropertyFilter;
/**
* Ensure global uniqueness of query collection object
*/
persistence.uniqueQueryCollection = function(coll) {
var entityName = coll._entityName;
if(coll._items) { // LocalQueryCollection
return coll;
}
if(!this.queryCollectionCache[entityName]) {
this.queryCollectionCache[entityName] = {};
}
var uniqueString = coll.toUniqueString();
if(!this.queryCollectionCache[entityName][uniqueString]) {
this.queryCollectionCache[entityName][uniqueString] = coll;
}
return this.queryCollectionCache[entityName][uniqueString];
}
/**
* The constructor function of the _abstract_ QueryCollection
* DO NOT INSTANTIATE THIS
* @constructor
*/
function QueryCollection () {
}
QueryCollection.prototype = new Observable();
QueryCollection.prototype.oldAddEventListener = QueryCollection.prototype.addEventListener;
QueryCollection.prototype.setupSubscriptions = function() {
this._filter.subscribeGlobally(this, this._entityName);
};
QueryCollection.prototype.teardownSubscriptions = function() {
this._filter.unsubscribeGlobally(this, this._entityName);
};
QueryCollection.prototype.addEventListener = function(eventType, fn) {
var that = this;
var subscription = this.oldAddEventListener(eventType, fn);
if(this.subscribers[eventType].length === 1) { // first subscriber
this.setupSubscriptions();
}
subscription.oldUnsubscribe = subscription.unsubscribe;
subscription.unsubscribe = function() {
this.oldUnsubscribe();
if(that.subscribers[eventType].length === 0) { // last subscriber
that.teardownSubscriptions();
}
};
return subscription;
};
/**
* Function called when session is flushed, returns list of SQL queries to execute
* (as [query, arg] tuples)
*/
QueryCollection.prototype.persistQueries = function() { return []; };
/**
* Invoked by sub-classes to initialize the query collection
*/
QueryCollection.prototype.init = function (session, entityName, constructor) {
this._filter = new NullFilter();
this._orderColumns = []; // tuples of [column, ascending]
this._prefetchFields = [];
this._entityName = entityName;
this._constructor = constructor;
this._limit = -1;
this._skip = 0;
this._reverse = false;
this._session = session || persistence;
// For observable
this.subscribers = {};
}
QueryCollection.prototype.toUniqueString = function() {
var s = this._constructor.name + ": " + this._entityName;
s += '|Filter:';
var values = [];
s += this._filter.toUniqueString();
s += '|Values:';
for(var i = 0; i < values.length; i++) {
s += values + "|^|";
}
s += '|Order:';
for(var i = 0; i < this._orderColumns.length; i++) {
var col = this._orderColumns[i];
s += col[0] + ", " + col[1];
}
s += '|Prefetch:';
for(var i = 0; i < this._prefetchFields.length; i++) {
s += this._prefetchFields[i];
}
s += '|Limit:';
s += this._limit;
s += '|Skip:';
s += this._skip;
s += '|Reverse:';
s += this._reverse;
return s;
};
/**
* Creates a clone of this query collection
* @return a clone of the collection
*/
QueryCollection.prototype.clone = function (cloneSubscribers) {
var c = new (this._constructor)(this._session, this._entityName);
c._filter = this._filter;
c._prefetchFields = this._prefetchFields.slice(0); // clone
c._orderColumns = this._orderColumns.slice(0);
c._limit = this._limit;
c._skip = this._skip;
c._reverse = this._reverse;
if(cloneSubscribers) {
var subscribers = {};
for(var eventType in this.subscribers) {
if(this.subscribers.hasOwnProperty(eventType)) {
subscribers[eventType] = this.subscribers[eventType].slice(0);
}
}
c.subscribers = subscribers; //this.subscribers;
} else {
c.subscribers = this.subscribers;
}
return c;
};
/**
* Returns a new query collection with a property filter condition added
* @param property the property to filter on
* @param operator the operator to use
* @param value the literal value that the property should match
* @return the query collection with the filter added
*/
QueryCollection.prototype.filter = function (property, operator, value) {
var c = this.clone(true);
c._filter = new AndFilter(this._filter, new PropertyFilter(property,
operator, value));
// Add global listener (TODO: memory leak waiting to happen!)
var session = this._session;
c = session.uniqueQueryCollection(c);
//session.subscribeToGlobalPropertyListener(c, this._entityName, property);
return session.uniqueQueryCollection(c);
};
/**
* Returns a new query collection with an OR condition between the
* current filter and the filter specified as argument
* @param filter the other filter
* @return the new query collection
*/
QueryCollection.prototype.or = function (filter) {
var c = this.clone(true);
c._filter = new OrFilter(this._filter, filter);
return this._session.uniqueQueryCollection(c);
};
/**
* Returns a new query collection with an AND condition between the
* current filter and the filter specified as argument
* @param filter the other filter
* @return the new query collection
*/
QueryCollection.prototype.and = function (filter) {
var c = this.clone(true);
c._filter = new AndFilter(this._filter, filter);
return this._session.uniqueQueryCollection(c);
};
/**
* Returns a new query collection with an ordering imposed on the collection
* @param property the property to sort on
* @param ascending should the order be ascending (= true) or descending (= false)
* @return the query collection with imposed ordering
*/
QueryCollection.prototype.order = function (property, ascending) {
ascending = ascending === undefined ? true : ascending;
var c = this.clone();
c._orderColumns.push( [ property, ascending ]);
return this._session.uniqueQueryCollection(c);
};
/**
* Returns a new query collection will limit its size to n items
* @param n the number of items to limit it to
* @return the limited query collection
*/
QueryCollection.prototype.limit = function(n) {
var c = this.clone();
c._limit = n;
return this._session.uniqueQueryCollection(c);
};
/**
* Returns a new query collection which will skip the first n results
* @param n the number of results to skip
* @return the query collection that will skip n items
*/
QueryCollection.prototype.skip = function(n) {
var c = this.clone();
c._skip = n;
return this._session.uniqueQueryCollection(c);
};
/**
* Returns a new query collection which reverse the order of the result set
* @return the query collection that will reverse its items
*/
QueryCollection.prototype.reverse = function() {
var c = this.clone();
c._reverse = true;
return this._session.uniqueQueryCollection(c);
};
/**
* Returns a new query collection which will prefetch a certain object relationship.
* Only works with 1:1 and N:1 relations.
* Relation must target an entity, not a mix-in.
* @param rel the relation name of the relation to prefetch
* @return the query collection prefetching `rel`
*/
QueryCollection.prototype.prefetch = function (rel) {
var c = this.clone();
c._prefetchFields.push(rel);
return this._session.uniqueQueryCollection(c);
};
/**
* Select a subset of data, represented by this query collection as a JSON
* structure (Javascript object)
*
* @param tx database transaction to use, leave out to start a new one
* @param props a property specification
* @param callback(result)
*/
QueryCollection.prototype.selectJSON = function(tx, props, callback) {
var args = argspec.getArgs(arguments, [
{ name: "tx", optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: "props", optional: false },
{ name: "callback", optional: false }
]);
var session = this._session;
var that = this;
tx = args.tx;
props = args.props;
callback = args.callback;
if(!tx) {
session.transaction(function(tx) {
that.selectJSON(tx, props, callback);
});
return;
}
var Entity = getEntity(this._entityName);
// TODO: This could do some clever prefetching to make it more efficient
this.list(function(items) {
var resultArray = [];
persistence.asyncForEach(items, function(item, callback) {
item.selectJSON(tx, props, function(obj) {
resultArray.push(obj);
callback();
});
}, function() {
callback(resultArray);
});
});
};
/**
* Adds an object to a collection
* @param obj the object to add
*/
QueryCollection.prototype.add = function(obj) {
if(!obj.id || !obj._type) {
throw new Error("Cannot add object of non-entity type onto collection.");
}
this._session.add(obj);
this._filter.makeFit(obj);
this.triggerEvent('add', this, obj);
this.triggerEvent('change', this, obj);
}
/**
* Adds an an array of objects to a collection
* @param obj the object to add
*/
QueryCollection.prototype.addAll = function(objs) {
for(var i = 0; i < objs.length; i++) {
var obj = objs[i];
this._session.add(obj);
this._filter.makeFit(obj);
this.triggerEvent('add', this, obj);
}
this.triggerEvent('change', this);
}
/**
* Removes an object from a collection
* @param obj the object to remove from the collection
*/
QueryCollection.prototype.remove = function(obj) {
if(!obj.id || !obj._type) {
throw new Error("Cannot remove object of non-entity type from collection.");
}
this._filter.makeNotFit(obj);
this.triggerEvent('remove', this, obj);
this.triggerEvent('change', this, obj);
}
/**
* A database implementation of the QueryCollection
* @param entityName the name of the entity to create the collection for
* @constructor
*/
function DbQueryCollection (session, entityName) {
this.init(session, entityName, DbQueryCollection);
}
/**
* Execute a function for each item in the list
* @param tx the transaction to use (or null to open a new one)
* @param eachFn (elem) the function to be executed for each item
*/
QueryCollection.prototype.each = function (tx, eachFn) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'eachFn', optional: true, check: argspec.isCallback() }
]);
tx = args.tx;
eachFn = args.eachFn;
this.list(tx, function(results) {
for(var i = 0; i < results.length; i++) {
eachFn(results[i]);
}
});
}
// Alias
QueryCollection.prototype.forEach = QueryCollection.prototype.each;
QueryCollection.prototype.one = function (tx, oneFn) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'oneFn', optional: false, check: argspec.isCallback() }
]);
tx = args.tx;
oneFn = args.oneFn;
var that = this;
this.limit(1).list(tx, function(results) {
if(results.length === 0) {
oneFn(null);
} else {
oneFn(results[0]);
}
});
}
DbQueryCollection.prototype = new QueryCollection();
/**
* An implementation of QueryCollection, that is used
* to represent all instances of an entity type
* @constructor
*/
function AllDbQueryCollection (session, entityName) {
this.init(session, entityName, AllDbQueryCollection);
}
AllDbQueryCollection.prototype = new DbQueryCollection();
AllDbQueryCollection.prototype.add = function(obj) {
this._session.add(obj);
this.triggerEvent('add', this, obj);
this.triggerEvent('change', this, obj);
};
AllDbQueryCollection.prototype.remove = function(obj) {
this._session.remove(obj);
this.triggerEvent('remove', this, obj);
this.triggerEvent('change', this, obj);
};
/**
* A ManyToMany implementation of QueryCollection
* @constructor
*/
function ManyToManyDbQueryCollection (session, entityName) {
this.init(session, entityName, persistence.ManyToManyDbQueryCollection);
this._localAdded = [];
this._localRemoved = [];
}
ManyToManyDbQueryCollection.prototype = new DbQueryCollection();
ManyToManyDbQueryCollection.prototype.initManyToMany = function(obj, coll) {
this._obj = obj;
this._coll = coll;
};
ManyToManyDbQueryCollection.prototype.add = function(obj) {
if(!arrayContains(this._localAdded, obj)) {
this._session.add(obj);
this._localAdded.push(obj);
this.triggerEvent('add', this, obj);
this.triggerEvent('change', this, obj);
}
};
ManyToManyDbQueryCollection.prototype.addAll = function(objs) {
for(var i = 0; i < objs.length; i++) {
var obj = objs[i];
if(!arrayContains(this._localAdded, obj)) {
this._session.add(obj);
this._localAdded.push(obj);
this.triggerEvent('add', this, obj);
}
}
this.triggerEvent('change', this);
}
ManyToManyDbQueryCollection.prototype.clone = function() {
var c = DbQueryCollection.prototype.clone.call(this);
c._localAdded = this._localAdded;
c._localRemoved = this._localRemoved;
c._obj = this._obj;
c._coll = this._coll;
return c;
};
ManyToManyDbQueryCollection.prototype.remove = function(obj) {
if(arrayContains(this._localAdded, obj)) { // added locally, can just remove it from there
arrayRemove(this._localAdded, obj);
} else if(!arrayContains(this._localRemoved, obj)) {
this._localRemoved.push(obj);
}
this.triggerEvent('remove', this, obj);
this.triggerEvent('change', this, obj);
};
////////// Local implementation of QueryCollection \\\\\\\\\\\\\\\\
function LocalQueryCollection(initialArray) {
this.init(persistence, null, LocalQueryCollection);
this._items = initialArray || [];
}
LocalQueryCollection.prototype = new QueryCollection();
LocalQueryCollection.prototype.clone = function() {
var c = DbQueryCollection.prototype.clone.call(this);
c._items = this._items;
return c;
};
LocalQueryCollection.prototype.add = function(obj) {
if(!arrayContains(this._items, obj)) {
this._session.add(obj);
this._items.push(obj);
this.triggerEvent('add', this, obj);
this.triggerEvent('change', this, obj);
}
};
LocalQueryCollection.prototype.addAll = function(objs) {
for(var i = 0; i < objs.length; i++) {
var obj = objs[i];
if(!arrayContains(this._items, obj)) {
this._session.add(obj);
this._items.push(obj);
this.triggerEvent('add', this, obj);
}
}
this.triggerEvent('change', this);
}
LocalQueryCollection.prototype.remove = function(obj) {
var items = this._items;
for(var i = 0; i < items.length; i++) {
if(items[i] === obj) {
this._items.splice(i, 1);
this.triggerEvent('remove', this, obj);
this.triggerEvent('change', this, obj);
}
}
};
LocalQueryCollection.prototype.list = function(tx, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'callback', optional: true, check: argspec.isCallback() }
]);
callback = args.callback;
if(!callback || callback.executeSql) { // first argument is transaction
callback = arguments[1]; // set to second argument
}
var array = this._items.slice(0);
var that = this;
var results = [];
for(var i = 0; i < array.length; i++) {
if(this._filter.match(array[i])) {
results.push(array[i]);
}
}
results.sort(function(a, b) {
for(var i = 0; i < that._orderColumns.length; i++) {
var col = that._orderColumns[i][0];
var asc = that._orderColumns[i][1];
var aVal = persistence.get(a, col);
var bVal = persistence.get(b, col);
if(aVal < bVal) {
return asc ? -1 : 1;
} else if(aVal > bVal) {
return asc ? 1 : -1;
}
}
return 0;
});
if(this._skip) {
results.splice(0, this._skip);
}
if(this._limit > -1) {
results = results.slice(0, this._limit);
}
if(this._reverse) {
results.reverse();
}
if(callback) {
callback(results);
} else {
return results;
}
};
LocalQueryCollection.prototype.destroyAll = function(callback) {
if(!callback || callback.executeSql) { // first argument is transaction
callback = arguments[1]; // set to second argument
}
this._items = [];
this.triggerEvent('change', this);
if(callback) callback();
};
LocalQueryCollection.prototype.count = function(tx, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'callback', optional: true, check: argspec.isCallback() }
]);
tx = args.tx;
callback = args.callback;
var result = this.list();
if(callback) {
callback(result.length);
} else {
return result.length;
}
};
persistence.QueryCollection = QueryCollection;
persistence.DbQueryCollection = DbQueryCollection;
persistence.ManyToManyDbQueryCollection = ManyToManyDbQueryCollection;
persistence.LocalQueryCollection = LocalQueryCollection;
persistence.Observable = Observable;
persistence.Subscription = Subscription;
persistence.AndFilter = AndFilter;
persistence.OrFilter = OrFilter;
persistence.PropertyFilter = PropertyFilter;
}());
// ArgSpec.js library: http://github.com/zefhemel/argspecjs
var argspec = {};
(function() {
argspec.getArgs = function(args, specs) {
var argIdx = 0;
var specIdx = 0;
var argObj = {};
while(specIdx < specs.length) {
var s = specs[specIdx];
var a = args[argIdx];
if(s.optional) {
if(a !== undefined && s.check(a)) {
argObj[s.name] = a;
argIdx++;
specIdx++;
} else {
if(s.defaultValue !== undefined) {
argObj[s.name] = s.defaultValue;
}
specIdx++;
}
} else {
if(s.check && !s.check(a)) {
throw new Error("Invalid value for argument: " + s.name + " Value: " + a);
}
argObj[s.name] = a;
specIdx++;
argIdx++;
}
}
return argObj;
}
argspec.hasProperty = function(name) {
return function(obj) {
return obj && obj[name] !== undefined;
};
}
argspec.hasType = function(type) {
return function(obj) {
return typeof obj === type;
};
}
argspec.isCallback = function() {
return function(obj) {
return obj && obj.apply;
};
}
}());
persistence.argspec = argspec;
return persistence;
} // end of createPersistence
// JSON2 library, source: http://www.JSON.org/js.html
// Most modern browsers already support this natively, but mobile
// browsers often don't, hence this implementation
// Relevant APIs:
// JSON.stringify(value, replacer, space)
// JSON.parse(text, reviver)
if(typeof JSON === 'undefined') {
JSON = {};
}
//var JSON = typeof JSON === 'undefined' ? window.JSON : {};
if (!JSON.stringify) {
(function () {
function f(n) {
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap, indent,
meta = {
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
escapable.lastIndex = 0;
return escapable.test(string) ?
'"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' :
'"' + string + '"';
}
function str(key, holder) {
var i, k, v, length, mind = gap, partial, value = holder[key];
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
return String(value);
case 'object':
if (!value) {
return 'null';
}
gap += indent;
partial = [];
if (Object.prototype.toString.apply(value) === '[object Array]') {
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
v = partial.length === 0 ? '[]' :
gap ? '[\n' + gap +
partial.join(',\n' + gap) + '\n' +
mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
k = rep[i];
if (typeof k === 'string') {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
v = partial.length === 0 ? '{}' :
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
mind + '}' : '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
var i;
gap = '';
indent = '';
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
} else if (typeof space === 'string') {
indent = space;
}
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
return str('', {'': value});
};
}
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
var j;
function walk(holder, key) {
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
j = eval('(' + text + ')');
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
throw new SyntaxError('JSON.parse');
};
}
}());
}
/**
* Default type mapper. Override to support more types or type options.
*/
var defaultTypeMapper = {
/**
* SQL type for ids
*/
idType: "VARCHAR(32)",
/**
* SQL type for class names (used by mixins)
*/
classNameType: "TEXT",
/**
* Returns SQL type for column definition
*/
columnType: function(type){
switch(type) {
case 'JSON': return 'TEXT';
case 'BOOL': return 'INT';
case 'DATE': return 'INT';
default: return type;
}
},
inVar: function(str, type){
return str;
},
outVar: function(str, type){
return str;
},
outId: function(str){
return "'" + str + "'";
},
/**
* Converts a value from the database to a value suitable for the entity
* (also does type conversions, if necessary)
*/
dbValToEntityVal: function(val, type){
if (val === null || val === undefined) {
return val;
}
switch (type) {
case 'DATE':
// SQL is in seconds and JS in miliseconds
return new Date(parseInt(val, 10) * 1000);
case 'BOOL':
return val === 1 || val === '1';
break;
case 'INT':
return +val;
break;
case 'BIGINT':
return +val;
break;
case 'JSON':
if (val) {
return JSON.parse(val);
}
else {
return val;
}
break;
default:
return val;
}
},
/**
* Converts an entity value to a database value, inverse of
* dbValToEntityVal
*/
entityValToDbVal: function(val, type){
if (val === undefined || val === null) {
return null;
}
else if (type === 'JSON' && val) {
return JSON.stringify(val);
}
else if (val.id) {
return val.id;
}
else if (type === 'BOOL') {
return (val === 'false') ? 0 : (val ? 1 : 0);
}
else if (type === 'DATE' || val.getTime) {
// In order to make SQLite Date/Time functions work we should store
// values in seconds and not as miliseconds as JS Date.getTime()
val = new Date(val);
return Math.round(val.getTime() / 1000);
}
else {
return val;
}
},
/**
* Shortcut for inVar when type is id -- no need to override
*/
inIdVar: function(str){
return this.inVar(str, this.idType);
},
/**
* Shortcut for outVar when type is id -- no need to override
*/
outIdVar: function(str){
return this.outVar(str, this.idType);
},
/**
* Shortcut for entityValToDbVal when type is id -- no need to override
*/
entityIdToDbId: function(id){
return this.entityValToDbVal(id, this.idType);
}
}
function config(persistence, dialect) {
var argspec = persistence.argspec;
persistence.typeMapper = dialect.typeMapper || defaultTypeMapper;
persistence.generatedTables = {}; // set
/**
* Synchronize the data model with the database, creates table that had not
* been defined before
*
* @param tx
* transaction object to use (optional)
* @param callback
* function to be called when synchronization has completed,
* takes started transaction as argument
*/
persistence.schemaSync = function (tx, callback, emulate) {
var args = argspec.getArgs(arguments, [
{ name: "tx", optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: "callback", optional: true, check: argspec.isCallback(), defaultValue: function(){} },
{ name: "emulate", optional: true, check: argspec.hasType('boolean') }
]);
tx = args.tx;
callback = args.callback;
emulate = args.emulate;
if(!tx) {
var session = this;
this.transaction(function(tx) { session.schemaSync(tx, callback, emulate); });
return;
}
var queries = [], meta, colDefs, otherMeta, tableName;
var tm = persistence.typeMapper;
var entityMeta = persistence.getEntityMeta();
for (var entityName in entityMeta) {
if (entityMeta.hasOwnProperty(entityName)) {
meta = entityMeta[entityName];
if (!meta.isMixin) {
colDefs = [];
for (var prop in meta.fields) {
if (meta.fields.hasOwnProperty(prop)) {
colDefs.push([prop, meta.fields[prop]]);
}
}
for (var rel in meta.hasOne) {
if (meta.hasOne.hasOwnProperty(rel)) {
otherMeta = meta.hasOne[rel].type.meta;
colDefs.push([rel, tm.idType]);
queries.push([dialect.createIndex(meta.name, [rel]), null]);
}
}
for (var i = 0; i < meta.indexes.length; i++) {
queries.push([dialect.createIndex(meta.name, meta.indexes[i].columns, meta.indexes[i]), null]);
}
}
for (var rel in meta.hasMany) {
if (meta.hasMany.hasOwnProperty(rel) && meta.hasMany[rel].manyToMany) {
tableName = meta.hasMany[rel].tableName;
if (!persistence.generatedTables[tableName]) {
var otherMeta = meta.hasMany[rel].type.meta;
var inv = meta.hasMany[rel].inverseProperty;
// following test ensures that mixin mtm tables get created with the mixin itself
// it seems superfluous because mixin will be processed before entitites that use it
// but better be safe than sorry.
if (otherMeta.hasMany[inv].type.meta != meta)
continue;
var p1 = meta.name + "_" + rel;
var p2 = otherMeta.name + "_" + inv;
queries.push([dialect.createIndex(tableName, [p1]), null]);
queries.push([dialect.createIndex(tableName, [p2]), null]);
var columns = [[p1, tm.idType], [p2, tm.idType]];
if (meta.isMixin)
columns.push([p1 + "_class", tm.classNameType])
if (otherMeta.isMixin)
columns.push([p2 + "_class", tm.classNameType])
queries.push([dialect.createTable(tableName, columns), null]);
persistence.generatedTables[tableName] = true;
}
}
}
if (!meta.isMixin) {
colDefs.push(["id", tm.idType, "PRIMARY KEY"]);
persistence.generatedTables[meta.name] = true;
queries.push([dialect.createTable(meta.name, colDefs), null]);
}
}
}
var fns = persistence.schemaSyncHooks;
for(var i = 0; i < fns.length; i++) {
fns[i](tx);
}
if(emulate) {
// Done
callback(tx);
} else {
executeQueriesSeq(tx, queries, function(_, err) {
callback(tx, err);
});
}
};
/**
* Persists all changes to the database transaction
*
* @param tx
* transaction to use
* @param callback
* function to be called when done
*/
persistence.flush = function (tx, callback) {
var args = argspec.getArgs(arguments, [
{ name: "tx", optional: true, check: persistence.isTransaction },
{ name: "callback", optional: true, check: argspec.isCallback(), defaultValue: null }
]);
tx = args.tx;
callback = args.callback;
var session = this;
if(!tx) {
this.transaction(function(tx) { session.flush(tx, callback); });
return;
}
var fns = persistence.flushHooks;
persistence.asyncForEach(fns, function(fn, callback) {
fn(session, tx, callback);
}, function() {
// After applying the hooks
var persistObjArray = [];
for (var id in session.trackedObjects) {
if (session.trackedObjects.hasOwnProperty(id)) {
persistObjArray.push(session.trackedObjects[id]);
}
}
var removeObjArray = [];
for (var id in session.objectsToRemove) {
if (session.objectsToRemove.hasOwnProperty(id)) {
removeObjArray.push(session.objectsToRemove[id]);
delete session.trackedObjects[id]; // Stop tracking
}
}
session.objectsToRemove = {};
if(callback) {
persistence.asyncParForEach(removeObjArray, function(obj, callback) {
remove(obj, tx, callback);
}, function(result, err) {
if (err) return callback(result, err);
persistence.asyncParForEach(persistObjArray, function(obj, callback) {
save(obj, tx, callback);
}, callback);
});
} else { // More efficient
for(var i = 0; i < persistObjArray.length; i++) {
save(persistObjArray[i], tx);
}
for(var i = 0; i < removeObjArray.length; i++) {
remove(removeObjArray[i], tx);
}
}
});
};
/**
* Remove all tables in the database (as defined by the model)
*/
persistence.reset = function (tx, callback) {
var args = argspec.getArgs(arguments, [
{ name: "tx", optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: "callback", optional: true, check: argspec.isCallback(), defaultValue: function(){} }
]);
tx = args.tx;
callback = args.callback;
var session = this;
if(!tx) {
session.transaction(function(tx) { session.reset(tx, callback); });
return;
}
// First emulate syncing the schema (to know which tables were created)
this.schemaSync(tx, function() {
var tableArray = [];
for (var p in persistence.generatedTables) {
if (persistence.generatedTables.hasOwnProperty(p)) {
tableArray.push(p);
}
}
function dropOneTable () {
var tableName = tableArray.pop();
tx.executeSql("DROP TABLE IF EXISTS `" + tableName + "`", null, function () {
if (tableArray.length > 0) {
dropOneTable();
} else {
cb();
}
}, cb);
}
if(tableArray.length > 0) {
dropOneTable();
} else {
cb();
}
function cb(result, err) {
session.clean();
persistence.generatedTables = {};
if (callback) callback(result, err);
}
}, true);
};
/**
* Converts a database row into an entity object
*/
function rowToEntity(session, entityName, row, prefix) {
prefix = prefix || '';
if (session.trackedObjects[row[prefix + "id"]]) { // Cached version
return session.trackedObjects[row[prefix + "id"]];
}
var tm = persistence.typeMapper;
var rowMeta = persistence.getMeta(entityName);
var ent = persistence.define(entityName); // Get entity
if(!row[prefix+'id']) { // null value, no entity found
return null;
}
var o = new ent(session, undefined, true);
o.id = tm.dbValToEntityVal(row[prefix + 'id'], tm.idType);
o._new = false;
for ( var p in row) {
if (row.hasOwnProperty(p)) {
if (p.substring(0, prefix.length) === prefix) {
var prop = p.substring(prefix.length);
if (prop != 'id') {
o._data[prop] = tm.dbValToEntityVal(row[p], rowMeta.fields[prop] || tm.idType);
}
}
}
}
return o;
}
/**
* Internal function to persist an object to the database
* this function is invoked by persistence.flush()
*/
function save(obj, tx, callback) {
var meta = persistence.getMeta(obj._type);
var tm = persistence.typeMapper;
var properties = [];
var values = [];
var qs = [];
var propertyPairs = [];
if(obj._new) { // Mark all properties dirty
for (var p in meta.fields) {
if(meta.fields.hasOwnProperty(p)) {
obj._dirtyProperties[p] = true;
}
}
}
for ( var p in obj._dirtyProperties) {
if (obj._dirtyProperties.hasOwnProperty(p)) {
properties.push("`" + p + "`");
var type = meta.fields[p] || tm.idType;
values.push(tm.entityValToDbVal(obj._data[p], type));
qs.push(tm.outVar("?", type));
propertyPairs.push("`" + p + "` = " + tm.outVar("?", type));
}
}
var additionalQueries = [];
for(var p in meta.hasMany) {
if(meta.hasMany.hasOwnProperty(p)) {
additionalQueries = additionalQueries.concat(persistence.get(obj, p).persistQueries());
}
}
executeQueriesSeq(tx, additionalQueries, function() {
if (properties.length === 0) { // Nothing changed
if(callback) callback();
return;
}
obj._dirtyProperties = {};
if (obj._new) {
properties.push('id');
values.push(tm.entityIdToDbId(obj.id));
qs.push(tm.outIdVar('?'));
var sql = "INSERT INTO `" + obj._type + "` (" + properties.join(", ") + ") VALUES (" + qs.join(', ') + ")";
obj._new = false;
tx.executeSql(sql, values, callback, callback);
} else {
var sql = "UPDATE `" + obj._type + "` SET " + propertyPairs.join(',') + " WHERE id = " + tm.outId(obj.id);
tx.executeSql(sql, values, callback, callback);
}
});
}
persistence.save = save;
function remove (obj, tx, callback) {
var meta = persistence.getMeta(obj._type);
var tm = persistence.typeMapper;
var queries = [["DELETE FROM `" + obj._type + "` WHERE id = " + tm.outId(obj.id), null]];
for (var rel in meta.hasMany) {
if (meta.hasMany.hasOwnProperty(rel) && meta.hasMany[rel].manyToMany) {
var tableName = meta.hasMany[rel].tableName;
//var inverseProperty = meta.hasMany[rel].inverseProperty;
queries.push(["DELETE FROM `" + tableName + "` WHERE `" + meta.name + '_' + rel + "` = " + tm.outId(obj.id), null]);
}
}
executeQueriesSeq(tx, queries, callback);
}
/**
* Utility function to execute a series of queries in an asynchronous way
* @param tx the transaction to execute the queries on
* @param queries an array of [query, args] tuples
* @param callback the function to call when all queries have been executed
*/
function executeQueriesSeq (tx, queries, callback) {
// queries.reverse();
var callbackArgs = [];
for ( var i = 3; i < arguments.length; i++) {
callbackArgs.push(arguments[i]);
}
persistence.asyncForEach(queries, function(queryTuple, callback) {
tx.executeSql(queryTuple[0], queryTuple[1], callback, function(_, err) {
console.log(err.message);
callback(_, err);
});
}, function(result, err) {
if (err && callback) {
callback(result, err);
return;
}
if(callback) callback.apply(null, callbackArgs);
});
}
persistence.executeQueriesSeq = executeQueriesSeq;
/////////////////////////// QueryCollection patches to work in SQL environment
/**
* Function called when session is flushed, returns list of SQL queries to execute
* (as [query, arg] tuples)
*/
persistence.QueryCollection.prototype.persistQueries = function() { return []; };
var oldQCClone = persistence.QueryCollection.prototype.clone;
persistence.QueryCollection.prototype.clone = function (cloneSubscribers) {
var c = oldQCClone.call(this, cloneSubscribers);
c._additionalJoinSqls = this._additionalJoinSqls.slice(0);
c._additionalWhereSqls = this._additionalWhereSqls.slice(0);
c._additionalGroupSqls = this._additionalGroupSqls.slice(0);
c._manyToManyFetch = this._manyToManyFetch;
return c;
};
var oldQCInit = persistence.QueryCollection.prototype.init;
persistence.QueryCollection.prototype.init = function(session, entityName, constructor) {
oldQCInit.call(this, session, entityName, constructor);
this._manyToManyFetch = null;
this._additionalJoinSqls = [];
this._additionalWhereSqls = [];
this._additionalGroupSqls = [];
};
var oldQCToUniqueString = persistence.QueryCollection.prototype.toUniqueString;
persistence.QueryCollection.prototype.toUniqueString = function() {
var s = oldQCToUniqueString.call(this);
s += '|JoinSQLs:';
for(var i = 0; i < this._additionalJoinSqls.length; i++) {
s += this._additionalJoinSqls[i];
}
s += '|WhereSQLs:';
for(var i = 0; i < this._additionalWhereSqls.length; i++) {
s += this._additionalWhereSqls[i];
}
s += '|GroupSQLs:';
for(var i = 0; i < this._additionalGroupSqls.length; i++) {
s += this._additionalGroupSqls[i];
}
if(this._manyToManyFetch) {
s += '|ManyToManyFetch:';
s += JSON.stringify(this._manyToManyFetch); // TODO: Do something more efficient
}
return s;
};
persistence.NullFilter.prototype.sql = function (meta, alias, values) {
return "1=1";
};
persistence.AndFilter.prototype.sql = function (meta, alias, values) {
return "(" + this.left.sql(meta, alias, values) + " AND "
+ this.right.sql(meta, alias, values) + ")";
};
persistence.OrFilter.prototype.sql = function (meta, alias, values) {
return "(" + this.left.sql(meta, alias, values) + " OR "
+ this.right.sql(meta, alias, values) + ")";
};
persistence.PropertyFilter.prototype.sql = function (meta, alias, values) {
var tm = persistence.typeMapper;
var aliasPrefix = alias ? "`" + alias + "`." : "";
var sqlType = meta.fields[this.property] || tm.idType;
if (this.operator === '=' && this.value === null) {
return aliasPrefix + '`' + this.property + "` IS NULL";
} else if (this.operator === '!=' && this.value === null) {
return aliasPrefix + '`' + this.property + "` IS NOT NULL";
} else if (this.operator === 'in') {
var vals = this.value;
var qs = [];
for(var i = 0; i < vals.length; i++) {
qs.push('?');
values.push(tm.entityValToDbVal(vals[i], sqlType));
}
if(vals.length === 0) {
// Optimize this a little
return "1 = 0";
} else {
return aliasPrefix + '`' + this.property + "` IN (" + qs.join(', ') + ")";
}
} else if (this.operator === 'not in') {
var vals = this.value;
var qs = [];
for(var i = 0; i < vals.length; i++) {
qs.push('?');
values.push(tm.entityValToDbVal(vals[i], sqlType));
}
if(vals.length === 0) {
// Optimize this a little
return "1 = 1";
} else {
return aliasPrefix + '`' + this.property + "` NOT IN (" + qs.join(', ') + ")";
}
} else {
var value = this.value;
if(value === true || value === false) {
value = value ? 1 : 0;
}
values.push(tm.entityValToDbVal(value, sqlType));
return aliasPrefix + '`' + this.property + "` " + this.operator + " " + tm.outVar("?", sqlType);
}
};
// QueryColleciton's list
/**
* Asynchronous call to actually fetch the items in the collection
* @param tx transaction to use
* @param callback function to be called taking an array with
* result objects as argument
*/
persistence.DbQueryCollection.prototype.list = function (tx, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'callback', optional: false, check: argspec.isCallback() }
]);
tx = args.tx;
callback = args.callback;
var that = this;
var session = this._session;
if(!tx) { // no transaction supplied
session.transaction(function(tx) {
that.list(tx, callback);
});
return;
}
var entityName = this._entityName;
var meta = persistence.getMeta(entityName);
var tm = persistence.typeMapper;
// handles mixin case -- this logic is generic and could be in persistence.
if (meta.isMixin) {
var result = [];
persistence.asyncForEach(meta.mixedIns, function(realMeta, next) {
var query = that.clone();
query._entityName = realMeta.name;
query.list(tx, function(array) {
result = result.concat(array);
next();
});
}, function() {
var query = new persistence.LocalQueryCollection(result);
query._orderColumns = that._orderColumns;
query._reverse = that._reverse;
// TODO: handle skip and limit -- do we really want to do it?
query.list(null, callback);
});
return;
}
function selectAll (meta, tableAlias, prefix) {
var selectFields = [ tm.inIdVar("`" + tableAlias + "`.id") + " AS " + prefix + "id" ];
for ( var p in meta.fields) {
if (meta.fields.hasOwnProperty(p)) {
selectFields.push(tm.inVar("`" + tableAlias + "`.`" + p + "`", meta.fields[p]) + " AS `"
+ prefix + p + "`");
}
}
for ( var p in meta.hasOne) {
if (meta.hasOne.hasOwnProperty(p)) {
selectFields.push(tm.inIdVar("`" + tableAlias + "`.`" + p + "`") + " AS `"
+ prefix + p + "`");
}
}
return selectFields;
}
var args = [];
var mainPrefix = entityName + "_";
var mainAlias = 'root';
var selectFields = selectAll(meta, mainAlias, mainPrefix);
var joinSql = '';
var additionalWhereSqls = this._additionalWhereSqls.slice(0);
var mtm = this._manyToManyFetch;
if(mtm) {
joinSql += "LEFT JOIN `" + mtm.table + "` AS mtm ON mtm.`" + mtm.inverseProp + "` = `root`.`id` ";
additionalWhereSqls.push("mtm.`" + mtm.prop + "` = " + tm.outId(mtm.id));
}
joinSql += this._additionalJoinSqls.join(' ');
for ( var i = 0; i < this._prefetchFields.length; i++) {
var prefetchField = this._prefetchFields[i];
var thisMeta = meta.hasOne[prefetchField].type.meta;
if (thisMeta.isMixin)
throw new Error("cannot prefetch a mixin");
var tableAlias = thisMeta.name + '_' + prefetchField + "_tbl";
selectFields = selectFields.concat(selectAll(thisMeta, tableAlias,
prefetchField + "_"));
joinSql += "LEFT JOIN `" + thisMeta.name + "` AS `" + tableAlias
+ "` ON `" + tableAlias + "`.`id` = `" + mainAlias + '`.`' + prefetchField + "` ";
}
var whereSql = "WHERE "
+ [ this._filter.sql(meta, mainAlias, args) ].concat(additionalWhereSqls).join(' AND ');
var sql = "SELECT " + selectFields.join(", ") + " FROM `" + entityName
+ "` AS `" + mainAlias + "` " + joinSql + " " + whereSql;
if(this._additionalGroupSqls.length > 0) {
sql += this._additionalGroupSqls.join(' ');
}
if(this._orderColumns.length > 0) {
sql += " ORDER BY "
+ this._orderColumns.map(
function (c) {
return "`" + mainPrefix + c[0] + "` "
+ (c[1] ? "ASC" : "DESC");
}).join(", ");
}
if(this._limit >= 0) {
sql += " LIMIT " + this._limit;
}
if(this._skip > 0) {
sql += " OFFSET " + this._skip;
}
session.flush(tx, function () {
tx.executeSql(sql, args, function (rows) {
var results = [];
if(that._reverse) {
rows.reverse();
}
for ( var i = 0; i < rows.length; i++) {
var r = rows[i];
var e = rowToEntity(session, entityName, r, mainPrefix);
for ( var j = 0; j < that._prefetchFields.length; j++) {
var prefetchField = that._prefetchFields[j];
var thisMeta = meta.hasOne[prefetchField].type.meta;
e._data_obj[prefetchField] = rowToEntity(session, thisMeta.name, r, prefetchField + '_');
session.add(e._data_obj[prefetchField]);
}
results.push(e);
session.add(e);
}
callback(results);
that.triggerEvent('list', that, results);
});
});
};
/**
* Asynchronous call to remove all the items in the collection.
* Note: does not only remove the items from the collection, but
* the items themselves.
* @param tx transaction to use
* @param callback function to be called when clearing has completed
*/
persistence.DbQueryCollection.prototype.destroyAll = function (tx, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'callback', optional: true, check: argspec.isCallback(), defaultValue: function(){} }
]);
tx = args.tx;
callback = args.callback;
var that = this;
var session = this._session;
if(!tx) { // no transaction supplied
session.transaction(function(tx) {
that.destroyAll(tx, callback);
});
return;
}
var entityName = this._entityName;
var meta = persistence.getMeta(entityName);
var tm = persistence.typeMapper;
// handles mixin case -- this logic is generic and could be in persistence.
if (meta.isMixin) {
persistence.asyncForEach(meta.mixedIns, function(realMeta, next) {
var query = that.clone();
query._entityName = realMeta.name;
query.destroyAll(tx, callback);
}, callback);
return;
}
var joinSql = '';
var additionalWhereSqls = this._additionalWhereSqls.slice(0);
var mtm = this._manyToManyFetch;
if(mtm) {
joinSql += "LEFT JOIN `" + mtm.table + "` AS mtm ON mtm.`" + mtm.inverseProp + "` = `root`.`id` ";
additionalWhereSqls.push("mtm.`" + mtm.prop + "` = " + tm.outId(mtm.id));
}
joinSql += this._additionalJoinSqls.join(' ');
var args = [];
var whereSql = "WHERE "
+ [ this._filter.sql(meta, null, args) ].concat(additionalWhereSqls).join(' AND ');
var selectSql = "SELECT id FROM `" + entityName + "` " + joinSql + ' ' + whereSql;
var deleteSql = "DELETE FROM `" + entityName + "` " + joinSql + ' ' + whereSql;
var args2 = args.slice(0);
session.flush(tx, function () {
tx.executeSql(selectSql, args, function(results) {
for(var i = 0; i < results.length; i++) {
delete session.trackedObjects[results[i].id];
session.objectsRemoved.push({id: results[i].id, entity: entityName});
}
that.triggerEvent('change', that);
tx.executeSql(deleteSql, args2, callback, callback);
}, callback);
});
};
/**
* Asynchronous call to count the number of items in the collection.
* @param tx transaction to use
* @param callback function to be called when clearing has completed
*/
persistence.DbQueryCollection.prototype.count = function (tx, callback) {
var args = argspec.getArgs(arguments, [
{ name: 'tx', optional: true, check: persistence.isTransaction, defaultValue: null },
{ name: 'callback', optional: false, check: argspec.isCallback() }
]);
tx = args.tx;
callback = args.callback;
var that = this;
var session = this._session;
if(tx && !tx.executeSql) { // provided callback as first argument
callback = tx;
tx = null;
}
if(!tx) { // no transaction supplied
session.transaction(function(tx) {
that.count(tx, callback);
});
return;
}
var entityName = this._entityName;
var meta = persistence.getMeta(entityName);
var tm = persistence.typeMapper;
// handles mixin case -- this logic is generic and could be in persistence.
if (meta.isMixin) {
var result = 0;
persistence.asyncForEach(meta.mixedIns, function(realMeta, next) {
var query = that.clone();
query._entityName = realMeta.name;
query.count(tx, function(count) {
result += count;
next();
});
}, function() {
callback(result);
});
return;
}
var joinSql = '';
var additionalWhereSqls = this._additionalWhereSqls.slice(0);
var mtm = this._manyToManyFetch;
if(mtm) {
joinSql += "LEFT JOIN `" + mtm.table + "` AS mtm ON mtm.`" + mtm.inverseProp + "` = `root`.`id` ";
additionalWhereSqls.push("mtm.`" + mtm.prop + "` = " + tm.outId(mtm.id));
}
joinSql += this._additionalJoinSqls.join(' ');
var args = [];
var whereSql = "WHERE " + [ this._filter.sql(meta, "root", args) ].concat(additionalWhereSqls).join(' AND ');
var sql = "SELECT COUNT(*) AS cnt FROM `" + entityName + "` AS `root` " + joinSql + " " + whereSql;
session.flush(tx, function () {
tx.executeSql(sql, args, function(results) {
callback(parseInt(results[0].cnt, 10));
});
});
};
persistence.ManyToManyDbQueryCollection.prototype.persistQueries = function() {
var queries = [];
var meta = persistence.getMeta(this._obj._type);
var inverseMeta = meta.hasMany[this._coll].type.meta;
var tm = persistence.typeMapper;
var rel = meta.hasMany[this._coll];
var inv = inverseMeta.hasMany[rel.inverseProperty];
var direct = rel.mixin ? rel.mixin.meta.name : meta.name;
var inverse = inv.mixin ? inv.mixin.meta.name : inverseMeta.name;
// Added
for(var i = 0; i < this._localAdded.length; i++) {
var columns = [direct + "_" + this._coll, inverse + '_' + rel.inverseProperty];
var vars = [tm.outIdVar("?"), tm.outIdVar("?")];
var args = [tm.entityIdToDbId(this._obj.id), tm.entityIdToDbId(this._localAdded[i].id)];
if (rel.mixin) {
columns.push(direct + "_" + this._coll + "_class");
vars.push("?");
args.push(meta.name);
}
if (inv.mixin) {
columns.push(inverse + "_" + rel.inverseProperty + "_class");
vars.push("?");
args.push(inverseMeta.name);
}
queries.push(["INSERT INTO " + rel.tableName +
" (`" + columns.join("`, `") + "`) VALUES (" + vars.join(",") + ")", args]);
}
this._localAdded = [];
// Removed
for(var i = 0; i < this._localRemoved.length; i++) {
queries.push(["DELETE FROM " + rel.tableName +
" WHERE `" + direct + "_" + this._coll + "` = " + tm.outIdVar("?") + " AND `" +
inverse + '_' + rel.inverseProperty +
"` = " + tm.outIdVar("?"), [tm.entityIdToDbId(this._obj.id), tm.entityIdToDbId(this._localRemoved[i].id)]]);
}
this._localRemoved = [];
return queries;
};
};
if (typeof exports !== 'undefined') {
exports.defaultTypeMapper = defaultTypeMapper;
exports.config = config;
}
else {
window = window || {};
window.persistence = window.persistence || {};
window.persistence.store = window.persistence.store || {};
window.persistence.store.sql = {
defaultTypeMapper: defaultTypeMapper,
config: config
};
}
try {
if(!window) {
window = {};
//exports.console = console;
}
} catch(e) {
window = {};
exports.console = console;
}
var persistence = (window && window.persistence) ? window.persistence : {};
if(!persistence.store) {
persistence.store = {};
}
persistence.store.websql = {};
persistence.store.websql.config = function(persistence, dbname, description, size) {
var conn = null;
/**
* Create a transaction
*
* @param callback,
* the callback function to be invoked when the transaction
* starts, taking the transaction object as argument
*/
persistence.transaction = function (callback) {
if(!conn) {
throw new Error("No ongoing database connection, please connect first.");
} else {
conn.transaction(callback);
}
};
////////// Low-level database interface, abstracting from HTML5 and Gears databases \\\\
persistence.db = persistence.db || {};
persistence.db.implementation = "unsupported";
persistence.db.conn = null;
// window object does not exist on Qt Declarative UI (http://doc.trolltech.org/4.7-snapshot/declarativeui.html)
if (window && window.openDatabase) {
persistence.db.implementation = "html5";
} else if (window && window.google && google.gears) {
persistence.db.implementation = "gears";
} else {
try {
if (openDatabaseSync) {
// TODO: find a browser that implements openDatabaseSync and check out if
// it is attached to the window or some other object
persistence.db.implementation = "html5-sync";
}
} catch(e) {
}
}
persistence.db.html5 = {};
persistence.db.html5.connect = function (dbname, description, size) {
var that = {};
var conn = openDatabase(dbname, '1.0', description, size);
that.transaction = function (fn) {
return conn.transaction(function (sqlt) {
return fn(persistence.db.html5.transaction(sqlt));
});
};
return that;
};
persistence.db.html5.transaction = function (t) {
var that = {};
that.executeSql = function (query, args, successFn, errorFn) {
if(persistence.debug) {
console.log(query, args);
}
t.executeSql(query, args, function (_, result) {
if (successFn) {
var results = [];
for ( var i = 0; i < result.rows.length; i++) {
results.push(result.rows.item(i));
}
successFn(results);
}
}, errorFn);
};
return that;
};
persistence.db.html5Sync = {};
persistence.db.html5Sync.connect = function (dbname, description, size) {
var that = {};
var conn = openDatabaseSync(dbname, '1.0', description, size);
that.transaction = function (fn) {
return conn.transaction(function (sqlt) {
return fn(persistence.db.html5Sync.transaction(sqlt));
});
};
return that;
};
persistence.db.html5Sync.transaction = function (t) {
var that = {};
that.executeSql = function (query, args, successFn, errorFn) {
if (args == null) args = [];
if(persistence.debug) {
console.log(query, args);
}
var result = t.executeSql(query, args);
if (result) {
if (successFn) {
var results = [];
for ( var i = 0; i < result.rows.length; i++) {
results.push(result.rows.item(i));
}
successFn(results);
}
}
};
return that;
};
persistence.db.gears = {};
persistence.db.gears.connect = function (dbname) {
var that = {};
var conn = google.gears.factory.create('beta.database');
conn.open(dbname);
that.transaction = function (fn) {
fn(persistence.db.gears.transaction(conn));
};
return that;
};
persistence.db.gears.transaction = function (conn) {
var that = {};
that.executeSql = function (query, args, successFn, errorFn) {
if(persistence.debug) {
console.log(query, args);
}
var rs = conn.execute(query, args);
if (successFn) {
var results = [];
while (rs.isValidRow()) {
var result = {};
for ( var i = 0; i < rs.fieldCount(); i++) {
result[rs.fieldName(i)] = rs.field(i);
}
results.push(result);
rs.next();
}
successFn(results);
}
};
return that;
};
persistence.db.connect = function (dbname, description, size) {
if (persistence.db.implementation == "html5") {
return persistence.db.html5.connect(dbname, description, size);
} else if (persistence.db.implementation == "html5-sync") {
return persistence.db.html5Sync.connect(dbname, description, size);
} else if (persistence.db.implementation == "gears") {
return persistence.db.gears.connect(dbname);
}
};
///////////////////////// SQLite dialect
persistence.store.websql.sqliteDialect = {
// columns is an array of arrays, e.g.
// [["id", "VARCHAR(32)", "PRIMARY KEY"], ["name", "TEXT"]]
createTable: function(tableName, columns) {
var tm = persistence.typeMapper;
var sql = "CREATE TABLE IF NOT EXISTS `" + tableName + "` (";
var defs = [];
for(var i = 0; i < columns.length; i++) {
var column = columns[i];
defs.push("`" + column[0] + "` " + tm.columnType(column[1]) + (column[2] ? " " + column[2] : ""));
}
sql += defs.join(", ");
sql += ')';
return sql;
},
// columns is array of column names, e.g.
// ["id"]
createIndex: function(tableName, columns, options) {
options = options || {};
return "CREATE "+(options.unique?"UNIQUE ":"")+"INDEX IF NOT EXISTS `" + tableName + "__" + columns.join("_") +
"` ON `" + tableName + "` (" +
columns.map(function(col) { return "`" + col + "`"; }).join(", ") + ")";
}
};
// Configure persistence for generic sql persistence, using sqliteDialect
persistence.store.sql.config(persistence, persistence.store.websql.sqliteDialect);
// Make the connection
conn = persistence.db.connect(dbname, description, size);
if(!conn) {
throw new Error("No supported database found in this browser.");
}
};
try {
exports.persistence = persistence;
} catch(e) {}
(function () {
var global = this,
root = (typeof ProvideCustomRxRootObject == "undefined") ? global.Rx : ProvideCustomRxRootObject();
var observable = root.Observable;
var observableCreate = observable.Create;
observable.FromAngularScope = function (angularScope, propertyName) {
return observableCreate(function (observer) {
var unwatch = angularScope.$watch(function(){
return angularScope[propertyName];
},
function(){
observer.OnNext(angularScope[propertyName]);
});
return function () {
unwatch();
};
})
.Skip(1); //In AngularJS 0.10.x There is no way to avoid initial evaluation. So we take care about it!
};
observable.prototype.ToOutputProperty = function (scope, propertyName) {
var disposable = this.Subscribe(function (data) {
scope[propertyName] = data;
scope.$apply();
});
scope.$on('$destroy', function(event){
//we need to asure that we only dispose the observable when it's our scope that
//was destroyed.
//TODO: Figure out if thats enough to asure the above (e.g what happens when
//a child scope will be destroyed but ours won't be affected. Or the other way around,
//if a higher scope will be destroyed (and therefore ours as well) does it mean that $destroy()
//will be also called on our scope or will our scope get destroyed without actually
//calling $destroy() on it?
if (event.targetScope === scope){
disposable.Dispose();
}
});
};
})();
\ No newline at end of file
// Copyright (c) Microsoft Corporation. All rights reserved.
// This code is licensed by Microsoft Corporation under the terms
// of the MICROSOFT REACTIVE EXTENSIONS FOR JAVASCRIPT AND .NET LIBRARIES License.
// See http://go.microsoft.com/fwlink/?LinkId=186234.
(function(){var a;var b;var c=this;var d="Index out of range";if(typeof ProvideCustomRxRootObject =="undefined")b=c.Rx={}; else b=ProvideCustomRxRootObject();var e=function(){};var f=function(){return new Date().getTime();};var g=function(r0,s0){return r0===s0;};var h=function(r0){return r0;};var i=function(r0){return {Dispose:r0};};var j={Dispose:e};b.Disposable={Create:i,Empty:j};var k=b.BooleanDisposable=function(){var r0=false;this.GetIsDisposed=function(){return r0;};this.Dispose=function(){r0=true;};};var l=function(r0){var s0=false;r0.a++;this.Dispose=function(){var t0=false;if(!r0.b){if(!this.c){this.c=true;r0.a--;if(r0.a==0&&r0.d){r0.b=true;t0=true;}}}if(t0)r0.e.Dispose();};};var m=b.RefCountDisposable=function(r0){this.d=false;this.b=false;this.e=r0;this.a=0;this.Dispose=function(){var s0=false;if(!this.b){if(!this.d){this.d=true;if(this.a==0){this.b=true;s0=true;}}}if(s0)this.e.Dispose();};this.GetDisposable=function(){if(this.b)return j; else return new l(this);};};var n=b.CompositeDisposable=function(){var r0=new q();for(var s0=0;s0<arguments.length;s0++) r0.Add(arguments[s0]);var t0=false;this.GetCount=function(){return r0.GetCount();};this.Add=function(u0){if(!t0)r0.Add(u0); else u0.Dispose();};this.Remove=function(u0,v0){if(!t0){var w0=r0.Remove(u0);if(!v0&w0)u0.Dispose();}};this.Dispose=function(){if(!t0){t0=true;this.Clear();}};this.Clear=function(){for(var u0=0;u0<r0.GetCount();u0++) r0.GetItem(u0).Dispose();r0.Clear();};};var o=b.MutableDisposable=function(){var r0=false;var s0;this.Get=function(){return s0;},this.Replace=function(t0){if(r0&&t0!==a)t0.Dispose(); else{if(s0!==a)s0.Dispose();s0=t0;}};this.Dispose=function(){if(!r0){r0=true;if(s0!==a)s0.Dispose();}};};var p=function(r0){var s0=[];for(var t0=0;t0<r0.length;t0++) s0.push(r0[t0]);return s0;};var q=b.List=function(r0){var s0=[];var t0=0;var u0=r0!==a?r0:g;this.Add=function(v0){s0[t0]=v0;t0++;};this.RemoveAt=function(v0){if(v0<0||v0>=t0)throw d;if(v0==0){s0.shift();t0--;}else{s0.splice(v0,1);t0--;}};this.IndexOf=function(v0){for(var w0=0;w0<t0;w0++){if(u0(v0,s0[w0]))return w0;}return -1;};this.Remove=function(v0){var w0=this.IndexOf(v0);if(w0==-1)return false;this.RemoveAt(w0);return true;};this.Clear=function(){s0=[];t0=0;};this.GetCount=function(){return t0;};this.GetItem=function(v0){if(v0<0||v0>=t0)throw d;return s0[v0];};this.SetItem=function(v0,w0){if(v0<0||v0>=t0)throw d;s0[v0]=w0;};this.ToArray=function(){var v0=[];for(var w0=0;w0<this.GetCount();w0++) v0.push(this.GetItem(w0));return v0;};};var r=function(r0){if(r0===null)r0=g;this.f=r0;var s0=4;this.g=new Array(s0);this.h=0;};r.prototype.i=function(r0,s0){return this.f(this.g[r0],this.g[s0])<0;};r.prototype.j=function(r0){if(r0>=this.h||r0<0)return;var s0=r0-1>>1;if(s0<0||s0==r0)return;if(this.i(r0,s0)){var t0=this.g[r0];this.g[r0]=this.g[s0];this.g[s0]=t0;this.j(s0);}};r.prototype.k=function(r0){if(r0===a)r0=0;var s0=2*r0+1;var t0=2*r0+2;var u0=r0;if(s0<this.h&&this.i(s0,u0))u0=s0;if(t0<this.h&&this.i(t0,u0))u0=t0;if(u0!=r0){var v0=this.g[r0];this.g[r0]=this.g[u0];this.g[u0]=v0;this.k(u0);}};r.prototype.GetCount=function(){return this.h;};r.prototype.Peek=function(){if(this.h==0)throw "Heap is empty.";return this.g[0];};r.prototype.Dequeue=function(){var r0=this.Peek();this.g[0]=this.g[--this.h];delete this.g[this.h];this.k();return r0;};r.prototype.Enqueue=function(r0){var s0=this.h++;this.g[s0]=r0;this.j(s0);};var s=b.Scheduler=function(r0,s0,t0){this.Schedule=r0;this.ScheduleWithTime=s0;this.Now=t0;this.ScheduleRecursive=function(u0){var v0=this;var w0=new n();var x0;x0=function(){u0(function(){var y0=false;var z0=false;var A0;A0=v0.Schedule(function(){x0();if(y0)w0.Remove(A0); else z0=true;});if(!z0){w0.Add(A0);y0=true;}});};w0.Add(v0.Schedule(x0));return w0;};this.ScheduleRecursiveWithTime=function(u0,v0){var w0=this;var x0=new n();var y0;y0=function(){u0(function(z0){var A0=false;var B0=false;var C0;C0=w0.ScheduleWithTime(function(){y0();if(A0)x0.Remove(C0); else B0=true;},z0);if(!B0){x0.Add(C0);A0=true;}});};x0.Add(w0.ScheduleWithTime(y0,v0));return x0;};};var t=b.VirtualScheduler=function(r0,s0,t0,u0){var v0=new s(function(w0){return this.ScheduleWithTime(w0,0);},function(w0,x0){return this.ScheduleVirtual(w0,u0(x0));},function(){return t0(this.l);});v0.ScheduleVirtual=function(w0,x0){var y0=new k();var z0=s0(this.l,x0);var A0=function(){if(!y0.IsDisposed)w0();};var B0=new y(A0,z0);this.m.Enqueue(B0);return y0;};v0.Run=function(){while(this.m.GetCount()>0){var w0=this.m.Dequeue();this.l=w0.n;w0.o();}};v0.RunTo=function(w0){while(this.m.GetCount()>0&&this.f(this.m.Peek().n,w0)<=0){var x0=this.m.Dequeue();this.l=x0.n;x0.o();}};v0.GetTicks=function(){return this.l;};v0.l=0;v0.m=new r(function(w0,x0){return r0(w0.n,x0.n);});v0.f=r0;return v0;};var u=b.TestScheduler=function(){var r0=new t(function(s0,t0){return s0-t0;},function(s0,t0){return s0+t0;},function(s0){return new Date(s0);},function(s0){if(s0<=0)return 1;return s0;});return r0;};var v=new s(function(r0){return this.ScheduleWithTime(r0,0);},function(r0,s0){var t0=this.Now()+s0;var u0=new y(r0,t0);if(this.m===a){var v0=new w();try{this.m.Enqueue(u0);v0.p();}finally{v0.q();}}else this.m.Enqueue(u0);return u0.r();},f);v.s=function(r0){if(this.m===a){var s0=new w();try{r0();s0.p();}finally{s0.q();}}else r0();};s.CurrentThread=v;var w=function(){v.m=new r(function(r0,s0){try{return r0.n-s0.n;}catch(t0){debugger;}});this.q=function(){v.m=a;};this.p=function(){while(v.m.GetCount()>0){var r0=v.m.Dequeue();if(!r0.t()){while(r0.n-v.Now()>0);if(!r0.t())r0.o();}}};};var x=0;var y=function(r0,s0){this.u=x++;this.o=r0;this.n=s0;this.v=new k();this.t=function(){return this.v.GetIsDisposed();};this.r=function(){return this.v;};};var z=new s(function(r0){r0();return j;},function(r0,s0){while(this.Now<s0);r0();},f);s.Immediate=z;var A=new s(function(r0){var s0=c.setTimeout(r0,0);return i(function(){c.clearTimeout(s0);});},function(r0,s0){var t0=c.setTimeout(r0,s0);return i(function(){c.clearTimeout(t0);});},f);s.Timeout=A;var B=b.Observer=function(r0,s0,t0){this.OnNext=r0===a?e:r0;this.OnError=s0===a?function(u0){throw u0;}:s0;this.OnCompleted=t0===a?e:t0;this.AsObserver=function(){var u0=this;return new B(function(v0){u0.OnNext(v0);},function(v0){u0.OnError(v0);},function(){u0.OnCompleted();});};};var C=B.Create=function(r0,s0,t0){return new B(r0,s0,t0);};var D=b.Observable=function(r0){this.w=r0;};var E=D.CreateWithDisposable=function(r0){return new D(r0);};var F=D.Create=function(r0){return E(function(s0){return i(r0(s0));});};var G=function(){return this.Select(function(r0){return r0.Value;});};D.prototype={Subscribe:function(r0,s0,t0){var u0;if(arguments.length==0||arguments.length>1||typeof r0 =="function")u0=new B(r0,s0,t0); else u0=r0;return this.x(u0);},x:function(r0){var s0=false;var t0=new o();var u0=this;v.s(function(){var v0=new B(function(w0){if(!s0)r0.OnNext(w0);},function(w0){if(!s0){s0=true;t0.Dispose();r0.OnError(w0);}},function(){if(!s0){s0=true;t0.Dispose();r0.OnCompleted();}});t0.Replace(u0.w(v0));});return new n(t0,i(function(){s0=true;}));},Select:function(r0){var s0=this;return E(function(t0){var u0=0;return s0.Subscribe(new B(function(v0){var w0;try{w0=r0(v0,u0++);}catch(x0){t0.OnError(x0);return;}t0.OnNext(w0);},function(v0){t0.OnError(v0);},function(){t0.OnCompleted();}));});},Let:function(r0,s0){if(s0===a)return r0(this);var t0=this;return E(function(u0){var v0=s0();var w0;try{w0=r0(v0);}catch(A0){return L(A0).Subscribe(u0);}var x0=new o();var y0=new o();var z0=new n(y0,x0);x0.Replace(w0.Subscribe(function(A0){u0.OnNext(A0);},function(A0){u0.OnError(A0);z0.Dispose();},function(){u0.OnCompleted();z0.Dispose();}));y0.Replace(t0.Subscribe(v0));return z0;});},MergeObservable:function(){var r0=this;return E(function(s0){var t0=false;var u0=new n();var v0=new o();u0.Add(v0);v0.Replace(r0.Subscribe(function(w0){var x0=new o();u0.Add(x0);x0.Replace(w0.Subscribe(function(y0){s0.OnNext(y0);},function(y0){s0.OnError(y0);},function(){u0.Remove(x0);if(u0.GetCount()==1&&t0)s0.OnCompleted();}));},function(w0){s0.OnError(w0);},function(){t0=true;if(u0.GetCount()==1)s0.OnCompleted();}));return u0;});},y:function(r0,s0){var t0=p(s0);t0.unshift(this);return r0(t0);},Concat:function(){return this.y(I,arguments);},Merge:function(){return this.y(H,arguments);},Catch:function(){return this.y(P,arguments);},OnErrorResumeNext:function(){return this.y(V,arguments);},Zip:function(r0,s0){var t0=this;return E(function(u0){var v0=false;var w0=[];var x0=[];var y0=false;var z0=false;var A0=new n();var B0=function(C0){A0.Dispose();w0=a;x0=a;u0.OnError(C0);};A0.Add(t0.Subscribe(function(C0){if(z0){u0.OnCompleted();return;}if(x0.length>0){var D0=x0.shift();var E0;try{E0=s0(C0,D0);}catch(F0){A0.Dispose();u0.OnError(F0);return;}u0.OnNext(E0);}else w0.push(C0);},B0,function(){if(z0){u0.OnCompleted();return;}y0=true;}));A0.Add(r0.Subscribe(function(C0){if(y0){u0.OnCompleted();return;}if(w0.length>0){var D0=w0.shift();var E0;try{E0=s0(D0,C0);}catch(F0){A0.Dispose();u0.OnError(F0);return;}u0.OnNext(E0);}else x0.push(C0);},B0,function(){if(y0){u0.OnCompleted();return;}z0=true;}));return A0;});},CombineLatest:function(r0,s0){var t0=this;return E(function(u0){var v0=false;var w0=false;var x0=false;var y0;var z0;var A0=false;var B0=false;var C0=new n();var D0=function(E0){C0.Dispose();u0.OnError(E0);};C0.Add(t0.Subscribe(function(E0){if(B0){u0.OnCompleted();return;}if(x0){var F0;try{F0=s0(E0,z0);}catch(G0){C0.Dispose();u0.OnError(G0);return;}u0.OnNext(F0);}y0=E0;w0=true;},D0,function(){if(B0){u0.OnCompleted();return;}A0=true;}));C0.Add(r0.Subscribe(function(E0){if(A0){u0.OnCompleted();return;}if(w0){var F0;try{F0=s0(y0,E0);}catch(G0){C0.Dispose();u0.OnError(G0);return;}u0.OnNext(F0);}z0=E0;x0=true;},D0,function(){if(A0){u0.OnCompleted();return;}B0=true;}));});},Switch:function(){var r0=this;return E(function(s0){var t0=false;var u0=new o();var v0=new o();v0.Replace(r0.Subscribe(function(w0){if(!t0){var x0=new o();x0.Replace(w0.Subscribe(function(y0){s0.OnNext(y0);},function(y0){v0.Dispose();u0.Dispose();s0.OnError(y0);},function(){u0.Replace(a);if(t0)s0.OnCompleted();}));u0.Replace(x0);}},function(w0){u0.Dispose();s0.OnError(w0);},function(){t0=true;if(u0.Get()===a)s0.OnCompleted();}));return new n(v0,u0);});},TakeUntil:function(r0){var s0=this;return E(function(t0){var u0=new n();u0.Add(r0.Subscribe(function(){t0.OnCompleted();u0.Dispose();},function(v0){t0.OnError(v0);},function(){}));u0.Add(s0.Subscribe(t0));return u0;});},SkipUntil:function(r0){var s0=this;return E(function(t0){var u0=true;var v0=new n();v0.Add(r0.Subscribe(function(){u0=false;},function(w0){t0.OnError(w0);},e));v0.Add(s0.Subscribe(new B(function(w0){if(!u0)t0.OnNext(w0);},function(w0){t0.OnError(w0);},function(){if(!u0)t0.OnCompleted();})));return v0;});},Scan1:function(r0){var s0=this;return O(function(){var t0;var u0=false;return s0.Select(function(v0){if(u0)t0=r0(t0,v0); else{t0=v0;u0=true;}return t0;});});},Scan:function(r0,s0){var t0=this;return O(function(){var u0;var v0=false;return t0.Select(function(w0){if(v0)u0=s0(u0,w0); else{u0=s0(r0,w0);v0=true;}return u0;});});},Scan0:function(r0,s0){var t0=this;return E(function(u0){var v0=r0;var w0=true;return t0.Subscribe(function(x0){if(w0){w0=false;u0.OnNext(v0);}try{v0=s0(v0,x0);}catch(y0){u0.OnError(y0);return;}u0.OnNext(v0);},function(x0){if(w0)u0.OnNext(v0);u0.OnError(x0);},function(){if(w0)u0.OnNext(v0);u0.OnCompleted();});});},Finally:function(r0){var s0=this;return F(function(t0){var u0=s0.Subscribe(t0);return function(){try{u0.Dispose();r0();}catch(v0){r0();throw v0;}};});},Do:function(r0,s0,t0){var u0;if(arguments.length==0||arguments.length>1||typeof r0 =="function")u0=new B(r0,s0!==a?s0:e,t0); else u0=r0;var v0=this;return E(function(w0){return v0.Subscribe(new B(function(x0){try{u0.OnNext(x0);}catch(y0){w0.OnError(y0);return;}w0.OnNext(x0);},function(x0){if(s0!==a)try{u0.OnError(x0);}catch(y0){w0.OnError(y0);return;}w0.OnError(x0);},function(){if(t0!==a)try{u0.OnCompleted();}catch(x0){w0.OnError(x0);return;}w0.OnCompleted();}));});},Where:function(r0){var s0=this;return E(function(t0){var u0=0;return s0.Subscribe(new B(function(v0){var w0=false;try{w0=r0(v0,u0++);}catch(x0){t0.OnError(x0);return;}if(w0)t0.OnNext(v0);},function(v0){t0.OnError(v0);},function(){t0.OnCompleted();}));});},Take:function(r0,s0){if(s0===a)s0=z;var t0=this;return E(function(u0){if(r0<=0){t0.Subscribe().Dispose();return N(s0).Subscribe(u0);}var v0=r0;return t0.Subscribe(new B(function(w0){if(v0-->0){u0.OnNext(w0);if(v0==0)u0.OnCompleted();}},function(w0){u0.OnError(w0);},function(){u0.OnCompleted();}));});},GroupBy:function(r0,s0,t0){if(r0===a)r0=h;if(s0===a)s0=h;if(t0===a)t0=function(v0){return v0.toString();};var u0=this;return E(function(v0){var w0={};var x0=new o();var y0=new m(x0);x0.Replace(u0.Subscribe(function(z0){var A0;try{A0=r0(z0);}catch(G0){for(var H0 in w0) w0[H0].OnError(G0);v0.OnError(G0);return;}var B0=false;var C0;try{var D0=t0(A0);if(w0[D0]===a){C0=new i0();w0[D0]=C0;B0=true;}else C0=w0[D0];}catch(G0){for(var H0 in w0) w0[H0].OnError(G0);v0.OnError(G0);return;}if(B0){var E0=E(function(G0){return new n(y0.GetDisposable(),C0.Subscribe(G0));});E0.Key=A0;v0.OnNext(E0);}var F0;try{F0=s0(z0);}catch(G0){for(var H0 in w0) w0[H0].OnError(G0);v0.OnError(G0);return;}C0.OnNext(F0);},function(z0){for(var A0 in w0) w0[A0].OnError(z0);v0.OnError(z0);},function(){for(var z0 in w0) w0[z0].OnCompleted();v0.OnCompleted();}));return y0;});},TakeWhile:function(r0){var s0=this;return E(function(t0){var u0=true;return s0.Subscribe(new B(function(v0){if(u0){try{u0=r0(v0);}catch(w0){t0.OnError(w0);return;}if(u0)t0.OnNext(v0); else t0.OnCompleted();}},function(v0){t0.OnError(v0);},function(){t0.OnCompleted();}));});},SkipWhile:function(r0){var s0=this;return E(function(t0){var u0=false;return s0.Subscribe(new B(function(v0){if(!u0)try{u0=!r0(v0);}catch(w0){t0.OnError(w0);return;}if(u0)t0.OnNext(v0);},function(v0){t0.OnError(v0);},function(){t0.OnCompleted();}));});},Skip:function(r0){var s0=this;return E(function(t0){var u0=r0;return s0.Subscribe(new B(function(v0){if(u0--<=0)t0.OnNext(v0);},function(v0){t0.OnError(v0);},function(){t0.OnCompleted();}));});},SelectMany:function(r0){return this.Select(r0).MergeObservable();},TimeInterval:function(r0){if(r0===a)r0=z;var s0=this;return O(function(){var t0=r0.Now();return s0.Select(function(u0){var v0=r0.Now();var w0=v0-t0;t0=v0;return {Interval:w0,Value:u0};});});},RemoveInterval:G,Timestamp:function(r0){if(r0===a)r0=z;return this.Select(function(s0){return {Timestamp:r0.Now(),Value:s0};});},RemoveTimestamp:G,Materialize:function(){var r0=this;return E(function(s0){return r0.Subscribe(new B(function(t0){s0.OnNext(new h0("N",t0));},function(t0){s0.OnNext(new h0("E",t0));s0.OnCompleted();},function(){s0.OnNext(new h0("C"));s0.OnCompleted();}));});},Dematerialize:function(){return this.SelectMany(function(r0){return r0;});},AsObservable:function(){var r0=this;return E(function(s0){return r0.Subscribe(s0);});},Delay:function(r0,s0){if(s0===a)s0=A;var t0=this;return E(function(u0){var v0=[];var w0=false;var x0=new o();var y0=t0.Materialize().Timestamp().Subscribe(function(z0){if(z0.Value.Kind=="E"){u0.OnError(z0.Value.Value);v0=[];if(w0)x0.Dispose();return;}v0.push({Timestamp:s0.Now()+r0,Value:z0.Value});if(!w0){x0.Replace(s0.ScheduleRecursiveWithTime(function(A0){var B0;do{B0=a;if(v0.length>0&&v0[0].Timestamp<=s0.Now())B0=v0.shift().Value;if(B0!==a)B0.Accept(u0);}while(B0!==a);if(v0.length>0){A0(Math.max(0,v0[0].Timestamp-s0.Now()));w0=true;}else w0=false;},r0));w0=true;}});return new n(y0,x0);});},Throttle:function(r0,s0){if(s0===a)s0=A;var t0=this;return E(function(u0){var v0;var w0=false;var x0=new o();var y0=0;var z0=t0.Subscribe(function(A0){w0=true;v0=A0;y0++;var B0=y0;x0.Replace(s0.ScheduleWithTime(function(){if(w0&&y0==B0)u0.OnNext(v0);w0=false;},r0));},function(A0){x0.Dispose();u0.OnError(A0);w0=false;y0++;},function(){x0.Dispose();if(w0)u0.OnNext(v0);u0.OnCompleted();w0=false;y0++;});return new n(z0,x0);});},Timeout:function(r0,s0,t0){if(t0===a)t0=A;if(s0===a)s0=L("Timeout",t0);var u0=this;return E(function(v0){var w0=new o();var x0=new o();var y0=0;var z0=y0;var A0=false;x0.Replace(t0.ScheduleWithTime(function(){A0=y0==z0;if(A0)w0.Replace(s0.Subscribe(v0));},r0));w0.Replace(u0.Subscribe(function(B0){var C0=0;if(!A0){y0++;C0=y0;v0.OnNext(B0);x0.Replace(t0.ScheduleWithTime(function(){A0=y0==C0;if(A0)w0.Replace(s0.Subscribe(v0));},r0));}},function(B0){if(!A0){y0++;v0.OnError(B0);}},function(){if(!A0){y0++;v0.OnCompleted();}}));return new n(w0,x0);});},Sample:function(r0,s0){if(s0===a)s0=A;var t0=this;return E(function(u0){var v0=false;var w0;var x0=false;var y0=new n();y0.Add(Y(r0,s0).Subscribe(function(z0){if(v0){u0.OnNext(w0);v0=false;}if(x0)u0.OnCompleted();},function(z0){u0.OnError(z0);},function(){u0.OnCompleted();}));y0.Add(t0.Subscribe(function(z0){v0=true;w0=z0;},function(z0){u0.OnError(z0);y0.Dispose();},function(){x0=true;}));return y0;});},Repeat:function(r0,s0){var t0=this;if(s0===a)s0=z;if(r0===a)r0=-1;return E(function(u0){var v0=r0;var w0=new o();var x0=new n(w0);var y0=function(z0){w0.Replace(t0.Subscribe(function(A0){u0.OnNext(A0);},function(A0){u0.OnError(A0);},function(){if(v0>0){v0--;if(v0==0){u0.OnCompleted();return;}}z0();}));};x0.Add(s0.ScheduleRecursive(y0));return x0;});},Retry:function(r0,s0){var t0=this;if(s0===a)s0=z;if(r0===a)r0=-1;return E(function(u0){var v0=r0;var w0=new o();var x0=new n(w0);var y0=function(z0){w0.Replace(t0.Subscribe(function(A0){u0.OnNext(A0);},function(A0){if(v0>0){v0--;if(v0==0){u0.OnError(A0);return;}}z0();},function(){u0.OnCompleted();}));};x0.Add(s0.ScheduleRecursive(y0));return x0;});},BufferWithTime:function(r0,s0,t0){if(t0===a)t0=A;if(s0===a)s0=r0;var u0=this;return E(function(v0){var w0=new q();var x0=t0.Now();var y0=function(){var C0=[];for(var D0=0;D0<w0.GetCount();D0++){var E0=w0.GetItem(D0);if(E0.Timestamp-x0>=0)C0.push(E0.Value);}return C0;};var z0=new n();var A0=function(C0){v0.OnError(C0);};var B0=function(){v0.OnNext(y0());v0.OnCompleted();};z0.Add(u0.Subscribe(function(C0){w0.Add({Value:C0,Timestamp:t0.Now()});},A0,B0));z0.Add(a0(r0,s0,t0).Subscribe(function(C0){var D0=y0();var E0=t0.Now()+s0-r0;while(w0.GetCount()>0&&w0.GetItem(0).Timestamp-E0<=0)w0.RemoveAt(0);v0.OnNext(D0);x0=E0;},A0,B0));return z0;});},BufferWithTimeOrCount:function(r0,s0,t0){if(t0===a)t0=A;var u0=this;return E(function(v0){var w0=0;var x0=new q();var y0=function(){v0.OnNext(x0.ToArray());x0.Clear();w0++;};var z0=new o();var A0;A0=function(C0){var D0=t0.ScheduleWithTime(function(){var E0=false;var F0=0;if(C0==w0){y0();F0=w0;E0=true;}if(E0)A0(F0);},r0);z0.Replace(D0);};A0(w0);var B0=u0.Subscribe(function(C0){var D0=false;var E0=0;x0.Add(C0);if(x0.GetCount()==s0){y0();E0=w0;D0=true;}if(D0)A0(E0);},function(C0){v0.OnError(C0);x0.Clear();},function(){v0.OnNext(x0.ToArray());w0++;v0.OnCompleted();x0.Clear();});return new n(B0,z0);});},BufferWithCount:function(r0,s0){if(s0===a)s0=r0;var t0=this;return E(function(u0){var v0=[];var w0=0;return t0.Subscribe(function(x0){if(w0==0)v0.push(x0); else w0--;var y0=v0.length;if(y0==r0){var z0=v0;v0=[];var A0=Math.min(s0,y0);for(var B0=A0;B0<y0;B0++) v0.push(z0[B0]);w0=Math.max(0,s0-r0);u0.OnNext(z0);}},function(x0){u0.OnError(x0);},function(){if(v0.length>0)u0.OnNext(v0);u0.OnCompleted();});});},StartWith:function(r0,s0){if(!(r0 instanceof Array))r0=[r0];if(s0===a)s0=z;var t0=this;return E(function(u0){var v0=new n();var w0=0;v0.Add(s0.ScheduleRecursive(function(x0){if(w0<r0.length){u0.OnNext(r0[w0]);w0++;x0();}else v0.Add(t0.Subscribe(u0));}));return v0;});},DistinctUntilChanged:function(r0,s0){if(r0===a)r0=h;if(s0===a)s0=g;var t0=this;return E(function(u0){var v0;var w0=false;return t0.Subscribe(function(x0){var y0;try{y0=r0(x0);}catch(A0){u0.OnError(A0);return;}var z0=false;if(w0)try{z0=s0(v0,y0);}catch(A0){u0.OnError(A0);return;}if(!w0||!z0){w0=true;v0=y0;u0.OnNext(x0);}},function(x0){u0.OnError(x0);},function(){u0.OnCompleted();});});},Publish:function(r0){if(r0===a)return new q0(this,new i0());var s0=this;return E(function(t0){var u0=new q0(s0,new i0());return new n(r0(u0).Subscribe(B),u0.Connect());});},Prune:function(r0,s0){if(s0===a)s0=z;if(r0===a)return new q0(this,new k0(s0));var t0=this;return E(function(u0){var v0=new q0(t0,new k0(s0));return new n(r0(v0).Subscribe(B),v0.Connect());});},Replay:function(r0,s0,t0,u0){if(u0===a)u0=v;if(r0===a)return new q0(this,new m0(s0,t0,u0));var v0=this;return E(function(w0){var x0=new q0(v0,new m0(s0,t0,u0));return new n(r0(x0).Subscribe(B),x0.Connect());});},SkipLast:function(r0){var s0=this;return E(function(t0){var u0=[];return s0.Subscribe(function(v0){u0.push(v0);if(u0.length>r0)t0.OnNext(u0.shift());},function(v0){t0.OnError(v0);},function(){t0.OnCompleted();});});},TakeLast:function(r0){var s0=this;return E(function(t0){var u0=[];return s0.Subscribe(function(v0){u0.push(v0);if(u0.length>r0)u0.shift();},function(v0){t0.OnError(v0);},function(){while(u0.length>0)t0.OnNext(u0.shift());t0.OnCompleted();});});}};var H=D.Merge=function(r0,s0){if(s0===a)s0=z;return J(r0,s0).MergeObservable();};var I=D.Concat=function(r0,s0){if(s0===a)s0=z;return E(function(t0){var u0=new o();var v0=0;var w0=s0.ScheduleRecursive(function(x0){if(v0<r0.length){var y0=r0[v0];v0++;var z0=new o();u0.Replace(z0);z0.Replace(y0.Subscribe(function(A0){t0.OnNext(A0);},function(A0){t0.OnError(A0);},x0));}else t0.OnCompleted();});return new n(u0,w0);});};var J=D.FromArray=function(r0,s0){if(s0===a)s0=z;return E(function(t0){var u0=0;return s0.ScheduleRecursive(function(v0){if(u0<r0.length){t0.OnNext(r0[u0++]);v0();}else t0.OnCompleted();});});};var K=D.Return=function(r0,s0){if(s0===a)s0=z;return E(function(t0){return s0.Schedule(function(){t0.OnNext(r0);t0.OnCompleted();});});};var L=D.Throw=function(r0,s0){if(s0===a)s0=z;return E(function(t0){return s0.Schedule(function(){t0.OnError(r0);});});};var M=D.Never=function(){return E(function(r0){return j;});};var N=D.Empty=function(r0){if(r0===a)r0=z;return E(function(s0){return r0.Schedule(function(){s0.OnCompleted();});});};var O=D.Defer=function(r0){return E(function(s0){var t0;try{t0=r0();}catch(u0){s0.OnError(u0);return j;}return t0.Subscribe(s0);});};var P=D.Catch=function(r0,s0){if(s0===a)s0=z;return E(function(t0){var u0=new o();var v0=0;var w0=s0.ScheduleRecursive(function(x0){var y0=r0[v0];v0++;var z0=new o();u0.Replace(z0);z0.Replace(y0.Subscribe(function(A0){t0.OnNext(A0);},function(A0){if(v0<r0.length)x0(); else t0.OnError(A0);},function(){t0.OnCompleted();}));});return new n(u0,w0);});};var Q=D.Using=function(r0,s0){return E(function(t0){var u0;var v0=j;try{var w0=r0();if(w0!==a)v0=w0;u0=s0(w0);}catch(x0){return new n(Throw(x0).Subscribe(t0),v0);}return new n(u0.Subscribe(t0),v0);});};var R=D.Range=function(r0,s0,t0){if(t0===a)t0=z;var u0=r0+s0-1;return T(r0,function(v0){return v0<=u0;},function(v0){return v0+1;},h,t0);};var S=D.Repeat=function(r0,s0,t0){if(t0===a)t0=z;if(s0===a)s0=-1;var u0=s0;return E(function(v0){return t0.ScheduleRecursive(function(w0){v0.OnNext(r0);if(u0>0){u0--;if(u0==0){v0.OnCompleted();return;}}w0();});});};var T=D.Generate=function(r0,s0,t0,u0,v0){if(v0===a)v0=z;return E(function(w0){var x0=r0;var y0=true;return v0.ScheduleRecursive(function(z0){var A0=false;var B0;try{if(y0)y0=false; else x0=t0(x0);A0=s0(x0);if(A0)B0=u0(x0);}catch(C0){w0.OnError(C0);return;}if(A0){w0.OnNext(B0);z0();}else w0.OnCompleted();});});};var U=D.GenerateWithTime=function(r0,s0,t0,u0,v0,w0){if(w0===a)w0=A;return new E(function(x0){var y0=r0;var z0=true;var A0=false;var B0;var C0;return w0.ScheduleRecursiveWithTime(function(D0){if(A0)x0.OnNext(B0);try{if(z0)z0=false; else y0=t0(y0);A0=s0(y0);if(A0){B0=u0(y0);C0=v0(y0);}}catch(E0){x0.OnError(E0);return;}if(A0)D0(C0); else x0.OnCompleted();},0);});};var V=D.OnErrorResumeNext=function(r0,s0){if(s0===a)s0=z;return E(function(t0){var u0=new o();var v0=0;var w0=s0.ScheduleRecursive(function(x0){if(v0<r0.length){var y0=r0[v0];v0++;var z0=new o();u0.Replace(z0);z0.Replace(y0.Subscribe(function(A0){t0.OnNext(A0);},x0,x0));}else t0.OnCompleted();});return new n(u0,w0);});};var W=D.Amb=function(){var r0=arguments;return E(function(s0){var t0=new n();var u0=new o();u0.Replace(t0);var v0=false;for(var w0=0;w0<r0.length;w0++){var x0=r0[w0];var y0=new o();var z0=new B(function(A0){if(!v0){t0.Remove(this.z,true);t0.Dispose();u0.Replace(this.z);v0=true;}s0.OnNext(A0);},function(A0){s0.OnError(A0);u0.Dispose();},function(){s0.OnCompleted();u0.Dispose();});z0.z=y0;y0.Replace(x0.Subscribe(z0));t0.Add(y0);}return u0;});};var X=D.ForkJoin=function(){var r0=arguments;return E(function(s0){var t0=[];var u0=[];var v0=[];var w0=new n();for(var x0=0;x0<r0.length;x0++) (function(y0){w0.Add(r0[y0].Subscribe(function(z0){t0[y0]=true;v0[y0]=z0;},function(z0){s0.OnError(z0);},function(z0){if(!t0[y0]){s0.OnCompleted();v0=a;t0=a;return;}u0[y0]=true;var A0=true;for(var B0=0;B0<r0.length;B0++){if(!u0[B0])A0=false;}if(A0){s0.OnNext(v0);s0.OnCompleted();v0=a;u0=a;t0=a;}}));})(x0);return w0;});};var Y=D.Interval=function(r0,s0){return a0(r0,r0,s0);};var Z=function(r0){return Math.max(0,r0);};var a0=D.Timer=function(r0,s0,t0){if(t0===a)t0=A;if(r0===a)return M();if(r0 instanceof Date)return O(function(){return D.Timer(r0-new Date(),s0,t0);});var u0=Z(r0);if(s0===a)return E(function(w0){return t0.ScheduleWithTime(function(){w0.OnNext(0);w0.OnCompleted();},u0);});var v0=Z(s0);return E(function(w0){var x0=0;return t0.ScheduleRecursiveWithTime(function(y0){w0.OnNext(x0++);y0(v0);},u0);});};var b0=D.While=function(r0,s0){return E(function(t0){var u0=new o();var v0=new n(u0);v0.Add(z.ScheduleRecursive(function(w0){var x0;try{x0=r0();}catch(y0){t0.OnError(y0);return;}if(x0)u0.Replace(s0.Subscribe(function(y0){t0.OnNext(y0);},function(y0){t0.OnError(y0);},function(){w0();})); else t0.OnCompleted();}));return v0;});};var c0=D.If=function(r0,s0,t0){if(t0===a)t0=N();return O(function(){return r0()?s0:t0;});};var d0=D.DoWhile=function(r0,s0){return I([r0,b0(s0,r0)]);};var e0=D.Case=function(r0,s0,t0,u0){if(u0===a)u0=z;if(t0===a)t0=N(u0);return O(function(){var v0=s0[r0()];if(v0===a)v0=t0;return v0;});};var f0=D.For=function(r0,s0){return E(function(t0){var u0=new n();var v0=0;u0.Add(z.ScheduleRecursive(function(w0){if(v0<r0.length){var x0;try{x0=s0(r0[v0]);}catch(y0){t0.OnError(y0);return;}u0.Add(x0.Subscribe(function(y0){t0.OnNext(y0);},function(y0){t0.OnError(y0);},function(){v0++;w0();}));}else t0.OnCompleted();}));return u0;});};var g0=D.Let=function(r0,s0){return O(function(){return s0(r0);});};var h0=b.Notification=function(r0,s0){this.Kind=r0;this.Value=s0;this.toString=function(){return this.Kind+": "+this.Value;};this.Accept=function(t0){switch(this.Kind){case "N":t0.OnNext(this.Value);break;case "E":t0.OnError(this.Value);break;case "C":t0.OnCompleted();break;}return j;};this.w=function(t0){var u0=this.Accept(t0);if(r0=="N")t0.OnCompleted();return u0;};};h0.prototype=new D;var i0=b.Subject=function(){var r0=new q();var s0=false;this.OnNext=function(t0){if(!s0){var u0=r0.ToArray();for(var v0=0;v0<u0.length;v0++){var w0=u0[v0];w0.OnNext(t0);}}};this.OnError=function(t0){if(!s0){var u0=r0.ToArray();for(var v0=0;v0<u0.length;v0++){var w0=u0[v0];w0.OnError(t0);}s0=true;r0.Clear();}};this.OnCompleted=function(){if(!s0){var t0=r0.ToArray();for(var u0=0;u0<t0.length;u0++){var v0=t0[u0];v0.OnCompleted();}s0=true;r0.Clear();}};this.w=function(t0){if(!s0){r0.Add(t0);return i(function(){r0.Remove(t0);});}else return j;};};i0.prototype=new D;for(var j0 in B.prototype) i0.prototype[j0]=B.prototype[j0];var k0=b.AsyncSubject=function(r0){var s0=new q();var t0;var u0=false;if(r0===a)r0=z;this.OnNext=function(v0){if(!u0)t0=new h0("N",v0);};this.OnError=function(v0){if(!u0){t0=new h0("E",v0);var w0=s0.ToArray();for(var x0=0;x0<w0.length;x0++){var y0=w0[x0];if(y0!==a)y0.OnError(v0);}u0=true;s0.Clear();}};this.OnCompleted=function(){if(!u0){if(t0===a)t0=new h0("C");var v0=s0.ToArray();for(var w0=0;w0<v0.length;w0++){var x0=v0[w0];if(x0!==a)t0.w(x0);}u0=true;s0.Clear();}};this.w=function(v0){if(!u0){s0.Add(v0);return i(function(){s0.Remove(v0);});}else return r0.Schedule(function(){t0.w(v0);});};};k0.prototype=new i0;var l0=b.BehaviorSubject=function(r0,s0){var t0=new m0(1,-1,s0);t0.OnNext(r0);return t0;};var m0=b.ReplaySubject=function(r0,s0,t0){var u0=new q();var v0=new q();var w0=false;if(t0===a)t0=v;var x0=s0>0;var y0=function(z0,A0){v0.Add({Value:new h0(z0,A0),Timestamp:t0.Now()});};this.A=function(){if(r0!==a)while(v0.GetCount()>r0)v0.RemoveAt(0);if(x0)while(v0.GetCount()>0&&t0.Now()-v0.GetItem(0).Timestamp>s0)v0.RemoveAt(0);};this.OnNext=function(z0){if(!w0){var A0=u0.ToArray();for(var B0=0;B0<A0.length;B0++){var C0=A0[B0];C0.OnNext(z0);}y0("N",z0);}};this.OnError=function(z0){if(!w0){var A0=u0.ToArray();for(var B0=0;B0<A0.length;B0++){var C0=A0[B0];C0.OnError(z0);}w0=true;u0.Clear();y0("E",z0);}};this.OnCompleted=function(){if(!w0){var z0=u0.ToArray();for(var A0=0;A0<z0.length;A0++){var B0=z0[A0];B0.OnCompleted();}w0=true;u0.Clear();y0("C");}};this.w=function(z0){var A0=new n0(this,z0);var B0=new n(A0);var C0=this;B0.Add(t0.Schedule(function(){if(!A0.B){C0.A();for(var D0=0;D0<v0.GetCount();D0++) v0.GetItem(D0).Value.Accept(z0);u0.Add(z0);A0.C=true;}}));return B0;};this.D=function(z0){u0.Remove(z0);};};m0.prototype=new i0;var n0=function(r0,s0){this.E=r0;this.F=s0;this.C=false;this.B=false;this.Dispose=function(){if(this.C)this.E.D(this.F);this.B=true;};};var o0=D.ToAsync=function(r0,s0){if(s0===a)s0=A;return function(){var t0=new k0(s0);var u0=function(){var x0;try{x0=r0.apply(this,arguments);}catch(y0){t0.OnError(y0);return;}t0.OnNext(x0);t0.OnCompleted();};var v0=this;var w0=p(arguments);s0.Schedule(function(){u0.apply(v0,w0);});return t0;};};var p0=D.Start=function(r0,s0,t0,u0){if(t0===a)t0=[];return o0(r0,u0).apply(s0,t0);};var q0=b.ConnectableObservable=function(r0,s0){if(s0===a)s0=new i0();this.E=s0;this.G=r0;this.H=false;this.Connect=function(){var t0;var u0=false;if(!this.H){this.H=true;var v0=this;t0=new n(i(function(){v0.H=false;}));this.I=t0;t0.Add(r0.Subscribe(this.E));}return this.I;};this.w=function(t0){return this.E.Subscribe(t0);};this.RefCount=function(){var t0=0;var u0=this;var v0;return F(function(w0){var x0=false;t0++;x0=t0==1;var y0=u0.Subscribe(w0);if(x0)v0=u0.Connect();return function(){y0.Dispose();t0--;if(t0==0)v0.Dispose();};});};};q0.prototype=new D;})();
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment